diff --git a/plugins/module_utils/aci.py b/plugins/module_utils/aci.py index da7fec758..996da4841 100644 --- a/plugins/module_utils/aci.py +++ b/plugins/module_utils/aci.py @@ -779,6 +779,7 @@ def construct_url( subclass_3=None, subclass_4=None, subclass_5=None, + subclass_6=None, child_classes=None, config_only=True, ): @@ -796,6 +797,7 @@ def construct_url( :type subclass_3: dict :type subclass_4: dict :type subclass_5: dict + :type subclass_6: dict :type child_classes: list :return: The path and filter_string needed to build the full URL. """ @@ -806,7 +808,9 @@ def construct_url( else: self.child_classes = set(child_classes) - if subclass_5 is not None: + if subclass_6 is not None: + self._construct_url_7(root_class, subclass_1, subclass_2, subclass_3, subclass_4, subclass_5, subclass_6, config_only) + elif subclass_5 is not None: self._construct_url_6(root_class, subclass_1, subclass_2, subclass_3, subclass_4, subclass_5, config_only) elif subclass_4 is not None: self._construct_url_5(root_class, subclass_1, subclass_2, subclass_3, subclass_4, config_only) @@ -1077,7 +1081,7 @@ def _construct_url_5(self, root, ter, sec, parent, obj, config_only=True): def _construct_url_6(self, root, quad, ter, sec, parent, obj, config_only=True): """ - This method is used by construct_url when the object is the fourth-level class. + This method is used by construct_url when the object is the fifth-level class. """ root_rn = root.get("aci_rn") root_obj = root.get("module_object") @@ -1145,6 +1149,85 @@ def _construct_url_6(self, root, quad, ter, sec, parent, obj, config_only=True): # Query for a specific object of the module's class self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}.json".format(root_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn) + def _construct_url_7(self, root, quin, quad, ter, sec, parent, obj, config_only=True): + """ + This method is used by construct_url when the object is the sixth-level class. + """ + root_rn = root.get("aci_rn") + root_obj = root.get("module_object") + quin_rn = quin.get("aci_rn") + quin_obj = quin.get("module_object") + quad_rn = quad.get("aci_rn") + quad_obj = quad.get("module_object") + ter_rn = ter.get("aci_rn") + ter_obj = ter.get("module_object") + sec_rn = sec.get("aci_rn") + sec_obj = sec.get("module_object") + parent_rn = parent.get("aci_rn") + parent_obj = parent.get("module_object") + obj_class = obj.get("aci_class") + obj_rn = obj.get("aci_rn") + obj_filter = obj.get("target_filter") + mo = obj.get("module_object") + + if self.child_classes is None: + self.child_classes = [obj_class] + + if self.module.params.get("state") in ("absent", "present"): + # State is absent or present + self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}/{6}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn) + if config_only: + self.update_qs({"rsp-prop-include": "config-only"}) + self.obj_filter = obj_filter + # TODO: Add all missing cases + elif root_obj is None: + self.child_classes.add(obj_class) + self.path = "api/class/{0}.json".format(obj_class) + self.update_qs({"query-target-filter": self.build_filter(obj_class, obj_filter)}) + elif quin_obj is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}.json".format(root_rn) + # NOTE: No need to select by root_filter + # self.update_qs({'query-target-filter': self.build_filter(root_class, root_filter)}) + # TODO: Filter by quin_filter, parent and obj_filter + self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)}) + elif quad_obj is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}/{1}.json".format(root_rn, quin_rn) + # NOTE: No need to select by root_filter + # self.update_qs({'query-target-filter': self.build_filter(root_class, root_filter)}) + # TODO: Filter by quin_filter, parent and obj_filter + self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)}) + elif ter_obj is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}/{1}/{2}.json".format(root_rn, quin_rn, quad_rn) + # NOTE: No need to select by quad_filter + # self.update_qs({'query-target-filter': self.build_filter(quin_class, quin_filter)}) + # TODO: Filter by ter_filter, parent and obj_filter + self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)}) + elif sec_obj is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}/{1}/{2}/{3}.json".format(root_rn, quin_rn, quad_rn, ter_rn) + # NOTE: No need to select by ter_filter + # self.update_qs({'query-target-filter': self.build_filter(ter_class, ter_filter)}) + # TODO: Filter by sec_filter, parent and obj_filter + self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)}) + elif parent_obj is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn) + # NOTE: No need to select by sec_filter + # self.update_qs({'query-target-filter': self.build_filter(sec_class, sec_filter)}) + # TODO: Filter by parent_filter and obj_filter + self.update_qs({"rsp-subtree-filter": self.build_filter(obj_class, obj_filter)}) + elif mo is None: + self.child_classes.add(obj_class) + self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn) + # NOTE: No need to select by parent_filter + # self.update_qs({'query-target-filter': self.build_filter(parent_class, parent_filter)}) + else: + # Query for a specific object of the module's class + self.path = "api/mo/uni/{0}/{1}/{2}/{3}/{4}/{5}/{6}.json".format(root_rn, quin_rn, quad_rn, ter_rn, sec_rn, parent_rn, obj_rn) + def delete_config(self): """ This method is used to handle the logic when the modules state is equal to absent. The method only pushes a change if diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 97d5c4fa2..1e95029d3 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -62,6 +62,14 @@ - IP address. type: str aliases: [ addr, ip_address ] + mac_address: + description: + - The MAC address option of the interface. + type: str + link_local_address: + description: + - The link local address option of the interface. + type: str mtu: description: - Interface MTU. @@ -325,7 +333,6 @@ def main(): encap=dict(type="str"), encap_scope=dict(type="str", choices=["vrf", "local"]), auto_state=dict(type="str", choices=["enabled", "disabled"]), - description=dict(type="str", aliases=["descr"]), external_bridge_group_profile=dict(type="str"), dscp=dict( type="str", @@ -374,6 +381,8 @@ def main(): address = module.params.get("address") mtu = module.params.get("mtu") ipv6_dad = module.params.get("ipv6_dad") + link_local_address = module.params.get("link_local_address") + mac_address = module.params.get("mac_address") mode = module.params.get("mode") encap = module.params.get("encap") encap_scope = "ctx" if module.params.get("encap_scope") == "vrf" else module.params.get("encap_scope") @@ -441,7 +450,6 @@ def main(): l3extRsBdProfile=dict( attributes=dict( tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), - ), ) ) @@ -453,7 +461,16 @@ def main(): aci.payload( aci_class="l3extVirtualLIfP", class_config=dict( - addr=address, ipv6Dad=ipv6_dad, mtu=mtu, ifInstT="ext-svi", mode=mode, encap=encap, encapScope=encap_scope, autostate=auto_state + addr=address, + ipv6Dad=ipv6_dad, + mtu=mtu, + ifInstT="ext-svi", + mode=mode, + encap=encap, + encapScope=encap_scope, + autostate=auto_state, + llAddr=link_local_address, + mac=mac_address, ), child_configs=child_configs, ) diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index 1a628043d..f501664c5 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -44,15 +44,26 @@ description: - Pod to build the interface on. type: str + required: true node_id: description: - Node to build the interface on for Port-channels and single ports. type: str + required: true + encap: + description: + - Encapsulation on the interface (e.g. "vlan-500") + type: str + required: true + address: + description: + - IP address of the floating SVI interface. + type: str + aliases: [ addr, ip_address ] domain: description: - This option allows virtual machines to send frames with a mac address. type: str - choices: [ enable, disable ] domain_type: description: - The domain type of the path. @@ -60,7 +71,7 @@ choices: [ physical, vmware ] access_encap: description: - - The port encapsulation. + - The port encapsulation option. type: str floating_ip: description: @@ -71,17 +82,20 @@ description: - This option allows virtual machines to send frames with a mac address. type: str - choices: [ enable, disable ] + choices: [ enabled, disabled ] + default: disabled mac_change: description: - The status of the mac address change support for port groups in an external VMM controller. type: str - choices: [ enable, disable ] + choices: [ enabled, disabled ] + default: disabled promiscuous_mode: description: - The status of promiscuous mode for port groups in an external VMM controller. type: str - choices: [ enable, disable ] + choices: [ enabled, disabled ] + default: disabled enhanced_lag_policy: description: - The enhanced lag policy of the path. @@ -320,13 +334,15 @@ def main(): pod_id=dict(type="str", required=True), node_id=dict(type="str", required=True), encap=dict(type="str", required=True), - floating_ip=dict(type="str", aliases=["floating_address"], required=True), - forged_transmit=dict(type="str", choices=["enabled", "disabled"]), - mac_change=dict(type="str", choices=["enabled", "disabled"]), - promiscuous_mode=dict(type="str", choices=["enabled", "disabled"]), - domain_type=dict(type="str", choices=["physical", "vmware"], required=True), - domain=dict(type="str", required=True), + address=dict(type="str", aliases=["addr", "ip_address"]), + floating_ip=dict(type="str", aliases=["floating_address"]), + forged_transmit=dict(type="str", choices=["enabled", "disabled"], default="disabled"), + mac_change=dict(type="str", choices=["enabled", "disabled"], default="disabled"), + promiscuous_mode=dict(type="str", choices=["enabled", "disabled"], default="disabled"), + domain_type=dict(type="str", choices=["physical", "vmware"]), + domain=dict(type="str"), enhanced_lag_policy=dict(type="str"), + access_encap=dict(type="str"), ) module = AnsibleModule( @@ -344,17 +360,19 @@ def main(): node_id = module.params.get("node_id") floating_ip = module.params.get("floating_ip") encap = module.params.get("encap") - forged_transmit = module.params.get("forged_transmit") - mac_change = module.params.get("mac_change") - promiscuous_mode = module.params.get("promiscuous_mode") + forged_transmit = module.params.get("forged_transmit").capitalize() + mac_change = module.params.get("mac_change").capitalize() + promiscuous_mode = module.params.get("promiscuous_mode").capitalize() domain_type = module.params.get("domain_type") domain = module.params.get("domain") enhanced_lag_policy = module.params.get("enhanced_lag_policy") + access_encap = module.params.get("access_encap") aci = ACIModule(module) node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + tDn = None if domain_type == "physical": tDn = "uni/phys-{0}".format(domain) elif domain_type == "vmware": @@ -401,7 +419,7 @@ def main(): if state == "present": child_configs = [] - if enhanced_lag_policy is not None and domain_type == "virtual": + if enhanced_lag_policy is not None and domain_type == "vmware": existing_enhanced_lag_policy = "" if isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}): @@ -448,6 +466,7 @@ def main(): forgedTransmit=forged_transmit, macChange=mac_change, promMode=promiscuous_mode, + encap=access_encap, ), child_configs=child_configs, ) diff --git a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py index 2f84ae2be..a46e12cbd 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -48,25 +48,47 @@ description: - Pod to build the interface on. type: str + required: true node_id: description: - Node to build the interface on for Port-channels and single ports. type: str + required: true + encap: + description: + - Encapsulation on the interface (e.g. "vlan-500") + type: str + required: true + address: + description: + - The floating IP address. + type: str + aliases: [ addr, ip_address ] domain: description: - This option allows virtual machines to send frames with a mac address. type: str - choices: [ enable, disable ] + required: true domain_type: description: - The domain type of the path. type: str choices: [ physical, vmware ] + required: true + floating_ip: + description: + - The floating IP address. + type: str + aliases: [ floating_address ] secondary_ip: description: - The secondary floating IP address. type: str aliases: [ secondary_floating_address ] + access_encap: + description: + - Encapsulation of the floating path attribute. + type: str state: description: - Use C(present) or C(absent) for adding or removing. @@ -78,13 +100,9 @@ - cisco.aci.aci - cisco.aci.annotation -notes: -- This is a test seealso: -- module: aci_l3out -- module: aci_l3out_logical_node_profile -- module: aci_l3out_logical_interface_profile -- module: aci_l3out_logical_interface +- module: aci_l3out_floating_svi +- module: aci_l3out_floating_svi_path - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) link: https://developer.cisco.com/docs/apic-mim-ref/ @@ -288,9 +306,12 @@ def main(): pod_id=dict(type="str", required=True), node_id=dict(type="str", required=True), encap=dict(type="str", required=True), + address=dict(type="str", aliases=["addr", "ip_address"]), + floating_ip=dict(type="str", aliases=["floating_address"]), domain_type=dict(type="str", choices=["physical", "vmware"], required=True), domain=dict(type="str", required=True), secondary_ip=dict(type="str", aliases=["secondary_floating_address"]), + access_encap=dict(type="str"), ) module = AnsibleModule( @@ -320,7 +341,7 @@ def main(): interface_profile = module.params.get("interface_profile") pod_id = module.params.get("pod_id") node_id = module.params.get("node_id") - encap = (module.params.get("encap"),) + encap = module.params.get("encap") secondary_ip = module.params.get("secondary_ip") domain_type = module.params.get("domain_type") domain = module.params.get("domain") @@ -330,9 +351,10 @@ def main(): node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + tDn = None if domain_type == "physical": tDn = "uni/phys-{0}".format(domain) - elif domain_type == "vmware": + else: tDn = "uni/vmmp-VMware/dom-{0}".format(domain) aci.construct_url( diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index c5fee236d..efa010a97 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -48,15 +48,31 @@ description: - Pod to build the interface on. type: str + required: true node_id: description: - Node to build the interface on for Port-channels and single ports. type: str + required: true + encap: + description: + - Encapsulation on the interface (e.g. "vlan-500") + type: str + required: true secondary_ip: description: - The secondary floating IP address. type: str aliases: [ secondary_floating_address ] + address: + description: + - The floating IP address. + type: str + aliases: [ addr, ip_address ] + external_bridge_group_profile: + description: + - The external bridge group profile. + type: str state: description: - Use C(present) or C(absent) for adding or removing. @@ -74,7 +90,7 @@ - module: aci_l3out - module: aci_l3out_logical_node_profile - module: aci_l3out_logical_interface_profile -- module: aci_l3out_logical_interface +- module: aci_l3out_floating_svi - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) link: https://developer.cisco.com/docs/apic-mim-ref/ @@ -270,7 +286,9 @@ def main(): pod_id=dict(type="str", required=True), node_id=dict(type="str", required=True), encap=dict(type="str", required=True), + address=dict(type="str", aliases=["addr", "ip_address"]), secondary_ip=dict(type="str", aliases=["secondary_floating_address"]), + external_bridge_group_profile=dict(type="str"), ) module = AnsibleModule( @@ -300,7 +318,7 @@ def main(): interface_profile = module.params.get("interface_profile") pod_id = module.params.get("pod_id") node_id = module.params.get("node_id") - encap = (module.params.get("encap"),) + encap = module.params.get("encap") secondary_ip = module.params.get("secondary_ip") state = module.params.get("state") diff --git a/plugins/modules/aci_rest.py b/plugins/modules/aci_rest.py index 374c9206f..d1207f464 100644 --- a/plugins/modules/aci_rest.py +++ b/plugins/modules/aci_rest.py @@ -406,7 +406,8 @@ def main(): module.fail_json(msg="Failed to parse provided XML payload: {0}".format(to_text(e)), payload=payload) # Perform actual request using auth cookie (Same as aci.request(), but also supports XML) - aci.url = "{0}/{1}".format(aci.base_url, path.lstrip("/")) + aci.path = path.lstrip("/") + aci.url = "{0}/{1}".format(aci.base_url, aci.path) if aci.params.get("method") != "get" and not rsp_subtree_preserve: aci.url = update_qsl(aci.url, {"rsp-subtree": "modified"}) diff --git a/tests/integration/inventory.networking b/tests/integration/inventory.networking index 3ad73a97d..357f58758 100644 --- a/tests/integration/inventory.networking +++ b/tests/integration/inventory.networking @@ -1,10 +1,10 @@ [aci] -#cn-dmz-apic-m1-02-v42 ansible_host=173.36.219.68 aci_hostname=173.36.219.68 -#cn-dmz-apic-m1-03-v52 ansible_host=173.36.219.69 aci_hostname=173.36.219.69 -#cn-dmz-apic-m1-04-v60 ansible_host=173.36.219.70 aci_hostname=173.36.219.70 +cn-dmz-apic-m1-02-v42 ansible_host=173.36.219.68 aci_hostname=173.36.219.68 +cn-dmz-apic-m1-03-v52 ansible_host=173.36.219.69 aci_hostname=173.36.219.69 +cn-dmz-apic-m1-04-v60 ansible_host=173.36.219.70 aci_hostname=173.36.219.70 cn-dmz-apic-m1-07-v32 ansible_host=173.36.219.73 aci_hostname=173.36.219.73 -#aws_cloud ansible_host=52.52.20.121 aci_hostname=52.52.20.121 cloud_type=aws region=us-east-1 region_2=us-west-1 availability_zone=us-west-1a -#azure_cloud ansible_host=20.245.236.136 aci_hostname=20.245.236.136 cloud_type=azure region=westus region_2=westus2 vnet_gateway=true +aws_cloud ansible_host=52.52.20.121 aci_hostname=52.52.20.121 cloud_type=aws region=us-east-1 region_2=us-west-1 availability_zone=us-west-1a +azure_cloud ansible_host=20.245.236.136 aci_hostname=20.245.236.136 cloud_type=azure region=westus region_2=westus2 vnet_gateway=true [aci:vars] aci_username=ansible_github_ci diff --git a/tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml index cee435793..523193528 100644 --- a/tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml @@ -51,7 +51,7 @@ domain: l3outintftest route_control: export - - name: Crete node profile + - name: Create node profile cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outintftest @@ -62,79 +62,212 @@ <<: *np_present interface_profile: Floating - - name: Create a floating svi in check mode + - name: Create a floating svi cisco.aci.aci_l3out_floating_svi: &floating_svi <<: *intf_present pod_id: 1 node_id: 201 encap: vlan-1 address: 23.45.67.90/24 - external_bridge_group_profile: bridge1 + state: present + + - name: Create a floating svi + cisco.aci.aci_l3out_floating_svi: &floating_svi2 + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 + address: 26.45.67.90/24 + state: present + + - name: Add VMM domain + cisco.aci.aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + state: present + + - name: Add a vSwitch policy to vmware domain + cisco.aci.aci_vmm_vswitch_policy: + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + enhanced_lag: + - name: enhanced + - name: enhanced2 + state: present + + - name: Create a floating svi path of type physical in check_mode + cisco.aci.aci_l3out_floating_svi_path: + <<: *floating_svi + domain_type: physical + domain: physical_dom + floating_ip: 25.45.67.90/24 + access_encap: vlan-1 state: present check_mode: true - register: add_floating_cm + register: add_floating_path_cm - - name: Create a floating svi in normal mode - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi path of type physical in normal mode + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi + domain_type: physical + domain: physical_dom + floating_ip: 25.45.67.90/24 + access_encap: vlan-1 state: present - register: add_floating_nm + register: add_floating_path_nm - - name: Create a floating svi again - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi path of type physical in normal mode again + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi + domain_type: physical + domain: physical_dom + floating_ip: 25.45.67.90/24 + access_encap: vlan-1 state: present - register: add_floating_again + register: add_floating_path_again - - name: Update floating svi - cisco.aci.aci_l3out_floating_svi: + - name: Update a floating svi path of type physical + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi - external_bridge_group_profile: bridge2 + domain_type: physical + domain: physical_dom + floating_ip: 25.45.67.90/24 + access_encap: vlan-2 state: present - register: update_floating + register: update_floating_path - - name: Delete an external_bridge_group_profile - cisco.aci.aci_l3out_floating_svi: + - name: Create another floating svi path of type physical + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi - external_bridge_group_profile: "" + domain_type: physical + domain: physical_dom2 + floating_ip: 25.45.67.90/24 + access_encap: vlan-1 state: present - register: remove_bridge + register: add_another_floating_path - - name: Create another floating svi - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present - pod_id: 1 - node_id: 202 - encap: vlan-1 - address: 24.45.67.90/24 - external_bridge_group_profile: bridge2 + - name: Create a floating svi path of type virtual + cisco.aci.aci_l3out_floating_svi_path: + <<: *floating_svi2 + domain_type: vmware + domain: vmm_dom + floating_ip: 27.45.67.90/24 + forged_transmit: enabled + mac_change: enabled + promiscuous_mode: enabled + enhanced_lag_policy: enhanced + state: present + register: add_enhanced + + - name: Create a floating svi path of type virtual (change enhanced_lag_policy) + cisco.aci.aci_l3out_floating_svi_path: + <<: *floating_svi2 + domain_type: vmware + domain: vmm_dom + floating_ip: 27.45.67.90/24 + forged_transmit: enabled + mac_change: enabled + promiscuous_mode: enabled + enhanced_lag_policy: enhanced2 state: present - register: add_floating2 + register: change_enhanced - - name: Verify nm_add_intf + - name: Create a floating svi path of type virtual (delete enhanced_lag_policy) + cisco.aci.aci_l3out_floating_svi_path: + <<: *floating_svi2 + domain_type: vmware + domain: vmm_dom + floating_ip: 27.45.67.90/24 + forged_transmit: enabled + mac_change: enabled + promiscuous_mode: enabled + enhanced_lag_policy: "" + state: present + register: del_enhanced + + - name: Verify present ops assert: that: - - cm_add_intf is changed - - nm_add_intf is changed - - cm_add_intf.previous == nm_add_intf.previous == [] - - cm_add_intf.sent.l3extLIfP.attributes.name == nm_add_intf.sent.l3extLIfP.attributes.name == 'INTFS' - - cm_add_intf.sent.l3extLIfP.attributes.descr == nm_add_intf.sent.l3extLIfP.attributes.descr == 'test' - - nm_add_intf.current.0.l3extLIfP.attributes.annotation == 'orchestrator:ansible' - - - name: Query a floating svi - cisco.aci.aci_l3out_floating_svi: + - add_floating_path_cm is changed + - add_floating_path_nm is changed + - add_floating_path_again is not changed + - update_floating_path is changed + - add_another_floating_path is changed + - add_enhanced is changed + - change_enhanced is changed + - del_enhanced is changed + - add_floating_path_nm.current.0.l3extRsDynPathAtt.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]/rsdynPathAtt-[uni/phys-physical_dom]" + - add_floating_path_nm.current.0.l3extRsDynPathAtt.attributes.encap == "vlan-1" + - add_floating_path_nm.current.0.l3extRsDynPathAtt.attributes.floatingAddr == "25.45.67.90/24" + - update_floating_path.current.0.l3extRsDynPathAtt.attributes.encap == "vlan-2" + - add_enhanced.current.0.l3extRsDynPathAtt.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-202]-[vlan-1]/rsdynPathAtt-[uni/vmmp-VMware/dom-vmm_dom]" + - add_enhanced.current.0.l3extRsDynPathAtt.attributes.floatingAddr == "27.45.67.90/24" + - add_enhanced.current.0.l3extRsDynPathAtt.attributes.forgedTransmit == "Enabled" + - add_enhanced.current.0.l3extRsDynPathAtt.attributes.macChange == "Enabled" + - add_enhanced.current.0.l3extRsDynPathAtt.attributes.promMode == "Enabled" + - add_enhanced.current.0.l3extRsDynPathAtt.children.0.l3extVirtualLIfPLagPolAtt.children.0.l3extRsVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont/enlacplagp-enhanced" + - change_enhanced.current.0.l3extRsDynPathAtt.children.0.l3extVirtualLIfPLagPolAtt.children.0.l3extRsVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont/enlacplagp-enhanced2" + - del_enhanced.current.0.l3extRsDynPathAtt.children is not defined + + - name: Query a floating svi path + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi + domain_type: physical + domain: physical_dom state: query register: query_floating - - name: Query all floating svis - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present + - name: Query all floating svi paths + cisco.aci.aci_l3out_floating_svi_path: + <<: *floating_svi state: query register: query_all_floating - - name: Remove a floating svi - cisco.aci.aci_l3out_logical_interface_profile: + - name: Verify query ops + assert: + that: + - query_floating is not changed + - query_all_floating is not changed + - query_floating.current.0.l3extRsDynPathAtt.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]/rsdynPathAtt-[uni/phys-physical_dom]" + - query_floating.current.0.l3extRsDynPathAtt.attributes.floatingAddr == "25.45.67.90/24" + - query_floating.current.0.l3extRsDynPathAtt.attributes.encap == "vlan-2" + - query_all_floating.current.0.l3extVirtualLIfP.children | length == 2 + + - name: Remove a floating svi path + cisco.aci.aci_l3out_floating_svi_path: <<: *floating_svi + domain_type: physical + domain: physical_dom + state: absent + register: remove_floating_path + + - name: Verify absent ops + assert: + that: + - remove_floating_path is changed + - remove_floating_path.current == [] + + # Clean up Environment + - name: Remove vSwitch Policy + cisco.aci.aci_vmm_vswitch_policy: + <<: *aci_info + domain: vmm_dom + vm_provider: vmware + state: absent + + - name: Remove VMM domain + cisco.aci.aci_domain: + <<: *aci_info + domain: vmm_dom + domain_type: vmm + vm_provider: vmware + state: absent + + - name: Remove test tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test state: absent - register: remove_floating diff --git a/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml index cee435793..596ddc752 100644 --- a/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml @@ -11,7 +11,7 @@ validate_certs: '{{ aci_validate_certs | default(false) }}' use_ssl: '{{ aci_use_ssl | default(true) }}' use_proxy: '{{ aci_use_proxy | default(true) }}' - output_level: '{{ aci_output_level | default("info") }}' + output_level: '{{ aci_output_level | default("debug") }}' # CLEAN ENVIRONMENT - name: Remove test tenant before we kickoff @@ -51,7 +51,7 @@ domain: l3outintftest route_control: export - - name: Crete node profile + - name: Create node profile cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outintftest @@ -62,79 +62,115 @@ <<: *np_present interface_profile: Floating - - name: Create a floating svi in check mode + - name: Create a floating svi cisco.aci.aci_l3out_floating_svi: &floating_svi <<: *intf_present pod_id: 1 node_id: 201 encap: vlan-1 address: 23.45.67.90/24 - external_bridge_group_profile: bridge1 state: present - check_mode: true - register: add_floating_cm - - name: Create a floating svi in normal mode - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi path of type physical + cisco.aci.aci_l3out_floating_svi_path: &floating_svi_path <<: *floating_svi + domain_type: physical + domain: physical_dom + floating_ip: 25.45.67.90/24 state: present - register: add_floating_nm - - name: Create a floating svi again - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi path of type virtual + cisco.aci.aci_l3out_floating_svi_path: &floating_svi_path2 <<: *floating_svi + domain_type: vmware + domain: virtual + floating_ip: 25.45.67.90/24 state: present - register: add_floating_again - - name: Update floating svi - cisco.aci.aci_l3out_floating_svi: - <<: *floating_svi - external_bridge_group_profile: bridge2 + - name: Create a floating svi path secondary_ip (virtual) + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path2 + secondary_ip: 30.45.67.90/24 state: present - register: update_floating + register: add_ip_cm - - name: Delete an external_bridge_group_profile - cisco.aci.aci_l3out_floating_svi: - <<: *floating_svi - external_bridge_group_profile: "" + - name: Create a floating svi path secondary_ip in check mode + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 27.45.67.90/24 state: present - register: remove_bridge + check_mode: true + register: add_ip_cm - - name: Create another floating svi - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present - pod_id: 1 - node_id: 202 - encap: vlan-1 - address: 24.45.67.90/24 - external_bridge_group_profile: bridge2 + - name: Create a floating svi path secondary_ip in normal mode + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 27.45.67.90/24 + state: present + register: add_ip_nm + + - name: Create a floating svi path secondary_ip again + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 27.45.67.90/24 + state: present + register: add_ip_again + + - name: Create another floating svi path secondary_ip + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 28.45.67.90/24 state: present - register: add_floating2 + register: add_another_ip - - name: Verify nm_add_intf + - name: Verify present ops assert: that: - - cm_add_intf is changed - - nm_add_intf is changed - - cm_add_intf.previous == nm_add_intf.previous == [] - - cm_add_intf.sent.l3extLIfP.attributes.name == nm_add_intf.sent.l3extLIfP.attributes.name == 'INTFS' - - cm_add_intf.sent.l3extLIfP.attributes.descr == nm_add_intf.sent.l3extLIfP.attributes.descr == 'test' - - nm_add_intf.current.0.l3extLIfP.attributes.annotation == 'orchestrator:ansible' - - - name: Query a floating svi - cisco.aci.aci_l3out_floating_svi: - <<: *floating_svi + - add_ip_cm is changed + - add_ip_nm is changed + - add_ip_again is not changed + - add_another_ip is changed + - add_ip_nm.current.0.l3extIp.attributes.addr == "27.45.67.90/24" + - add_another_ip.current.0.l3extIp.attributes.addr == "28.45.67.90/24" + + - name: Query a floating svi path secondary_ip + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 27.45.67.90/24 state: query - register: query_floating + register: query_ip - - name: Query all floating svis - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present + - name: Query all ips + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path state: query - register: query_all_floating + register: query_all - - name: Remove a floating svi - cisco.aci.aci_l3out_logical_interface_profile: - <<: *floating_svi + - name: Verify query ops + assert: + that: + - query_ip is not changed + - query_all is not changed + - query_ip.current.0.l3extIp.attributes.addr == "27.45.67.90/24" + - query_all.current.0.l3extRsDynPathAtt.children | length == 2 + + - name: Delete a floating svi path secondary_ip + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: + <<: *floating_svi_path + secondary_ip: 27.45.67.90/24 + state: absent + register: delete_ip + + - name: Verify delete ops + assert: + that: + - delete_ip is changed + - delete_ip.current == [] + +# Clean up environment + - name: Remove test tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test state: absent - register: remove_floating + \ No newline at end of file diff --git a/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml index cee435793..57a270997 100644 --- a/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml @@ -51,7 +51,7 @@ domain: l3outintftest route_control: export - - name: Crete node profile + - name: Create node profile cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outintftest @@ -62,7 +62,7 @@ <<: *np_present interface_profile: Floating - - name: Create a floating svi in check mode + - name: Create a floating svi cisco.aci.aci_l3out_floating_svi: &floating_svi <<: *intf_present pod_id: 1 @@ -71,70 +71,84 @@ address: 23.45.67.90/24 external_bridge_group_profile: bridge1 state: present - check_mode: true register: add_floating_cm - - name: Create a floating svi in normal mode - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi secondary_ip in check mode + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi + secondary_ip: 25.45.67.90/24 state: present - register: add_floating_nm + check_mode: true + register: add_ip_cm - - name: Create a floating svi again - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi secondary_ip in normal mode + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi + secondary_ip: 25.45.67.90/24 state: present - register: add_floating_again + register: add_ip_nm - - name: Update floating svi - cisco.aci.aci_l3out_floating_svi: + - name: Create a floating svi secondary_ip again + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi - external_bridge_group_profile: bridge2 + secondary_ip: 25.45.67.90/24 state: present - register: update_floating + register: add_ip_again - - name: Delete an external_bridge_group_profile - cisco.aci.aci_l3out_floating_svi: + - name: Create another floating svi secondary_ip + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi - external_bridge_group_profile: "" + secondary_ip: 26.45.67.90/24 state: present - register: remove_bridge + register: add_another_ip - - name: Create another floating svi - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present - pod_id: 1 - node_id: 202 - encap: vlan-1 - address: 24.45.67.90/24 - external_bridge_group_profile: bridge2 - state: present - register: add_floating2 - - - name: Verify nm_add_intf + - name: Verify present ops assert: that: - - cm_add_intf is changed - - nm_add_intf is changed - - cm_add_intf.previous == nm_add_intf.previous == [] - - cm_add_intf.sent.l3extLIfP.attributes.name == nm_add_intf.sent.l3extLIfP.attributes.name == 'INTFS' - - cm_add_intf.sent.l3extLIfP.attributes.descr == nm_add_intf.sent.l3extLIfP.attributes.descr == 'test' - - nm_add_intf.current.0.l3extLIfP.attributes.annotation == 'orchestrator:ansible' - - - name: Query a floating svi - cisco.aci.aci_l3out_floating_svi: + - add_ip_cm is changed + - add_ip_nm is changed + - add_ip_again is not changed + - add_another_ip is changed + - add_ip_nm.current.0.l3extIp.attributes.addr == "25.45.67.90/24" + - add_another_ip.current.0.l3extIp.attributes.addr == "26.45.67.90/24" + + - name: Query a floating svi secondary_ip + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi + secondary_ip: 25.45.67.90/24 state: query - register: query_floating + register: query_ip - - name: Query all floating svis - cisco.aci.aci_l3out_floating_svi: - <<: *intf_present + - name: Query all ips + cisco.aci.aci_l3out_floating_svi_secondary_ip: + <<: *floating_svi state: query - register: query_all_floating + register: query_all - - name: Remove a floating svi - cisco.aci.aci_l3out_logical_interface_profile: + - name: Verify query ops + assert: + that: + - query_ip is not changed + - query_all is not changed + - query_ip.current.0.l3extIp.attributes.addr == "25.45.67.90/24" + - query_all.current.0.l3extVirtualLIfP.children | length == 2 + + - name: Delete a floating svi secondary_ip + cisco.aci.aci_l3out_floating_svi_secondary_ip: <<: *floating_svi + secondary_ip: 25.45.67.90/24 state: absent - register: remove_floating + register: delete_ip + + - name: Verify delete ops + assert: + that: + - delete_ip is changed + - delete_ip.current == [] + +# Clean up environment + - name: Remove test tenant + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent \ No newline at end of file