diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index 1bc3af185..e35a34974 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -45,6 +45,18 @@ openstack="OpenStack", redhat="Redhat", vmware="VMware", + nutanix="Nutanix", +) + +VM_SCOPE_MAPPING = dict( + cloudfoundry="cloudfoundry", + kubernetes="kubernetes", + microsoft="MicrosoftSCVMM", + openshift="openshift", + openstack="openstack", + redhat="rhev", + vmware="vm", + nutanix="nutanix", ) MATCH_TYPE_GROUP_MAPPING = {"all": "ALL", "all_in_pod": "ALL_IN_POD", "range": "range"} @@ -451,3 +463,5 @@ L4L7_FUNC_TYPES_MAPPING = {"go_to": "GoTo", "go_through": "GoThrough", "l1": "L1", "l2": "L2"} L4L7_HASH_ALGORITHMS_MAPPING = {"source_ip": "sip", "destination_ip": "dip", "ip_and_protocol": "sip-dip-prototype"} + +COS_MAPPING = {"cos_0": "Cos0", "cos_1": "Cos1", "cos_2": "Cos2", "cos_3": "Cos3", "cos_4": "Cos4", "cos_5": "Cos5", "cos_6": "Cos6", "cos_7": "Cos7"} diff --git a/plugins/modules/aci_aep_to_domain.py b/plugins/modules/aci_aep_to_domain.py index 3977e63e3..7ad6098c9 100644 --- a/plugins/modules/aci_aep_to_domain.py +++ b/plugins/modules/aci_aep_to_domain.py @@ -46,7 +46,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -227,7 +227,7 @@ def main(): domain=dict(type="str", aliases=["domain_name", "domain_profile"]), # Not required for querying all objects domain_type=dict(type="str", choices=["fc", "l2dom", "l3dom", "phys", "vmm"], aliases=["type"]), # Not required for querying all objects state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), ) module = AnsibleModule( diff --git a/plugins/modules/aci_domain.py b/plugins/modules/aci_domain.py index ea65805b8..0e4d1de61 100644 --- a/plugins/modules/aci_domain.py +++ b/plugins/modules/aci_domain.py @@ -75,7 +75,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] vswitch: description: - The virtual switch to use for vmm domains. @@ -279,16 +279,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec, aci_owner_spec - -VM_PROVIDER_MAPPING = dict( - cloudfoundry="CloudFoundry", - kubernetes="Kubernetes", - microsoft="Microsoft", - openshift="OpenShift", - openstack="OpenStack", - redhat="Redhat", - vmware="VMware", -) +from ansible_collections.cisco.aci.plugins.module_utils.constants import VM_PROVIDER_MAPPING VSWITCH_MAPPING = dict( avs="n1kv", @@ -341,7 +332,7 @@ def main(): tag_collection=dict(type="bool"), multicast_address=dict(type="str"), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=["cloudfoundry", "kubernetes", "microsoft", "openshift", "openstack", "redhat", "vmware"]), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), vswitch=dict(type="str", choices=["avs", "default", "dvs", "unknown"]), name_alias=dict(type="str"), access_mode=dict(type="str", choices=["read-write", "read-only"]), diff --git a/plugins/modules/aci_domain_to_encap_pool.py b/plugins/modules/aci_domain_to_encap_pool.py index bf573d208..c289f4797 100644 --- a/plugins/modules/aci_domain_to_encap_pool.py +++ b/plugins/modules/aci_domain_to_encap_pool.py @@ -62,7 +62,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -266,7 +266,7 @@ def main(): pool=dict(type="str", aliases=["pool_name"]), # Not required for querying all objects pool_allocation_mode=dict(type="str", aliases=["allocation_mode", "mode"], choices=["dynamic", "static"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), ) module = AnsibleModule( diff --git a/plugins/modules/aci_domain_to_vlan_pool.py b/plugins/modules/aci_domain_to_vlan_pool.py index 88d4a74c1..0e44dcad5 100644 --- a/plugins/modules/aci_domain_to_vlan_pool.py +++ b/plugins/modules/aci_domain_to_vlan_pool.py @@ -53,7 +53,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -265,7 +265,7 @@ def main(): pool=dict(type="str", aliases=["pool_name", "vlan_pool"]), # Not required for querying all objects pool_allocation_mode=dict(type="str", required=True, aliases=["allocation_mode", "mode"], choices=["dynamic", "static"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), ) module = AnsibleModule( diff --git a/plugins/modules/aci_epg_to_domain.py b/plugins/modules/aci_epg_to_domain.py index 611b1d66d..5857c0dd9 100644 --- a/plugins/modules/aci_epg_to_domain.py +++ b/plugins/modules/aci_epg_to_domain.py @@ -129,7 +129,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] custom_epg_name: description: - The custom epg name in VMM domain association. @@ -169,6 +169,62 @@ type: str choices: [ accept, reject ] default: reject + epg_cos: + description: + - The class of service (CoS). + - The APIC defaults to C(cos_0) when unset during creation. + type: str + choices: [ cos_0, cos_1, cos_2, cos_3, cos_4, cos_5, cos_6, cos_7 ] + epg_cos_preference: + description: + - The CoS preference. + - The APIC defaults to C(disabled) when unset during creation. + type: str + choices: [ enabled, disabled ] + ipam_dhcp_override: + description: + - The IP Address Management (IPAM) Dynamic Host Configuration Protocol (DHCP) override. + - Only applicable for Nutanix domains. + type: str + ipam_enabled: + description: + - The IPAM enabled state. + - Only applicable for Nutanix domains. + - The APIC defaults to C(false) when unset during creation. + type: bool + ipam_gateway: + description: + - The IPAM gateway. + - Only applicable for Nutanix domains. + type: str + lag_policy_name: + description: + - The link aggregation group (LAG) policy name. + type: str + netflow_direction: + description: + - The NetFlow monitoring direction. + - The APIC defaults to C(both) when unset during creation. + type: str + choices: [ both, ingress, egress ] + primary_encap_inner: + description: + - The primary inner encapsulation. + - This is used for the portgroup at the VMWare Distributed Virtual Switch (DVS). + - This VLAN is internal to the DVS and is used for communication between the other VMs and the AVE VM at a host. + - Traffic is not forwarded to the fabric over the VLAN. + - Only applicable for Cisco ACI Virtual Edge (AVE) domains. + - Accepted values range between C(1) and C(4096). + type: int + secondary_encap_inner: + description: + - The secondary inner encapsulation. + - This is used for the portgroup at the VMWare DVS. + - This VLAN is internal to the DVS and is used for communication between the other VMs and the AVE VM at a host. + - Traffic is not forwarded to the fabric over the VLAN. + - Only applicable for AVE domains. + - Accepted values range between C(1) and C(4096). + type: int extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -349,16 +405,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec - -VM_PROVIDER_MAPPING = dict( - cloudfoundry="CloudFoundry", - kubernetes="Kubernetes", - microsoft="Microsoft", - openshift="OpenShift", - openstack="OpenStack", - redhat="Redhat", - vmware="VMware", -) +from ansible_collections.cisco.aci.plugins.module_utils.constants import COS_MAPPING, VM_PROVIDER_MAPPING def main(): @@ -382,7 +429,7 @@ def main(): resolution_immediacy=dict(type="str", choices=["immediate", "lazy", "pre-provision"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects - vm_provider=dict(type="str", choices=["cloudfoundry", "kubernetes", "microsoft", "openshift", "openstack", "redhat", "vmware"]), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), promiscuous=dict(type="str", default="reject", choices=["accept", "reject"]), custom_epg_name=dict(type="str"), delimiter=dict(type="str", choices=["|", "~", "!", "@", "^", "+", "=", "_"]), @@ -392,6 +439,15 @@ def main(): number_of_ports=dict(type="int"), forged_transmits=dict(type="str", default="reject", choices=["accept", "reject"]), mac_changes=dict(type="str", default="reject", choices=["accept", "reject"]), + epg_cos=dict(type="str", choices=list(COS_MAPPING)), + epg_cos_preference=dict(type="str", choices=["enabled", "disabled"]), + ipam_dhcp_override=dict(type="str"), + ipam_enabled=dict(type="bool"), + ipam_gateway=dict(type="str"), + lag_policy_name=dict(type="str"), + netflow_direction=dict(type="str", choices=["both", "ingress", "egress"]), + primary_encap_inner=dict(type="int"), + secondary_encap_inner=dict(type="int"), ) module = AnsibleModule( @@ -414,12 +470,7 @@ def main(): vm_provider = module.params.get("vm_provider") promiscuous = module.params.get("promiscuous") custom_epg_name = module.params.get("custom_epg_name") - encap = module.params.get("encap") - if encap is not None: - if encap in range(1, 4097): - encap = "vlan-{0}".format(encap) - else: - module.fail_json(msg="Valid VLAN assignments are from 1 to 4096") + encap = format_vlan(aci, module.params.get("encap")) encap_mode = module.params.get("encap_mode") switching_mode = module.params.get("switching_mode") epg = module.params.get("epg") @@ -427,12 +478,7 @@ def main(): vmm_uplink_active = module.params.get("vmm_uplink_active") vmm_uplink_standby = module.params.get("vmm_uplink_standby") netflow = aci.boolean(module.params.get("netflow"), "enabled", "disabled") - primary_encap = module.params.get("primary_encap") - if primary_encap is not None: - if primary_encap in range(1, 4097): - primary_encap = "vlan-{0}".format(primary_encap) - else: - module.fail_json(msg="Valid VLAN assignments are from 1 to 4096") + primary_encap = format_vlan(aci, module.params.get("primary_encap")) resolution_immediacy = module.params.get("resolution_immediacy") state = module.params.get("state") tenant = module.params.get("tenant") @@ -449,6 +495,15 @@ def main(): number_of_ports = module.params.get("number_of_ports") forged_transmits = module.params.get("forged_transmits") mac_changes = module.params.get("mac_changes") + epg_cos = COS_MAPPING.get(module.params.get("epg_cos")) + epg_cos_pref = module.params.get("epg_cos_preference") + ipam_dhcp_override = module.params.get("ipam_dhcp_override") + ipam_enabled = aci.boolean(module.params.get("ipam_enabled")) + ipam_gateway = module.params.get("ipam_gateway") + lag_policy_name = module.params.get("lag_policy_name") + netflow_direction = module.params.get("netflow_direction") + primary_encap_inner = format_vlan(aci, module.params.get("primary_encap_inner")) + secondary_encap_inner = format_vlan(aci, module.params.get("secondary_encap_inner")) child_classes = None child_configs = None @@ -535,6 +590,15 @@ def main(): bindingType=port_binding, portAllocation=port_allocation, numPorts=number_of_ports, + epgCos=epg_cos, + epgCosPref=epg_cos_pref, + ipamDhcpOverride=ipam_dhcp_override, + ipamEnabled=ipam_enabled, + ipamGateway=ipam_gateway, + lagPolicyName=lag_policy_name, + netflowDir=netflow_direction, + primaryEncapInner=primary_encap_inner, + secondaryEncapInner=secondary_encap_inner, ), child_configs=child_configs, ) @@ -549,5 +613,13 @@ def main(): aci.exit_json() +def format_vlan(aci, vlan): + if vlan in range(1, 4097): + return "vlan-{0}".format(vlan) + if vlan is not None: + aci.fail_json(msg="Valid VLAN assignments are from 1 to 4096") + return vlan + + if __name__ == "__main__": main() diff --git a/plugins/modules/aci_vmm_controller.py b/plugins/modules/aci_vmm_controller.py index eac547dc1..af531b0ee 100644 --- a/plugins/modules/aci_vmm_controller.py +++ b/plugins/modules/aci_vmm_controller.py @@ -76,7 +76,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -248,26 +248,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec - -VM_PROVIDER_MAPPING = dict( - cloudfoundry="CloudFoundry", - kubernetes="Kubernetes", - microsoft="Microsoft", - openshift="OpenShift", - openstack="OpenStack", - redhat="Redhat", - vmware="VMware", -) - -VM_SCOPE_MAPPING = dict( - cloudfoundry="cloudfoundry", - kubernetes="kubernetes", - microsoft="MicrosoftSCVMM", - openshift="openshift", - openstack="openstack", - redhat="rhev", - vmware="vm", -) +from ansible_collections.cisco.aci.plugins.module_utils.constants import VM_PROVIDER_MAPPING, VM_SCOPE_MAPPING def main(): @@ -284,7 +265,7 @@ def main(): inband_management_epg=dict(type="str"), name_alias=dict(type="str"), datacenter=dict(type="str"), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), ) module = AnsibleModule( diff --git a/plugins/modules/aci_vmm_credential.py b/plugins/modules/aci_vmm_credential.py index bba310bf2..c6c249c33 100644 --- a/plugins/modules/aci_vmm_credential.py +++ b/plugins/modules/aci_vmm_credential.py @@ -59,7 +59,7 @@ - Support for Kubernetes was added in ACI v3.0. - Support for CloudFoundry, OpenShift and Red Hat was added in ACI v3.1. type: str - choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware ] + choices: [ cloudfoundry, kubernetes, microsoft, openshift, openstack, redhat, vmware, nutanix ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation @@ -229,16 +229,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec, aci_owner_spec - -VM_PROVIDER_MAPPING = dict( - cloudfoundry="CloudFoundry", - kubernetes="Kubernetes", - microsoft="Microsoft", - openshift="OpenShift", - openstack="OpenStack", - redhat="Redhat", - vmware="VMware", -) +from ansible_collections.cisco.aci.plugins.module_utils.constants import VM_PROVIDER_MAPPING def main(): @@ -252,7 +243,7 @@ def main(): description=dict(type="str", aliases=["descr"]), domain=dict(type="str", aliases=["domain_name", "domain_profile"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), name_alias=dict(type="str"), ) diff --git a/plugins/modules/aci_vmm_enhanced_lag_policy.py b/plugins/modules/aci_vmm_enhanced_lag_policy.py index 7ea30c97a..a410ea23d 100644 --- a/plugins/modules/aci_vmm_enhanced_lag_policy.py +++ b/plugins/modules/aci_vmm_enhanced_lag_policy.py @@ -207,18 +207,20 @@ ACIModule, aci_argument_spec, enhanced_lag_spec, -) -from ansible_collections.cisco.aci.plugins.module_utils.aci import ( aci_annotation_spec, aci_owner_spec, ) - from ansible_collections.cisco.aci.plugins.module_utils.constants import ( VM_PROVIDER_MAPPING, ) def main(): + + # Remove nutanix from VM_PROVIDER_MAPPING as it is not supported + CLEAN_VM_PROVIDER_MAPPING = VM_PROVIDER_MAPPING.copy() + CLEAN_VM_PROVIDER_MAPPING.pop("nutanix") + argument_spec = aci_argument_spec() argument_spec.update(aci_annotation_spec()) argument_spec.update(aci_owner_spec()) @@ -226,7 +228,7 @@ def main(): argument_spec.update( domain=dict(type="str", aliases=["domain_name", "domain_profile"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING)), + vm_provider=dict(type="str", choices=list(CLEAN_VM_PROVIDER_MAPPING)), ) module = AnsibleModule( @@ -251,7 +253,7 @@ def main(): aci.construct_url( root_class=dict( aci_class="vmmProvP", - aci_rn="vmmp-{0}".format(VM_PROVIDER_MAPPING.get(vm_provider)), + aci_rn="vmmp-{0}".format(CLEAN_VM_PROVIDER_MAPPING.get(vm_provider)), module_object=vm_provider, target_filter={"vendor": vm_provider}, ), diff --git a/plugins/modules/aci_vmm_vswitch_policy.py b/plugins/modules/aci_vmm_vswitch_policy.py index 90525e11c..615d81b69 100644 --- a/plugins/modules/aci_vmm_vswitch_policy.py +++ b/plugins/modules/aci_vmm_vswitch_policy.py @@ -300,20 +300,20 @@ """ from ansible.module_utils.basic import AnsibleModule -from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, enhanced_lag_spec, netflow_spec -from ansible_collections.cisco.aci.plugins.module_utils.aci import aci_annotation_spec, aci_owner_spec +from ansible_collections.cisco.aci.plugins.module_utils.aci import ( + ACIModule, + aci_argument_spec, + enhanced_lag_spec, + netflow_spec, + aci_annotation_spec, + aci_owner_spec, +) +from ansible_collections.cisco.aci.plugins.module_utils.constants import ( + VM_PROVIDER_MAPPING, +) # via UI vSwitch Policy can only be added for VMware and Microsoft vmm domains # behavior for other domains is currently untested. -VM_PROVIDER_MAPPING = dict( - cloudfoundry="CloudFoundry", - kubernetes="Kubernetes", - microsoft="Microsoft", - openshift="OpenShift", - openstack="OpenStack", - redhat="Redhat", - vmware="VMware", -) # enhanced_lag_spec = dict( # name=dict(type='str', required=True), @@ -326,7 +326,6 @@ # 'src-dst-l4port', 'src-port-id', 'vlan']), # number_uplinks=dict(type='int'), # ) - # netflow_spec = dict( # name=dict(type='str', required=True), # active_flow_timeout=dict(type='int'), @@ -336,6 +335,11 @@ def main(): + + # Remove nutanix from VM_PROVIDER_MAPPING as it is not supported + CLEAN_VM_PROVIDER_MAPPING = VM_PROVIDER_MAPPING.copy() + CLEAN_VM_PROVIDER_MAPPING.pop("nutanix") + argument_spec = aci_argument_spec() argument_spec.update(aci_annotation_spec()) argument_spec.update(aci_owner_spec()) @@ -349,7 +353,7 @@ def main(): netflow_exporter=dict(type="dict", options=netflow_spec()), domain=dict(type="str", aliases=["domain_name", "domain_profile"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - vm_provider=dict(type="str", choices=list(VM_PROVIDER_MAPPING.keys())), + vm_provider=dict(type="str", choices=list(CLEAN_VM_PROVIDER_MAPPING)), ) module = AnsibleModule( @@ -388,7 +392,7 @@ def main(): aci.construct_url( root_class=dict( aci_class="vmmProvP", - aci_rn="vmmp-{0}".format(VM_PROVIDER_MAPPING.get(vm_provider)), + aci_rn="vmmp-{0}".format(CLEAN_VM_PROVIDER_MAPPING.get(vm_provider)), module_object=vm_provider, target_filter={"name": vm_provider}, ), diff --git a/tests/integration/targets/aci_epg_to_domain/tasks/main.yml b/tests/integration/targets/aci_epg_to_domain/tasks/main.yml index 0903178ef..81d6efe62 100644 --- a/tests/integration/targets/aci_epg_to_domain/tasks/main.yml +++ b/tests/integration/targets/aci_epg_to_domain/tasks/main.yml @@ -236,22 +236,42 @@ vmm_uplink_active: [ 3, 4 ] register: vmm_uplink_change_active + - name: Sort vmm_uplink children by name + ansible.builtin.set_fact: + vmm_uplink_sorted_children: "{{ vmm_uplink.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + + - name: Sort vmm_uplink_change_standby previous children by name + ansible.builtin.set_fact: + vmm_uplink_change_standby_sorted_children_previous: "{{ vmm_uplink_change_standby.previous[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + + - name: Sort vmm_uplink_change_standby current children by name + ansible.builtin.set_fact: + vmm_uplink_change_standby_sorted_children_current: "{{ vmm_uplink_change_standby.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + + - name: Sort vmm_uplink_change_active previous children by name + ansible.builtin.set_fact: + vmm_uplink_change_active_sorted_children_previous: "{{ vmm_uplink_change_active.previous[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + + - name: Sort vmm_uplink_change_active current children by name + ansible.builtin.set_fact: + vmm_uplink_change_active_sorted_children_current: "{{ vmm_uplink_change_active.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + - name: vmm_uplink assertions ansible.builtin.assert: that: - vmm_uplink is changed - - vmm_uplink.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" - - vmm_uplink.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "3,4" + - vmm_uplink_sorted_children.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_sorted_children.0.fvUplinkOrderCont.attributes.standby == "3,4" - vmm_uplink_change_standby is changed - - vmm_uplink_change_standby.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" - - vmm_uplink_change_standby.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "3,4" - - vmm_uplink_change_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" - - vmm_uplink_change_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" + - vmm_uplink_change_standby_sorted_children_previous.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_standby_sorted_children_previous.0.fvUplinkOrderCont.attributes.standby == "3,4" + - vmm_uplink_change_standby_sorted_children_current.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_standby_sorted_children_current.0.fvUplinkOrderCont.attributes.standby == "5,6" - vmm_uplink_change_active is changed - - vmm_uplink_change_active.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "1,2" - - vmm_uplink_change_active.previous.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" - - vmm_uplink_change_active.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "3,4" - - vmm_uplink_change_active.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "5,6" + - vmm_uplink_change_active_sorted_children_previous.0.fvUplinkOrderCont.attributes.active == "1,2" + - vmm_uplink_change_active_sorted_children_previous.0.fvUplinkOrderCont.attributes.standby == "5,6" + - vmm_uplink_change_active_sorted_children_current.0.fvUplinkOrderCont.attributes.active == "3,4" + - vmm_uplink_change_active_sorted_children_current.0.fvUplinkOrderCont.attributes.standby == "5,6" - name: bind vmm domain to epg - vmm_uplink change standby to same as active cisco.aci.aci_epg_to_domain: @@ -262,6 +282,8 @@ register: vmm_uplink_change_active_same_as_standby ignore_errors: true + # ACI 6+ gives validation error + # Active Uplink configuration cannot be empty when standby uplink configuration exists OR Active uplink can not be 0 as no uplink get assigned in the vCenter." - name: bind vmm domain to epg - vmm_uplink change 0 value cisco.aci.aci_epg_to_domain: <<: *aci_epg_to_domain_present @@ -269,6 +291,7 @@ vm_provider: vmware vmm_uplink_active: [ 0 ] register: vmm_uplink_0_value + when: version.current.0.topSystem.attributes.version is version('6.0', '<') - name: bind vmm domain to epg - vmm_uplink change 32 value cisco.aci.aci_epg_to_domain: @@ -285,16 +308,29 @@ vm_provider: vmware vmm_uplink_standby: [] register: vmm_uplink_empty_value_standby + + - name: Sort vmm_uplink_32_value children by name + ansible.builtin.set_fact: + vmm_uplink_32_value_sorted_children: "{{ vmm_uplink_32_value.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" - - name: vmm_uplink assertions + - name: Sort vmm_uplink_empty_value_standby children by name + ansible.builtin.set_fact: + vmm_uplink_empty_value_standby_sorted_children: "{{ vmm_uplink_empty_value_standby.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + + - name: vmm_uplink assertions version < 6 ansible.builtin.assert: that: - vmm_uplink_0_value is changed - vmm_uplink_0_value.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "0" + when: version.current.0.topSystem.attributes.version is version('6.0', '<') + + - name: vmm_uplink assertions + ansible.builtin.assert: + that: - vmm_uplink_32_value is changed - - vmm_uplink_32_value.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.active == "32" + - vmm_uplink_32_value_sorted_children.0.fvUplinkOrderCont.attributes.active == "32" - vmm_uplink_empty_value_standby is changed - - vmm_uplink_empty_value_standby.current.0.fvRsDomAtt.children.0.fvUplinkOrderCont.attributes.standby == "" + - vmm_uplink_empty_value_standby_sorted_children.0.fvUplinkOrderCont.attributes.standby == "" - name: bind vmm domain to epg - vmm_uplink change empty value active cisco.aci.aci_epg_to_domain: @@ -609,6 +645,10 @@ - forged_transmits_and_mac_changes_absent is changed - forged_transmits_and_mac_changes_absent.current == [] + - name: Sort enhanced_lag_policy children by name + ansible.builtin.set_fact: + enhanced_lag_policy_sorted_children: "{{ enhanced_lag_policy.current[0].fvRsDomAtt.children | map('dict2items') | sort(attribute='0.key') | map('items2dict') | list }}" + - name: present assertions ansible.builtin.assert: that: @@ -638,8 +678,8 @@ - invalid_vlan_primary_encap.msg == "Valid VLAN assignments are from 1 to 4096" - '"[uni/l2dom-anstest].json" in l2_present.url' - valid_vlan_primary_encap.current.0.fvRsDomAtt.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rsdomAtt-[uni/phys-anstest]" - - enhanced_lag_policy.current.0.fvRsDomAtt.children | length == 2 - - enhanced_lag_policy.current.0.fvRsDomAtt.children.0.fvAEPgLagPolAtt.children.0.fvRsVmmVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-anstest/vswitchpolcont/enlacplagp-enhanced" + - enhanced_lag_policy_sorted_children | length == 2 + - enhanced_lag_policy_sorted_children.0.fvAEPgLagPolAtt.children.0.fvRsVmmVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-anstest/vswitchpolcont/enlacplagp-enhanced" - name: get domain epg binding cisco.aci.aci_epg_to_domain: &aci_epg_domain_query @@ -774,4 +814,138 @@ cisco.aci.aci_tenant: <<: *underscore_tenant state: absent - register: tenant_present \ No newline at end of file + register: tenant_present + + # ADDITIONAL ADDED ATTRIBUTES + + - name: Ensure tenant does not exist for testing additional attributes + cisco.aci.aci_tenant: &additional_attributes_tenant + <<: *aci_info + tenant: additional_attributes + state: absent + + - name: Ensure tenant exists for testing additional attributes + cisco.aci.aci_tenant: + <<: *additional_attributes_tenant + tenant: additional_attributes + state: present + + - name: Ensure ap exists for testing additional attributes + cisco.aci.aci_ap: &additional_attributes_ap + <<: *additional_attributes_tenant + ap: additional_attributes + state: present + + - name: Ensure epg exists for testing additional attributes + cisco.aci.aci_epg: &additional_attributes_epg + <<: *additional_attributes_ap + epg: additional_attributes + + - name: Create domain with additional attributes as defaults + cisco.aci.aci_epg_to_domain: &additional_attributes_domain + <<: *additional_attributes_epg + domain: additional_attributes_test + domain_type: vmm + vm_provider: vmware + register: create_additional_attributes_domain + + - name: Update domain with additional attributes + cisco.aci.aci_epg_to_domain: + <<: *additional_attributes_domain + epg_cos: cos_4 + epg_cos_preference: enabled + lag_policy_name: lag_policy_test + netflow_direction: ingress + primary_encap_inner: 600 + secondary_encap_inner: 700 + register: update_additional_attributes_domain + + - name: Assert additional attributes + ansible.builtin.assert: + that: + - create_additional_attributes_domain is changed + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.tDn == "uni/vmmp-VMware/dom-additional_attributes_test" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.epgCos == "Cos0" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.epgCosPref == "disabled" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.lagPolicyName == "" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.netflowDir == "both" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.primaryEncapInner == "unknown" + - create_additional_attributes_domain.current.0.fvRsDomAtt.attributes.secondaryEncapInner == "unknown" + - update_additional_attributes_domain is changed + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.tDn == "uni/vmmp-VMware/dom-additional_attributes_test" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.epgCos == "Cos4" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.epgCosPref == "enabled" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.lagPolicyName == "lag_policy_test" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.netflowDir == "ingress" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.primaryEncapInner == "vlan-600" + - update_additional_attributes_domain.current.0.fvRsDomAtt.attributes.secondaryEncapInner == "vlan-700" + + - name: Remove tenant used for testing additional attributes + cisco.aci.aci_tenant: + <<: *additional_attributes_tenant + state: absent + register: additional_attributes_tenant_removed + + # NUTANIX SPECIFIC + - name: Execute tasks only for ACI v6+ + when: version.current.0.topSystem.attributes.version is version('6', '>=') + block: # block specifies execution of tasks within, based on conditions + + - name: Ensure tenant does not exists for testing nutanix specifc values + cisco.aci.aci_tenant: &nutanix_tenant + <<: *aci_info + tenant: nutanix + state: absent + + - name: Ensure tenant exists for testing nutanix specifc values + cisco.aci.aci_tenant: + <<: *nutanix_tenant + state: present + + - name: Ensure ap exists for testing nutanix specific values + cisco.aci.aci_ap: &nutanix_ap + <<: *nutanix_tenant + ap: nutanix + state: present + + - name: Ensure epg exists for testing nutanix specific values + cisco.aci.aci_epg: &nutanix_epg + <<: *nutanix_ap + epg: nutanix + + - name: Create domain with nutanix specific values + cisco.aci.aci_epg_to_domain: &nutanix_domain + <<: *nutanix_epg + domain: nutanix_test + domain_type: vmm + vm_provider: nutanix + resolution_immediacy: pre-provision + register: create_nutanix_domain + + - name: Update domain with nutanix specific values + cisco.aci.aci_epg_to_domain: + <<: *nutanix_domain + ipam_dhcp_override: "2.2.2.2" + ipam_gateway: "2.2.2.1/24" + ipam_enabled: yes + register: update_nutanix_domain + + - name: Assert nutanix specific values + ansible.builtin.assert: + that: + - create_nutanix_domain is changed + - create_nutanix_domain.current.0.fvRsDomAtt.attributes.tDn == "uni/vmmp-Nutanix/dom-nutanix_test" + - create_nutanix_domain.current.0.fvRsDomAtt.attributes.resImedcy == "pre-provision" + - create_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamDhcpOverride == "0.0.0.0" + - create_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamEnabled == "no" + - create_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamGateway == "0.0.0.0" + - update_nutanix_domain is changed + - update_nutanix_domain.current.0.fvRsDomAtt.attributes.tDn == "uni/vmmp-Nutanix/dom-nutanix_test" + - update_nutanix_domain.current.0.fvRsDomAtt.attributes.resImedcy == "pre-provision" + - update_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamDhcpOverride == "2.2.2.2" + - update_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamEnabled == "yes" + - update_nutanix_domain.current.0.fvRsDomAtt.attributes.ipamGateway == "2.2.2.1/24" + + - name: Remove tenant used for testing nutanix specific values + cisco.aci.aci_tenant: + <<: *nutanix_tenant