From 617115ad53ddeea1992c7910413c5455f98bccf8 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Wed, 20 Sep 2023 21:36:21 -0400 Subject: [PATCH 01/19] [minor_change] Addition of l3out Floating SVI module and its child modules --- plugins/modules/aci_l3out_floating_svi.py | 431 ++++++++++++++++++ ...ating_svi_external_bridge_group_profile.py | 390 ++++++++++++++++ .../aci_l3out_floating_svi_secondary_ip.py | 383 ++++++++++++++++ 3 files changed, 1204 insertions(+) create mode 100644 plugins/modules/aci_l3out_floating_svi.py create mode 100644 plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py create mode 100644 plugins/modules/aci_l3out_floating_svi_secondary_ip.py diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py new file mode 100644 index 000000000..9aa6eb8ea --- /dev/null +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -0,0 +1,431 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} + +DOCUMENTATION = r""" +--- +module: aci_l3out_interface_floating_svi +short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +description: +- Manage L3Out interfaces on Cisco ACI fabrics. +options: + tenant: + description: + - Name of an existing tenant. + type: str + aliases: [ tenant_name ] + required: true + l3out: + description: + - Name of an existing L3Out. + type: str + aliases: [ l3out_name ] + required: true + node_profile: + description: + - Name of the node profile. + type: str + aliases: [ node_profile_name, logical_node ] + required: true + interface_profile: + description: + - Name of the interface profile. + type: str + aliases: [ interface_profile_name, logical_interface ] + required: true + pod_id: + description: + - Pod to build the interface on. + type: str + node_id: + description: + - Node to build the interface on for Port-channels and single ports. + - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. + type: str + path_ep: + description: + - Path to interface + - Interface Policy Group name for Port-channels and vPCs + - Port number for single ports (e.g. "eth1/12") + type: str + encap: + description: + - encapsulation on the interface (e.g. "vlan-500") + type: str + address: + description: + - IP address. + type: str + aliases: [ addr, ip_address] + mtu: + description: + - Interface MTU. + type: str + ipv6_dad: + description: + - IPv6 DAD feature. + type: str + choices: [ enabled, disabled] + interface_type: + description: + - Type of interface to build. + type: str + choices: [ l3-port, sub-interface, ext-svi ] + mode: + description: + - Interface mode, only used if instance_type is ext-svi + type: str + choices: [ regular, native, untagged ] + state: + description: + - Use C(present) or C(absent) for adding or removing. + - Use C(query) for listing an object or multiple objects. + type: str + choices: [ absent, present, query ] + default: present + auto_state: + description: + - SVI auto state. + type: str + choices: [ enabled, disabled ] +extends_documentation_fragment: +- cisco.aci.aci +- cisco.aci.annotation + +seealso: +- module: aci_l3out +- module: aci_l3out_logical_node_profile +- 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/ +author: +- Tim Cragg (@timcragg) +- Marcel Zehnder (@maercu) +""" + +EXAMPLES = r""" +- name: Add a new routed interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + interface_type: l3-port + address: 192.168.10.1/27 + state: present + delegate_to: localhost + +- name: Add a new SVI vPC + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: my_vpc_ipg + interface_type: ext-svi + encap: vlan-800 + mode: regular + state: present + delegate_to: localhost + +- name: Delete an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: absent + delegate_to: localhost + +- name: Query an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: query + delegate_to: localhost + register: query_result + +""" + +RETURN = r""" +current: + description: The existing configuration from the APIC after the module has finished + returned: success + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +error: + description: The error information as returned from the APIC + returned: failure + type: dict + sample: + { + "code": "122", + "text": "unknown managed object class foo" + } +raw: + description: The raw output returned by the APIC REST API (xml or json) + returned: parse error + type: str + sample: '' +sent: + description: The actual/minimal configuration pushed to the APIC + returned: info + type: list + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment" + } + } + } +previous: + description: The original configuration from the APIC before the module has started + returned: info + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +proposed: + description: The assembled configuration from the user-provided parameters + returned: info + type: dict + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "name": "production" + } + } + } +filter_string: + description: The filter string used for the request + returned: failure or debug + type: str + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: str + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: str + sample: OK (30 bytes) +status: + description: The HTTP status from the APIC + returned: failure or debug + type: int + sample: 200 +url: + description: The HTTP url used for the request to the APIC + returned: failure or debug + type: str + sample: https://10.11.12.13/api/mo/uni/tn-production.json +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update( + tenant=dict(type="str", aliases=["tenant_name"], required=True), + l3out=dict(type="str", aliases=["l3out_name"], required=True), + node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True), + interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + pod_id=dict(type="str"), + node_id=dict(type="str"), + address=dict(type="str", aliases=["addr", "ip_address"]), + link_local_address=dict(type="str"), + mac_address=dict(type="str"), + mtu=dict(type="str"), + ipv6_dad=dict(type="str", choices=["enabled", "disabled"]), + mode=dict(type="str", choices=["regular", "native", "untagged"]), + 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", + choices=[ + "AF11", + "AF12", + "AF13", + "AF21", + "AF22", + "AF23", + "AF31", + "AF32", + "AF33", + "AF41", + "AF42", + "AF43", + "CS0", + "CS1", + "CS2", + "CS3", + "CS4", + "CS5", + "CS6", + "CS7", + "EF", + "VA", + "unspecified", + ], + aliases=["target_dscp"], + ), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[["state", "present", ["pod_id", "node_id", "encap"]], ["state", "absent", ["pod_id", "node_id"]]], + ) + + tenant = module.params.get("tenant") + l3out = module.params.get("l3out") + node_profile = module.params.get("node_profile") + interface_profile = module.params.get("interface_profile") + state = module.params.get("state") + pod_id = module.params.get("pod_id") + node_id = module.params.get("node_id") + address = module.params.get("address") + mtu = module.params.get("mtu") + ipv6_dad = module.params.get("ipv6_dad") + mode = module.params.get("mode") + encap = module.params.get("encap") + encap_scope = "ctx" if module.params.get("encap") is "vrf" else module.params.get("encap") + auto_state = module.params.get("auto_state") + #external_bridge_group_profile = module.params.get("xternal_bridge_group_profile") + + aci = ACIModule(module) + + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + + # child_configs = [] + + # if external_bridge_group_profile is not None: + # child_configs.append( + # dict( + # infraRsAttEntP=dict( + # attributes=dict( + # tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), + # ), + # ), + # ) + # ) + + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-{0}".format(tenant), + module_object=tenant, + target_filter={"name": tenant}, + ), + subclass_1=dict( + aci_class="l3extOut", + aci_rn="out-{0}".format(l3out), + module_object=l3out, + target_filter={"name": l3out}, + ), + subclass_2=dict( + aci_class="l3extLNodeP", + aci_rn="lnodep-{0}".format(node_profile), + module_object=node_profile, + target_filter={"name": node_profile}, + ), + subclass_3=dict( + aci_class="l3extLIfP", + aci_rn="lifp-{0}".format(interface_profile), + module_object=interface_profile, + target_filter={"name": interface_profile}, + ), + subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + ) + + aci.get_existing() + + if state == "present": + aci.payload( + aci_class="l3extVirtualLIfP", + class_config=dict(tDn=node_dn, addr=address, ipv6Dad=ipv6_dad, mtu=mtu, ifInstT="ext-svi", mode=mode, encap=encap, encapScope=encap_scope, autostate=auto_state), + ) + + aci.get_diff(aci_class="l3extVirtualLIfP") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py b/plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py new file mode 100644 index 000000000..e35558358 --- /dev/null +++ b/plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py @@ -0,0 +1,390 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} + +DOCUMENTATION = r""" +--- +module: aci_l3out_interface_floating_svi +short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +description: +- Manage L3Out interfaces on Cisco ACI fabrics. +options: + tenant: + description: + - Name of an existing tenant. + type: str + aliases: [ tenant_name ] + required: true + l3out: + description: + - Name of an existing L3Out. + type: str + aliases: [ l3out_name ] + required: true + node_profile: + description: + - Name of the node profile. + type: str + aliases: [ node_profile_name, logical_node ] + required: true + interface_profile: + description: + - Name of the interface profile. + type: str + aliases: [ interface_profile_name, logical_interface ] + required: true + pod_id: + description: + - Pod to build the interface on. + type: str + node_id: + description: + - Node to build the interface on for Port-channels and single ports. + - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. + type: str + path_ep: + description: + - Path to interface + - Interface Policy Group name for Port-channels and vPCs + - Port number for single ports (e.g. "eth1/12") + type: str + encap: + description: + - encapsulation on the interface (e.g. "vlan-500") + type: str + address: + description: + - IP address. + type: str + aliases: [ addr, ip_address] + mtu: + description: + - Interface MTU. + type: str + ipv6_dad: + description: + - IPv6 DAD feature. + type: str + choices: [ enabled, disabled] + interface_type: + description: + - Type of interface to build. + type: str + choices: [ l3-port, sub-interface, ext-svi ] + mode: + description: + - Interface mode, only used if instance_type is ext-svi + type: str + choices: [ regular, native, untagged ] + state: + description: + - Use C(present) or C(absent) for adding or removing. + - Use C(query) for listing an object or multiple objects. + type: str + choices: [ absent, present, query ] + default: present + auto_state: + description: + - SVI auto state. + type: str + choices: [ enabled, disabled ] +extends_documentation_fragment: +- cisco.aci.aci +- cisco.aci.annotation + +seealso: +- module: aci_l3out +- module: aci_l3out_logical_node_profile +- 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/ +author: +- Tim Cragg (@timcragg) +- Marcel Zehnder (@maercu) +""" + +EXAMPLES = r""" +- name: Add a new routed interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + interface_type: l3-port + address: 192.168.10.1/27 + state: present + delegate_to: localhost + +- name: Add a new SVI vPC + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: my_vpc_ipg + interface_type: ext-svi + encap: vlan-800 + mode: regular + state: present + delegate_to: localhost + +- name: Delete an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: absent + delegate_to: localhost + +- name: Query an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: query + delegate_to: localhost + register: query_result + +""" + +RETURN = r""" +current: + description: The existing configuration from the APIC after the module has finished + returned: success + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +error: + description: The error information as returned from the APIC + returned: failure + type: dict + sample: + { + "code": "122", + "text": "unknown managed object class foo" + } +raw: + description: The raw output returned by the APIC REST API (xml or json) + returned: parse error + type: str + sample: '' +sent: + description: The actual/minimal configuration pushed to the APIC + returned: info + type: list + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment" + } + } + } +previous: + description: The original configuration from the APIC before the module has started + returned: info + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +proposed: + description: The assembled configuration from the user-provided parameters + returned: info + type: dict + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "name": "production" + } + } + } +filter_string: + description: The filter string used for the request + returned: failure or debug + type: str + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: str + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: str + sample: OK (30 bytes) +status: + description: The HTTP status from the APIC + returned: failure or debug + type: int + sample: 200 +url: + description: The HTTP url used for the request to the APIC + returned: failure or debug + type: str + sample: https://10.11.12.13/api/mo/uni/tn-production.json +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update( + tenant=dict(type="str", aliases=["tenant_name"], required=True), + l3out=dict(type="str", aliases=["l3out_name"], required=True), + node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True), + interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + pod_id=dict(type="str"), + node_id=dict(type="str"), + encap=dict(type="str"), + external_bridge_group_profile=dict(type="str"), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[["state", "present", ["pod_id", "node_id", "encap", "external_bridge_group_profile"]], ["state", "absent", ["pod_id", "node_id"]]], + ) + + tenant = module.params.get("tenant") + l3out = module.params.get("l3out") + node_profile = module.params.get("node_profile") + interface_profile = module.params.get("interface_profile") + state = module.params.get("state") + pod_id = module.params.get("pod_id") + node_id = module.params.get("node_id") + encap = module.params.get("encap") + external_bridge_group_profile = module.params.get("external_bridge_group_profile") + + aci = ACIModule(module) + + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-{0}".format(tenant), + module_object=tenant, + target_filter={"name": tenant}, + ), + subclass_1=dict( + aci_class="l3extOut", + aci_rn="out-{0}".format(l3out), + module_object=l3out, + target_filter={"name": l3out}, + ), + subclass_2=dict( + aci_class="l3extLNodeP", + aci_rn="lnodep-{0}".format(node_profile), + module_object=node_profile, + target_filter={"name": node_profile}, + ), + subclass_3=dict( + aci_class="l3extLIfP", + aci_rn="lifp-{0}".format(interface_profile), + module_object=interface_profile, + target_filter={"name": interface_profile}, + ), + subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + subclass_5=dict( + aci_class="l3extBdProfileCont", + aci_rn="bdprofilecont", + #module_object=True, + ), + child_classes=["l3extRsBdProfile"], + ) + + aci.get_existing() + + if state == "present": + child_configs = [] + child_configs.append( + dict( + l3extRsBdProfile=dict( + attributes=dict( + tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), + ), + ), + ) + ) + aci.payload( + aci_class="l3extBdProfileCont", + child_configs=child_configs, + ) + + aci.get_diff(aci_class="l3extBdProfileCont") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py new file mode 100644 index 000000000..8305b9307 --- /dev/null +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -0,0 +1,383 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "community", +} + +DOCUMENTATION = r""" +--- +module: aci_l3out_floating_svi_secondary_ip +short_description: Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip). +description: +- Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip). +options: + tenant: + description: + - Name of an existing tenant. + type: str + aliases: [ tenant_name ] + l3out: + description: + - Name of an existing L3Out. + type: str + aliases: [ l3out_name ] + node_profile: + description: + - Name of the node profile. + type: str + aliases: [ node_profile_name, logical_node ] + interface_profile: + description: + - Name of the interface profile. + type: str + aliases: [ interface_profile_name, logical_interface ] + pod_id: + description: + - Pod to build the interface on. + type: str + node_id: + description: + - Node to build the interface on for Port-channels and single ports. + - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. + type: str + path_ep: + description: + - Path to interface + - Interface Policy Group name for Port-channels and vPCs + - Port number for single ports (e.g. "eth1/12") + type: str + side: + description: + - Provides the side for vPC member interfaces. + type: str + choices: [ A, B ] + address: + description: + - Secondary IP address. + type: str + aliases: [ addr, ip_address] + ipv6_dad: + description: + - IPv6 DAD feature. + type: str + choices: [ enabled, disabled] + state: + description: + - Use C(present) or C(absent) for adding or removing. + - Use C(query) for listing an object or multiple objects. + type: str + choices: [ absent, present, query ] + default: present +extends_documentation_fragment: +- 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 +- 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/ +author: +- Marcel Zehnder (@maercu) +""" + +EXAMPLES = r""" +- name: Add a new secondary IP to a routed interface + cisco.aci.aci_l3out_interface_secondary_ip: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + address: 192.168.10.2/27 + state: present + delegate_to: localhost + +- name: Add a new secondary IP to a vPC member + cisco.aci.aci_l3out_interface_secondary_ip: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: my_vpc_ipg + side: A + address: 192.168.10.2/27 + state: present + delegate_to: localhost + +- name: Delete a secondary IP + cisco.aci.aci_l3out_interface_secondary_ip: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + address: 192.168.10.2/27 + state: absent + delegate_to: localhost + +- name: Query a secondary IP + cisco.aci.aci_l3out_interface_secondary_ip: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + address: 192.168.10.2/27 + state: query + delegate_to: localhost + register: query_result +""" + +RETURN = r""" +current: + description: The existing configuration from the APIC after the module has finished + returned: success + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +error: + description: The error information as returned from the APIC + returned: failure + type: dict + sample: + { + "code": "122", + "text": "unknown managed object class foo" + } +raw: + description: The raw output returned by the APIC REST API (xml or json) + returned: parse error + type: str + sample: '' +sent: + description: The actual/minimal configuration pushed to the APIC + returned: info + type: list + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment" + } + } + } +previous: + description: The original configuration from the APIC before the module has started + returned: info + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +proposed: + description: The assembled configuration from the user-provided parameters + returned: info + type: dict + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "name": "production" + } + } + } +filter_string: + description: The filter string used for the request + returned: failure or debug + type: str + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: str + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: str + sample: OK (30 bytes) +status: + description: The HTTP status from the APIC + returned: failure or debug + type: int + sample: 200 +url: + description: The HTTP url used for the request to the APIC + returned: failure or debug + type: str + sample: https://10.11.12.13/api/mo/uni/tn-production.json +""" + +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec +from ansible.module_utils.basic import AnsibleModule + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update( + tenant=dict(type="str", aliases=["tenant_name"]), + l3out=dict(type="str", aliases=["l3out_name"]), + node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]), + interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + pod_id=dict(type="str"), + node_id=dict(type="str"), + encap=dict(type="str"), + address=dict(type="str", aliases=["addr", "ip_address"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + [ + "state", + "absent", + [ + "tenant", + "l3out", + "node_profile", + "interface_profile", + "pod_id", + "node_id", + ], + ], + [ + "state", + "present", + [ + "tenant", + "l3out", + "node_profile", + "interface_profile", + "pod_id", + "node_id", + ], + ], + ], + ) + + tenant = module.params.get("tenant") + l3out = module.params.get("l3out") + node_profile = module.params.get("node_profile") + 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"), + address = module.params.get("address") + state = module.params.get("state") + + aci = ACIModule(module) + + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-{0}".format(tenant), + module_object=tenant, + target_filter={"name": tenant}, + ), + subclass_1=dict( + aci_class="l3extOut", + aci_rn="out-{0}".format(l3out), + module_object=l3out, + target_filter={"name": l3out}, + ), + subclass_2=dict( + aci_class="l3extLNodeP", + aci_rn="lnodep-{0}".format(node_profile), + module_object=node_profile, + target_filter={"name": node_profile}, + ), + subclass_3=dict( + aci_class="l3extLIfP", + aci_rn="lifp-{0}".format(interface_profile), + module_object=interface_profile, + target_filter={"name": interface_profile}, + ), + subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + subclass_5=dict( + aci_class="l3extIp", + aci_rn="addr-[{0}]".format(address), + module_object=address, + target_filter={"addr": address}, + ), + ) + + aci.get_existing() + + if state == "present": + aci.payload(aci_class="l3extIp", class_config=dict(addr=address, ipv6Dad="enabled")) + aci.get_diff(aci_class="l3extIp") + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() From 1730144b23a0d444fe7ab077d89b28e77888a33c Mon Sep 17 00:00:00 2001 From: Shreyas Date: Mon, 25 Sep 2023 20:58:08 -0400 Subject: [PATCH 02/19] [ignore] Addition of child to a child class in the 'aci_floating_svi' module --- plugins/modules/aci_l3out_floating_svi.py | 77 ++++++++++++++++------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 9aa6eb8ea..e6a9e97d9 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -11,7 +11,7 @@ DOCUMENTATION = r""" --- -module: aci_l3out_interface_floating_svi +module: aci_l3out_floating_svi short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) description: - Manage L3Out interfaces on Cisco ACI fabrics. @@ -310,7 +310,7 @@ def main(): 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"), + external_bridge_group_profile=dict(type="str"), dscp=dict( type="str", choices=[ @@ -345,7 +345,7 @@ def main(): module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_if=[["state", "present", ["pod_id", "node_id", "encap"]], ["state", "absent", ["pod_id", "node_id"]]], + required_if=[["state", "present", ["pod_id", "node_id", "encap", "address"]], ["state", "absent", ["pod_id", "node_id", "encap"]]], ) tenant = module.params.get("tenant") @@ -360,26 +360,13 @@ def main(): ipv6_dad = module.params.get("ipv6_dad") mode = module.params.get("mode") encap = module.params.get("encap") - encap_scope = "ctx" if module.params.get("encap") is "vrf" else module.params.get("encap") + encap_scope = "ctx" if module.params.get("encap_scope") == "vrf" else module.params.get("encap_scope") auto_state = module.params.get("auto_state") - #external_bridge_group_profile = module.params.get("xternal_bridge_group_profile") + external_bridge_group_profile = module.params.get("external_bridge_group_profile") aci = ACIModule(module) - - node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) - - # child_configs = [] - # if external_bridge_group_profile is not None: - # child_configs.append( - # dict( - # infraRsAttEntP=dict( - # attributes=dict( - # tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), - # ), - # ), - # ) - # ) + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) aci.construct_url( root_class=dict( @@ -406,15 +393,63 @@ def main(): module_object=interface_profile, target_filter={"name": interface_profile}, ), - subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + subclass_4=dict( + aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn} + ), + child_classes=["l3extBdProfileCont"], ) aci.get_existing() if state == "present": + child_configs = [] + if external_bridge_group_profile is not None: + existing_external_bridge_group_profile = "" + if isinstance(aci.existing, list) and len(aci.existing) > 0: + for child in aci.existing[0].get("l3extVirtualLIfP", {}).get("children", {}): + if child.get("l3extBdProfileCont"): + existing_external_bridge_group_profile = ( + child.get("l3extBdProfileCont").get("children")[0].get("l3extRsBdProfile").get("attributes").get("tDn").split("bdprofile-")[1] + ) + if external_bridge_group_profile == "": + child_configs.append( + dict( + l3extBdProfileCont=dict( + attributes=dict(status="deleted"), + ), + ) + ) + + if external_bridge_group_profile != "": + status = "" + if existing_external_bridge_group_profile == "": + status = "created" + elif external_bridge_group_profile != existing_external_bridge_group_profile and existing_external_bridge_group_profile != "": + status = "modified" + if status != "": + child_configs.append( + dict( + l3extBdProfileCont=dict( + attributes=dict(status=status), + children=[ + dict( + l3extRsBdProfile=dict( + attributes=dict( + tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), + ), + ) + ) + ], + ) + ) + ) + aci.payload( aci_class="l3extVirtualLIfP", - class_config=dict(tDn=node_dn, addr=address, ipv6Dad=ipv6_dad, mtu=mtu, ifInstT="ext-svi", mode=mode, encap=encap, encapScope=encap_scope, autostate=auto_state), + class_config=dict( + addr=address, ipv6Dad=ipv6_dad, mtu=mtu, ifInstT="ext-svi", mode=mode, encap=encap, encapScope=encap_scope, autostate=auto_state + ), + child_configs=child_configs, ) aci.get_diff(aci_class="l3extVirtualLIfP") From fa75f30d3d9ea83e0a5acc99ffa67a6dbb18732d Mon Sep 17 00:00:00 2001 From: Shreyas Date: Tue, 26 Sep 2023 12:33:14 -0400 Subject: [PATCH 03/19] [ignore] Addition of 'l3out_floating_svi_path_attributes' module --- .../aci_l3out_floating_svi_path_attributes.py | 456 ++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 plugins/modules/aci_l3out_floating_svi_path_attributes.py diff --git a/plugins/modules/aci_l3out_floating_svi_path_attributes.py b/plugins/modules/aci_l3out_floating_svi_path_attributes.py new file mode 100644 index 000000000..9561d9943 --- /dev/null +++ b/plugins/modules/aci_l3out_floating_svi_path_attributes.py @@ -0,0 +1,456 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} + +DOCUMENTATION = r""" +--- +module: aci_l3out_floating_svi +short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +description: +- Manage L3Out interfaces on Cisco ACI fabrics. +options: + tenant: + description: + - Name of an existing tenant. + type: str + aliases: [ tenant_name ] + required: true + l3out: + description: + - Name of an existing L3Out. + type: str + aliases: [ l3out_name ] + required: true + node_profile: + description: + - Name of the node profile. + type: str + aliases: [ node_profile_name, logical_node ] + required: true + interface_profile: + description: + - Name of the interface profile. + type: str + aliases: [ interface_profile_name, logical_interface ] + required: true + pod_id: + description: + - Pod to build the interface on. + type: str + node_id: + description: + - Node to build the interface on for Port-channels and single ports. + - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. + type: str + path_ep: + description: + - Path to interface + - Interface Policy Group name for Port-channels and vPCs + - Port number for single ports (e.g. "eth1/12") + type: str + encap: + description: + - encapsulation on the interface (e.g. "vlan-500") + type: str + address: + description: + - IP address. + type: str + aliases: [ addr, ip_address] + mtu: + description: + - Interface MTU. + type: str + ipv6_dad: + description: + - IPv6 DAD feature. + type: str + choices: [ enabled, disabled] + interface_type: + description: + - Type of interface to build. + type: str + choices: [ l3-port, sub-interface, ext-svi ] + mode: + description: + - Interface mode, only used if instance_type is ext-svi + type: str + choices: [ regular, native, untagged ] + state: + description: + - Use C(present) or C(absent) for adding or removing. + - Use C(query) for listing an object or multiple objects. + type: str + choices: [ absent, present, query ] + default: present + auto_state: + description: + - SVI auto state. + type: str + choices: [ enabled, disabled ] +extends_documentation_fragment: +- cisco.aci.aci +- cisco.aci.annotation + +seealso: +- module: aci_l3out +- module: aci_l3out_logical_node_profile +- 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/ +author: +- Tim Cragg (@timcragg) +- Marcel Zehnder (@maercu) +""" + +EXAMPLES = r""" +- name: Add a new routed interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + interface_type: l3-port + address: 192.168.10.1/27 + state: present + delegate_to: localhost + +- name: Add a new SVI vPC + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201-202 + path_ep: my_vpc_ipg + interface_type: ext-svi + encap: vlan-800 + mode: regular + state: present + delegate_to: localhost + +- name: Delete an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: absent + delegate_to: localhost + +- name: Query an interface + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + path_ep: eth1/12 + state: query + delegate_to: localhost + register: query_result + +""" + +RETURN = r""" +current: + description: The existing configuration from the APIC after the module has finished + returned: success + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +error: + description: The error information as returned from the APIC + returned: failure + type: dict + sample: + { + "code": "122", + "text": "unknown managed object class foo" + } +raw: + description: The raw output returned by the APIC REST API (xml or json) + returned: parse error + type: str + sample: '' +sent: + description: The actual/minimal configuration pushed to the APIC + returned: info + type: list + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment" + } + } + } +previous: + description: The original configuration from the APIC before the module has started + returned: info + type: list + sample: + [ + { + "fvTenant": { + "attributes": { + "descr": "Production", + "dn": "uni/tn-production", + "name": "production", + "nameAlias": "", + "ownerKey": "", + "ownerTag": "" + } + } + } + ] +proposed: + description: The assembled configuration from the user-provided parameters + returned: info + type: dict + sample: + { + "fvTenant": { + "attributes": { + "descr": "Production environment", + "name": "production" + } + } + } +filter_string: + description: The filter string used for the request + returned: failure or debug + type: str + sample: ?rsp-prop-include=config-only +method: + description: The HTTP method used for the request to the APIC + returned: failure or debug + type: str + sample: POST +response: + description: The HTTP response from the APIC + returned: failure or debug + type: str + sample: OK (30 bytes) +status: + description: The HTTP status from the APIC + returned: failure or debug + type: int + sample: 200 +url: + description: The HTTP url used for the request to the APIC + returned: failure or debug + type: str + sample: https://10.11.12.13/api/mo/uni/tn-production.json +""" + + +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update( + tenant=dict(type="str", aliases=["tenant_name"], required=True), + l3out=dict(type="str", aliases=["l3out_name"], required=True), + node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True), + interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + 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", "virtual"], required=True), + domain=dict(type="str", required=True), + enhanced_lag_policy=dict(type="str"), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[["state", "present", ["domain_type", "domain", "floating_ip"]], ["state", "absent", ["domain_type", "domain"]]], + ) + + tenant = module.params.get("tenant") + l3out = module.params.get("l3out") + node_profile = module.params.get("node_profile") + interface_profile = module.params.get("interface_profile") + state = module.params.get("state") + pod_id = module.params.get("pod_id") + 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") + domain_type = module.params.get("domain_type") + domain = module.params.get("domain") + enhanced_lag_policy = module.params.get("enhanced_lag_policy") + + aci = ACIModule(module) + + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + + if domain_type == "physical": + tDn = "uni/phys-{0}".format(domain) + else: + tDn = "uni/vmmp-VMware/dom-{0}".format(domain) + + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-{0}".format(tenant), + module_object=tenant, + target_filter={"name": tenant}, + ), + subclass_1=dict( + aci_class="l3extOut", + aci_rn="out-{0}".format(l3out), + module_object=l3out, + target_filter={"name": l3out}, + ), + subclass_2=dict( + aci_class="l3extLNodeP", + aci_rn="lnodep-{0}".format(node_profile), + module_object=node_profile, + target_filter={"name": node_profile}, + ), + subclass_3=dict( + aci_class="l3extLIfP", + aci_rn="lifp-{0}".format(interface_profile), + module_object=interface_profile, + target_filter={"name": interface_profile}, + ), + subclass_4=dict( + aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn} + ), + subclass_5=dict( + aci_class="l3extRsDynPathAtt", + aci_rn="rsdynPathAtt-[{0}]".format(tDn), + module_object=tDn, + target_filter={"tDn": tDn}, + ), + child_classes=["l3extVirtualLIfPLagPolAtt"] + ) + + aci.get_existing() + + if state == "present": + child_configs = [] + if enhanced_lag_policy is not None and domain_type == "virtual": + existing_enhanced_lag_policy = "" + if isinstance(aci.existing, list) and len(aci.existing) > 0: + for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}): + if child.get("l3extVirtualLIfPLagPolAtt"): + existing_enhanced_lag_policy = ( + child.get("l3extVirtualLIfPLagPolAtt").get("children")[0].get("l3extRsVSwitchEnhancedLagPol").get("attributes").get("tDn").split("enlacplagp-")[1] + ) + if enhanced_lag_policy == "": + child_configs.append( + dict( + l3extVirtualLIfPLagPolAtt=dict( + attributes=dict(status="deleted"), + ), + ) + ) + + if enhanced_lag_policy != "": + status = "" + child=[ + dict( + l3extRsVSwitchEnhancedLagPol=dict( + attributes=dict( + tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy) + ), + ) + ), + ] + if existing_enhanced_lag_policy == "": + status = "created" + elif enhanced_lag_policy != existing_enhanced_lag_policy and existing_enhanced_lag_policy != "": + status = "modified" + child.append( + dict( + l3extRsVSwitchEnhancedLagPol=dict( + attributes=dict( + status="deleted", + tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, existing_enhanced_lag_policy) + ), + ) + ) + ) + if status != "": + child_configs.append( + dict( + l3extVirtualLIfPLagPolAtt=dict( + attributes=dict(status=status), + children=child + ) + ) + ) + + aci.payload( + aci_class="l3extRsDynPathAtt", + class_config=dict( + floatingAddr=floating_ip, forgedTransmit=forged_transmit, macChange=mac_change, promMode=promiscuous_mode, + ), + child_configs=child_configs, + ) + + aci.get_diff(aci_class="l3extRsDynPathAtt") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() From 5eb1f04b90e2222f2895b665aa850d7cbf120ad5 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Tue, 26 Sep 2023 23:07:13 -0400 Subject: [PATCH 04/19] [ignore] Change in payload function of 'aci.py' in module_utils to detect the presence of children of a child --- plugins/module_utils/aci.py | 2 + plugins/modules/aci_l3out_floating_svi.py | 52 +++++++------------ .../aci_l3out_floating_svi_path_attributes.py | 33 +++++------- 3 files changed, 36 insertions(+), 51 deletions(-) diff --git a/plugins/module_utils/aci.py b/plugins/module_utils/aci.py index 9c6e2db2d..f909e928f 100644 --- a/plugins/module_utils/aci.py +++ b/plugins/module_utils/aci.py @@ -1380,6 +1380,8 @@ def payload(self, aci_class, class_config, child_configs=None): else: child[root_key]["attributes"][final_keys] = str(values) has_value = True + if child_copy[root_key].get("children") is not None: + has_value = True if has_value: children.append(child) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index e6a9e97d9..4d71d3384 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -404,45 +404,33 @@ def main(): if state == "present": child_configs = [] if external_bridge_group_profile is not None: - existing_external_bridge_group_profile = "" - if isinstance(aci.existing, list) and len(aci.existing) > 0: + if external_bridge_group_profile == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extVirtualLIfP", {}).get("children", {}): if child.get("l3extBdProfileCont"): - existing_external_bridge_group_profile = ( - child.get("l3extBdProfileCont").get("children")[0].get("l3extRsBdProfile").get("attributes").get("tDn").split("bdprofile-")[1] + child_configs.append( + dict( + l3extBdProfileCont=dict( + attributes=dict(status="deleted"), + ), + ) ) - if external_bridge_group_profile == "": - child_configs.append( + elif external_bridge_group_profile != "": + child_configs.append( + dict( + l3extBdProfileCont=dict( + attributes=dict(), + children=[ dict( - l3extBdProfileCont=dict( - attributes=dict(status="deleted"), - ), - ) - ) - - if external_bridge_group_profile != "": - status = "" - if existing_external_bridge_group_profile == "": - status = "created" - elif external_bridge_group_profile != existing_external_bridge_group_profile and existing_external_bridge_group_profile != "": - status = "modified" - if status != "": - child_configs.append( - dict( - l3extBdProfileCont=dict( - attributes=dict(status=status), - children=[ - dict( - l3extRsBdProfile=dict( - attributes=dict( - tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), - ), - ) + l3extRsBdProfile=dict( + attributes=dict( + tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), + ), ) - ], - ) + ) + ], ) ) + ) aci.payload( aci_class="l3extVirtualLIfP", diff --git a/plugins/modules/aci_l3out_floating_svi_path_attributes.py b/plugins/modules/aci_l3out_floating_svi_path_attributes.py index 9561d9943..8e4bd14a8 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_attributes.py +++ b/plugins/modules/aci_l3out_floating_svi_path_attributes.py @@ -400,20 +400,16 @@ def main(): ) if enhanced_lag_policy != "": - status = "" child=[ - dict( - l3extRsVSwitchEnhancedLagPol=dict( - attributes=dict( - tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy) - ), - ) - ), + dict( + l3extRsVSwitchEnhancedLagPol=dict( + attributes=dict( + tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy) + ), + ) + ), ] - if existing_enhanced_lag_policy == "": - status = "created" - elif enhanced_lag_policy != existing_enhanced_lag_policy and existing_enhanced_lag_policy != "": - status = "modified" + if enhanced_lag_policy != existing_enhanced_lag_policy and existing_enhanced_lag_policy != "": child.append( dict( l3extRsVSwitchEnhancedLagPol=dict( @@ -424,15 +420,14 @@ def main(): ) ) ) - if status != "": - child_configs.append( - dict( - l3extVirtualLIfPLagPolAtt=dict( - attributes=dict(status=status), - children=child - ) + child_configs.append( + dict( + l3extVirtualLIfPLagPolAtt=dict( + attributes=dict(), + children=child ) ) + ) aci.payload( aci_class="l3extRsDynPathAtt", From 28bad78f2c214acf8f98c2544cf1ec2da3c625ce Mon Sep 17 00:00:00 2001 From: Shreyas Date: Wed, 27 Sep 2023 11:50:39 -0400 Subject: [PATCH 05/19] [ignore] Addition of 'aci_l3out_floating_svi_path_attributes' module to add secondary ips --- .../aci_l3out_floating_svi_path_attributes.py | 56 ++++++++--------- ...ating_svi_path_attributes_secondary_ip.py} | 61 ++++++++++--------- .../aci_l3out_floating_svi_secondary_ip.py | 36 +++++------ 3 files changed, 74 insertions(+), 79 deletions(-) rename plugins/modules/{aci_l3out_floating_svi_external_bridge_group_profile.py => aci_l3out_floating_svi_path_attributes_secondary_ip.py} (86%) diff --git a/plugins/modules/aci_l3out_floating_svi_path_attributes.py b/plugins/modules/aci_l3out_floating_svi_path_attributes.py index 8e4bd14a8..51b526b36 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_attributes.py +++ b/plugins/modules/aci_l3out_floating_svi_path_attributes.py @@ -305,7 +305,7 @@ def main(): 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", "virtual"], required=True), + domain_type=dict(type="str", choices=["physical", "vmware"], required=True), domain=dict(type="str", required=True), enhanced_lag_policy=dict(type="str"), ) @@ -331,14 +331,14 @@ def main(): domain_type = module.params.get("domain_type") domain = module.params.get("domain") enhanced_lag_policy = module.params.get("enhanced_lag_policy") - + aci = ACIModule(module) node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) if domain_type == "physical": - tDn = "uni/phys-{0}".format(domain) - else: + tDn = "uni/phys-{0}".format(domain) + elif domain_type == "vmware": tDn = "uni/vmmp-VMware/dom-{0}".format(domain) aci.construct_url( @@ -375,7 +375,7 @@ def main(): module_object=tDn, target_filter={"tDn": tDn}, ), - child_classes=["l3extVirtualLIfPLagPolAtt"] + child_classes=["l3extVirtualLIfPLagPolAtt"], ) aci.get_existing() @@ -388,7 +388,12 @@ def main(): for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}): if child.get("l3extVirtualLIfPLagPolAtt"): existing_enhanced_lag_policy = ( - child.get("l3extVirtualLIfPLagPolAtt").get("children")[0].get("l3extRsVSwitchEnhancedLagPol").get("attributes").get("tDn").split("enlacplagp-")[1] + child.get("l3extVirtualLIfPLagPolAtt") + .get("children")[0] + .get("l3extRsVSwitchEnhancedLagPol") + .get("attributes") + .get("tDn") + .split("enlacplagp-")[1] ) if enhanced_lag_policy == "": child_configs.append( @@ -400,39 +405,30 @@ def main(): ) if enhanced_lag_policy != "": - child=[ - dict( - l3extRsVSwitchEnhancedLagPol=dict( - attributes=dict( - tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy) - ), - ) - ), - ] + child = [ + dict( + l3extRsVSwitchEnhancedLagPol=dict( + attributes=dict(tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, enhanced_lag_policy)), + ) + ), + ] if enhanced_lag_policy != existing_enhanced_lag_policy and existing_enhanced_lag_policy != "": child.append( - dict( - l3extRsVSwitchEnhancedLagPol=dict( - attributes=dict( - status="deleted", - tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, existing_enhanced_lag_policy) - ), - ) + dict( + l3extRsVSwitchEnhancedLagPol=dict( + attributes=dict(status="deleted", tDn="{0}/vswitchpolcont/enlacplagp-{1}".format(tDn, existing_enhanced_lag_policy)), ) - ) - child_configs.append( - dict( - l3extVirtualLIfPLagPolAtt=dict( - attributes=dict(), - children=child ) ) - ) + child_configs.append(dict(l3extVirtualLIfPLagPolAtt=dict(attributes=dict(), children=child))) aci.payload( aci_class="l3extRsDynPathAtt", class_config=dict( - floatingAddr=floating_ip, forgedTransmit=forged_transmit, macChange=mac_change, promMode=promiscuous_mode, + floatingAddr=floating_ip, + forgedTransmit=forged_transmit, + macChange=mac_change, + promMode=promiscuous_mode, ), child_configs=child_configs, ) diff --git a/plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py b/plugins/modules/aci_l3out_floating_svi_path_attributes_secondary_ip.py similarity index 86% rename from plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py rename to plugins/modules/aci_l3out_floating_svi_path_attributes_secondary_ip.py index e35558358..3a07b6df6 100644 --- a/plugins/modules/aci_l3out_floating_svi_external_bridge_group_profile.py +++ b/plugins/modules/aci_l3out_floating_svi_path_attributes_secondary_ip.py @@ -11,7 +11,7 @@ DOCUMENTATION = r""" --- -module: aci_l3out_interface_floating_svi +module: aci_l3out_floating_svi short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) description: - Manage L3Out interfaces on Cisco ACI fabrics. @@ -298,16 +298,19 @@ def main(): node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True), interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - pod_id=dict(type="str"), - node_id=dict(type="str"), - encap=dict(type="str"), - external_bridge_group_profile=dict(type="str"), + 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), + domain_type=dict(type="str", choices=["physical", "vmware"], required=True), + domain=dict(type="str", required=True), + address=dict(type="str", aliases=["addr", "ip_address"]), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_if=[["state", "present", ["pod_id", "node_id", "encap", "external_bridge_group_profile"]], ["state", "absent", ["pod_id", "node_id"]]], + required_if=[["state", "present", ["address"]], ["state", "absent", ["address"]]], ) tenant = module.params.get("tenant") @@ -318,12 +321,19 @@ def main(): pod_id = module.params.get("pod_id") node_id = module.params.get("node_id") encap = module.params.get("encap") - external_bridge_group_profile = module.params.get("external_bridge_group_profile") + domain_type = module.params.get("domain_type") + domain = module.params.get("domain") + address = module.params.get("address") aci = ACIModule(module) - + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + if domain_type == "physical": + tDn = "uni/phys-{0}".format(domain) + elif domain_type == "vmware": + tDn = "uni/vmmp-VMware/dom-{0}".format(domain) + aci.construct_url( root_class=dict( aci_class="fvTenant", @@ -349,34 +359,29 @@ def main(): module_object=interface_profile, target_filter={"name": interface_profile}, ), - subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + subclass_4=dict( + aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn} + ), subclass_5=dict( - aci_class="l3extBdProfileCont", - aci_rn="bdprofilecont", - #module_object=True, + aci_class="l3extRsDynPathAtt", + aci_rn="rsdynPathAtt-[{0}]".format(tDn), + module_object=tDn, + target_filter={"tDn": tDn}, + ), + subclass_6=dict( + aci_class="l3extIp", + aci_rn="addr-[{0}]".format(address), + module_object=address, + target_filter={"addr": address}, ), - child_classes=["l3extRsBdProfile"], ) aci.get_existing() if state == "present": - child_configs = [] - child_configs.append( - dict( - l3extRsBdProfile=dict( - attributes=dict( - tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), - ), - ), - ) - ) - aci.payload( - aci_class="l3extBdProfileCont", - child_configs=child_configs, - ) + aci.payload(aci_class="l3extIp", class_config=dict(addr=address, ipv6Dad="disabled")) - aci.get_diff(aci_class="l3extBdProfileCont") + aci.get_diff(aci_class="l3extIp") aci.post_config() diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index 8305b9307..52110edf1 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -276,14 +276,14 @@ def main(): argument_spec = aci_argument_spec() argument_spec.update(aci_annotation_spec()) argument_spec.update( - tenant=dict(type="str", aliases=["tenant_name"]), - l3out=dict(type="str", aliases=["l3out_name"]), - node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"]), - interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"]), + tenant=dict(type="str", aliases=["tenant_name"], required=True), + l3out=dict(type="str", aliases=["l3out_name"], required=True), + node_profile=dict(type="str", aliases=["node_profile_name", "logical_node"], required=True), + interface_profile=dict(type="str", aliases=["interface_profile_name", "logical_interface"], required=True), state=dict(type="str", default="present", choices=["absent", "present", "query"]), - pod_id=dict(type="str"), - node_id=dict(type="str"), - encap=dict(type="str"), + 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"]), ) @@ -295,24 +295,14 @@ def main(): "state", "absent", [ - "tenant", - "l3out", - "node_profile", - "interface_profile", - "pod_id", - "node_id", + "address", ], ], [ "state", "present", [ - "tenant", - "l3out", - "node_profile", - "interface_profile", - "pod_id", - "node_id", + "address", ], ], ], @@ -324,7 +314,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"),) address = module.params.get("address") state = module.params.get("state") @@ -357,7 +347,9 @@ def main(): module_object=interface_profile, target_filter={"name": interface_profile}, ), - subclass_4=dict(aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[vlan-{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn}), + subclass_4=dict( + aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn} + ), subclass_5=dict( aci_class="l3extIp", aci_rn="addr-[{0}]".format(address), @@ -370,7 +362,9 @@ def main(): if state == "present": aci.payload(aci_class="l3extIp", class_config=dict(addr=address, ipv6Dad="enabled")) + aci.get_diff(aci_class="l3extIp") + aci.post_config() elif state == "absent": From e8bf1ff1fd22ab9db8ed5a5bf2b9d6b3b1301d38 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Thu, 28 Sep 2023 22:55:09 -0400 Subject: [PATCH 06/19] [ignore] Addition of a test file for the module 'l3out_floating_svi' --- plugins/module_utils/aci.py | 1 + plugins/modules/aci_l3out_floating_svi.py | 81 ++++++---- ...utes.py => aci_l3out_floating_svi_path.py} | 29 +--- ...i_l3out_floating_svi_path_secondary_ip.py} | 0 .../targets/aci_l3out_floating_svi/aliases | 2 + .../aci_l3out_floating_svi/tasks/main.yml | 140 ++++++++++++++++++ 6 files changed, 196 insertions(+), 57 deletions(-) rename plugins/modules/{aci_l3out_floating_svi_path_attributes.py => aci_l3out_floating_svi_path.py} (94%) rename plugins/modules/{aci_l3out_floating_svi_path_attributes_secondary_ip.py => aci_l3out_floating_svi_path_secondary_ip.py} (100%) create mode 100644 tests/integration/targets/aci_l3out_floating_svi/aliases create mode 100644 tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml diff --git a/plugins/module_utils/aci.py b/plugins/module_utils/aci.py index f909e928f..da7fec758 100644 --- a/plugins/module_utils/aci.py +++ b/plugins/module_utils/aci.py @@ -1380,6 +1380,7 @@ def payload(self, aci_class, class_config, child_configs=None): else: child[root_key]["attributes"][final_keys] = str(values) has_value = True + # TODO: This needs to be recursive in order to handle attributes and the children of the subsequent children of the child if child_copy[root_key].get("children") is not None: has_value = True if has_value: diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 4d71d3384..67d9310f7 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -47,23 +47,21 @@ node_id: description: - Node to build the interface on for Port-channels and single ports. - - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. type: str - path_ep: + encap: description: - - Path to interface - - Interface Policy Group name for Port-channels and vPCs - - Port number for single ports (e.g. "eth1/12") + - Encapsulation on the interface (e.g. "vlan-500") type: str - encap: + encap_scope: description: - - encapsulation on the interface (e.g. "vlan-500") + - Encapsulation scope. + choices: [ vrf, local ] type: str address: description: - IP address. type: str - aliases: [ addr, ip_address] + aliases: [ addr, ip_address ] mtu: description: - Interface MTU. @@ -73,16 +71,23 @@ - IPv6 DAD feature. type: str choices: [ enabled, disabled] - interface_type: - description: - - Type of interface to build. - type: str - choices: [ l3-port, sub-interface, ext-svi ] mode: description: - Interface mode, only used if instance_type is ext-svi type: str choices: [ regular, native, untagged ] + dscp: + description: + - The target Differentiated Service (DSCP) value. + - The APIC defaults to C(unspecified) when unset during creation. + type: str + choices: [ AF11, AF12, AF13, AF21, AF22, AF23, AF31, AF32, AF33, AF41, AF42, AF43, CS0, CS1, CS2, CS3, CS4, CS5, CS6, CS7, EF, VA, unspecified ] + aliases: [ target_dscp ] + external_bridge_group_profile: + description: + - The external bridge group profile. + - Pass "" as the value to remove an existing external bridge group profile (See Examples). + type: str state: description: - Use C(present) or C(absent) for adding or removing. @@ -102,17 +107,17 @@ seealso: - module: aci_l3out - module: aci_l3out_logical_node_profile +- module: aci_l3out_logical_interface_profile - 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/ author: -- Tim Cragg (@timcragg) -- Marcel Zehnder (@maercu) +- Shreyas Srish (@shrsr) """ EXAMPLES = r""" -- name: Add a new routed interface - cisco.aci.aci_l3out_interface: +- name: Create a Floating SVI + cisco.aci.aci_l3out_floating_svi: host: apic username: admin password: SomeSecretPassword @@ -122,14 +127,14 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - interface_type: l3-port - address: 192.168.10.1/27 + encap: vlan-1 + address: 23.45.67.90/24 + external_bridge_group_profile: bridge1 state: present delegate_to: localhost -- name: Add a new SVI vPC - cisco.aci.aci_l3out_interface: +- name: Remove an external bridge group profile + cisco.aci.aci_l3out_floating_svi: host: apic username: admin password: SomeSecretPassword @@ -138,16 +143,15 @@ node_profile: my_node_profile interface_profile: my_interface_profile pod_id: 1 - node_id: 201-202 - path_ep: my_vpc_ipg - interface_type: ext-svi - encap: vlan-800 - mode: regular + node_id: 201 + encap: vlan-1 + address: 23.45.67.90/24 + external_bridge_group_profile: "" state: present delegate_to: localhost -- name: Delete an interface - cisco.aci.aci_l3out_interface: +- name: Remove a Floating SVI + cisco.aci.aci_l3out_floating_svi: host: apic username: admin password: SomeSecretPassword @@ -157,11 +161,11 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 + encap: vlan-1 state: absent delegate_to: localhost -- name: Query an interface +- name: Query a a Floating SVI cisco.aci.aci_l3out_interface: host: apic username: admin @@ -172,11 +176,23 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 + encap: vlan-1 state: query delegate_to: localhost register: query_result +- name: Query all the Floating SVIs under an interface profile + cisco.aci.aci_l3out_interface: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + state: query + delegate_to: localhost + register: query_results """ RETURN = r""" @@ -424,6 +440,7 @@ def main(): l3extRsBdProfile=dict( attributes=dict( tDn="uni/tn-{0}/bdprofile-{1}".format(tenant, external_bridge_group_profile), + ), ) ) diff --git a/plugins/modules/aci_l3out_floating_svi_path_attributes.py b/plugins/modules/aci_l3out_floating_svi_path.py similarity index 94% rename from plugins/modules/aci_l3out_floating_svi_path_attributes.py rename to plugins/modules/aci_l3out_floating_svi_path.py index 51b526b36..3b14b5be2 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_attributes.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -12,9 +12,9 @@ DOCUMENTATION = r""" --- module: aci_l3out_floating_svi -short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +short_description: Manage Layer 3 Outside (L3Out) Floating SVI (l3ext:VirtualLIfP) description: -- Manage L3Out interfaces on Cisco ACI fabrics. +- Manage L3Out Floating SVI on Cisco ACI fabrics. options: tenant: description: @@ -47,37 +47,16 @@ node_id: description: - Node to build the interface on for Port-channels and single ports. - - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. - type: str - path_ep: - description: - - Path to interface - - Interface Policy Group name for Port-channels and vPCs - - Port number for single ports (e.g. "eth1/12") type: str encap: description: - encapsulation on the interface (e.g. "vlan-500") type: str - address: + floating_ip: description: - IP address. type: str - aliases: [ addr, ip_address] - mtu: - description: - - Interface MTU. - type: str - ipv6_dad: - description: - - IPv6 DAD feature. - type: str - choices: [ enabled, disabled] - interface_type: - description: - - Type of interface to build. - type: str - choices: [ l3-port, sub-interface, ext-svi ] + aliases: [ floating_address ] mode: description: - Interface mode, only used if instance_type is ext-svi diff --git a/plugins/modules/aci_l3out_floating_svi_path_attributes_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py similarity index 100% rename from plugins/modules/aci_l3out_floating_svi_path_attributes_secondary_ip.py rename to plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py diff --git a/tests/integration/targets/aci_l3out_floating_svi/aliases b/tests/integration/targets/aci_l3out_floating_svi/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml new file mode 100644 index 000000000..8ee0bc327 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml @@ -0,0 +1,140 @@ +# Author: Marcel Zehnder (@maercu) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + - name: Add interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: Floating + + - name: Create a floating svi in check mode + 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: + <<: *floating_svi + state: present + register: add_floating_nm + + - name: Create a floating svi again + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + state: present + register: add_floating_again + + - name: Update floating svi + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: bridge2 + state: present + register: update_floating + + - name: Delete an external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: "" + state: present + register: remove_bridge + + - 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 + 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 + state: query + register: query_floating + + - name: Query all floating svis + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + state: query + register: query_all_floating + + - name: Remove a floating svi + cisco.aci.aci_l3out_logical_interface_profile: + <<: *floating_svi + state: absent + register: remove_floating From 05acd436ad9a0991afe497b7b1dc7669c81e0cea Mon Sep 17 00:00:00 2001 From: Shreyas Date: Sat, 30 Sep 2023 10:06:57 -0400 Subject: [PATCH 07/19] [ignore] Addition of test files for 'floating_svi' modules and its counterparts --- plugins/modules/aci_l3out_floating_svi.py | 25 +-- .../modules/aci_l3out_floating_svi_path.py | 112 ++++++++----- ...ci_l3out_floating_svi_path_secondary_ip.py | 149 +++++++++--------- .../aci_l3out_floating_svi_secondary_ip.py | 90 +++++------ tests/integration/inventory.networking | 10 +- .../aci_l3out_floating_svi/tasks/main.yml | 81 ++++++++-- .../aci_l3out_floating_svi_path/aliases | 2 + .../tasks/main.yml | 140 ++++++++++++++++ .../aliases | 2 + .../tasks/main.yml | 140 ++++++++++++++++ .../aliases | 2 + .../tasks/main.yml | 140 ++++++++++++++++ 12 files changed, 703 insertions(+), 190 deletions(-) create mode 100644 tests/integration/targets/aci_l3out_floating_svi_path/aliases create mode 100644 tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml create mode 100644 tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/aliases create mode 100644 tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml create mode 100644 tests/integration/targets/aci_l3out_floating_svi_secondary_ip/aliases create mode 100644 tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 67d9310f7..97d5c4fa2 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -165,8 +165,8 @@ state: absent delegate_to: localhost -- name: Query a a Floating SVI - cisco.aci.aci_l3out_interface: +- name: Query a Floating SVI + cisco.aci.aci_l3out_floating_svi: host: apic username: admin password: SomeSecretPassword @@ -182,7 +182,7 @@ register: query_result - name: Query all the Floating SVIs under an interface profile - cisco.aci.aci_l3out_interface: + cisco.aci.aci_l3out_floating_svi: host: apic username: admin password: SomeSecretPassword @@ -382,7 +382,9 @@ def main(): aci = ACIModule(module) - node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + node_dn = None + if pod_id and node_id: + node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) aci.construct_url( root_class=dict( @@ -421,15 +423,14 @@ def main(): child_configs = [] if external_bridge_group_profile is not None: if external_bridge_group_profile == "" and isinstance(aci.existing, list) and len(aci.existing) > 0: - for child in aci.existing[0].get("l3extVirtualLIfP", {}).get("children", {}): - if child.get("l3extBdProfileCont"): - child_configs.append( - dict( - l3extBdProfileCont=dict( - attributes=dict(status="deleted"), - ), - ) + if aci.existing[0].get("l3extVirtualLIfP", {}).get("children") is not None: + child_configs.append( + dict( + l3extBdProfileCont=dict( + attributes=dict(status="deleted"), + ), ) + ) elif external_bridge_group_profile != "": child_configs.append( dict( diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index 3b14b5be2..1a628043d 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -11,10 +11,10 @@ DOCUMENTATION = r""" --- -module: aci_l3out_floating_svi -short_description: Manage Layer 3 Outside (L3Out) Floating SVI (l3ext:VirtualLIfP) +module: aci_l3out_floating_svi_path +short_description: Manage Layer 3 Outside (L3Out) Floating SVI Path Attributes(l3ext:RsDynPathAtt) description: -- Manage L3Out Floating SVI on Cisco ACI fabrics. +- Manages L3Out Floating SVI path attributes on Cisco ACI fabrics. options: tenant: description: @@ -48,20 +48,45 @@ description: - Node to build the interface on for Port-channels and single ports. type: str - encap: + domain: description: - - encapsulation on the interface (e.g. "vlan-500") + - 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. + type: str + choices: [ physical, vmware ] + access_encap: + description: + - The port encapsulation. type: str floating_ip: description: - - IP address. + - The floating IP address. type: str aliases: [ floating_address ] - mode: + forged_transmit: + description: + - This option allows virtual machines to send frames with a mac address. + type: str + choices: [ enable, disable ] + mac_change: description: - - Interface mode, only used if instance_type is ext-svi + - The status of the mac address change support for port groups in an external VMM controller. + type: str + choices: [ enable, disable ] + promiscuous_mode: + description: + - The status of promiscuous mode for port groups in an external VMM controller. + type: str + choices: [ enable, disable ] + enhanced_lag_policy: + description: + - The enhanced lag policy of the path. + - Pass "" as the value to remove an existing enhanced lag policy (See Examples). type: str - choices: [ regular, native, untagged ] state: description: - Use C(present) or C(absent) for adding or removing. @@ -69,29 +94,22 @@ type: str choices: [ absent, present, query ] default: present - auto_state: - description: - - SVI auto state. - type: str - choices: [ enabled, disabled ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation seealso: -- module: aci_l3out -- module: aci_l3out_logical_node_profile +- 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/ author: -- Tim Cragg (@timcragg) -- Marcel Zehnder (@maercu) +- Shreyas Srish (@shrsr) """ EXAMPLES = r""" -- name: Add a new routed interface - cisco.aci.aci_l3out_interface: +- name: Create a Floating SVI path attribute + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -101,14 +119,16 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - interface_type: l3-port - address: 192.168.10.1/27 + encap: vlan-1 + floating_ip: 23.45.67.90/24 + domain_type: virtual + domain: anstest + enhanced_lag_policy: enhanced state: present delegate_to: localhost -- name: Add a new SVI vPC - cisco.aci.aci_l3out_interface: +- name: Remove enhanced lag policy from the path + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -117,16 +137,17 @@ node_profile: my_node_profile interface_profile: my_interface_profile pod_id: 1 - node_id: 201-202 - path_ep: my_vpc_ipg - interface_type: ext-svi - encap: vlan-800 - mode: regular + node_id: 201 + encap: vlan-1 + floating_ip: 23.45.67.90/24 + domain_type: virtual + domain: anstest + enhanced_lag_policy: "" state: present delegate_to: localhost -- name: Delete an interface - cisco.aci.aci_l3out_interface: +- name: Remove a Floating SVI path attribute + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -136,12 +157,14 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 + encap: vlan-1 + domain_type: virtual + domain: anstest state: absent delegate_to: localhost -- name: Query an interface - cisco.aci.aci_l3out_interface: +- name: Query a Floating SVI path attribute + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -151,11 +174,28 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 + encap: vlan-1 + domain_type: virtual + domain: anstest state: query delegate_to: localhost register: query_result +- name: Query all the Floating SVI path attributes + cisco.aci.aci_l3out_floating_svi_path: + host: apic + username: admin + password: SomeSecretPassword + tenant: my_tenant + l3out: my_l3out + node_profile: my_node_profile + interface_profile: my_interface_profile + pod_id: 1 + node_id: 201 + encap: vlan-1 + state: query + delegate_to: localhost + register: query_results """ RETURN = r""" 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 3a07b6df6..2f84ae2be 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -7,14 +7,18 @@ __metaclass__ = type -ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} +ANSIBLE_METADATA = { + "metadata_version": "1.1", + "status": ["preview"], + "supported_by": "community", +} DOCUMENTATION = r""" --- -module: aci_l3out_floating_svi -short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +module: aci_l3out_floating_svi_path_secondary_ip +short_description: Manages Layer 3 Outside (L3Out) Floating SVI Path Attribute's Secondary IP addresses(l3ext:Ip) description: -- Manage L3Out interfaces on Cisco ACI fabrics. +- Manages L3Out Floating SVI path attribute's secondary IP addresses on Cisco ACI fabrics. options: tenant: description: @@ -47,42 +51,22 @@ node_id: description: - Node to build the interface on for Port-channels and single ports. - - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. type: str - path_ep: + domain: description: - - Path to interface - - Interface Policy Group name for Port-channels and vPCs - - Port number for single ports (e.g. "eth1/12") + - This option allows virtual machines to send frames with a mac address. type: str - encap: + choices: [ enable, disable ] + domain_type: description: - - encapsulation on the interface (e.g. "vlan-500") + - The domain type of the path. type: str - address: + choices: [ physical, vmware ] + secondary_ip: description: - - IP address. + - The secondary floating IP address. type: str - aliases: [ addr, ip_address] - mtu: - description: - - Interface MTU. - type: str - ipv6_dad: - description: - - IPv6 DAD feature. - type: str - choices: [ enabled, disabled] - interface_type: - description: - - Type of interface to build. - type: str - choices: [ l3-port, sub-interface, ext-svi ] - mode: - description: - - Interface mode, only used if instance_type is ext-svi - type: str - choices: [ regular, native, untagged ] + aliases: [ secondary_floating_address ] state: description: - Use C(present) or C(absent) for adding or removing. @@ -90,29 +74,27 @@ type: str choices: [ absent, present, query ] default: present - auto_state: - description: - - SVI auto state. - type: str - choices: [ enabled, disabled ] extends_documentation_fragment: - 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 - 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/ author: -- Tim Cragg (@timcragg) -- Marcel Zehnder (@maercu) +- Shreyas Srish (@shrsr) """ EXAMPLES = r""" -- name: Add a new routed interface - cisco.aci.aci_l3out_interface: +- name: Create a Floating SVI path attribute secondary IP + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -122,14 +104,15 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - interface_type: l3-port - address: 192.168.10.1/27 + encap: vlan-1 + secondary_ip: 23.45.67.90/24 + domain_type: virtual + domain: anstest state: present delegate_to: localhost -- name: Add a new SVI vPC - cisco.aci.aci_l3out_interface: +- name: Remove a Floating SVI path attribute secondary IP + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -138,16 +121,16 @@ node_profile: my_node_profile interface_profile: my_interface_profile pod_id: 1 - node_id: 201-202 - path_ep: my_vpc_ipg - interface_type: ext-svi - encap: vlan-800 - mode: regular - state: present + node_id: 201 + encap: vlan-1 + secondary_ip: 23.45.67.90/24 + domain_type: virtual + domain: anstest + state: absent delegate_to: localhost -- name: Delete an interface - cisco.aci.aci_l3out_interface: +- name: Query a Floating SVI path attribute secondary IP + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -157,12 +140,16 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - state: absent + encap: vlan-1 + domain_type: virtual + domain: anstest + secondary_ip: 23.45.67.90/24 + state: query delegate_to: localhost + register: query_result -- name: Query an interface - cisco.aci.aci_l3out_interface: +- name: Query all the secondary IPs under a Floating SVI path attribute + cisco.aci.aci_l3out_floating_svi_path: host: apic username: admin password: SomeSecretPassword @@ -172,11 +159,12 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 + encap: vlan-1 + domain_type: virtual + domain: anstest state: query delegate_to: localhost - register: query_result - + register: query_results """ RETURN = r""" @@ -284,9 +272,8 @@ sample: https://10.11.12.13/api/mo/uni/tn-production.json """ - -from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec +from ansible.module_utils.basic import AnsibleModule def main(): @@ -301,29 +288,43 @@ 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), domain_type=dict(type="str", choices=["physical", "vmware"], required=True), domain=dict(type="str", required=True), - address=dict(type="str", aliases=["addr", "ip_address"]), + secondary_ip=dict(type="str", aliases=["secondary_floating_address"]), ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_if=[["state", "present", ["address"]], ["state", "absent", ["address"]]], + required_if=[ + [ + "state", + "absent", + [ + "secondary_ip", + ], + ], + [ + "state", + "present", + [ + "secondary_ip", + ], + ], + ], ) tenant = module.params.get("tenant") l3out = module.params.get("l3out") node_profile = module.params.get("node_profile") interface_profile = module.params.get("interface_profile") - state = module.params.get("state") 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") - address = module.params.get("address") + state = module.params.get("state") aci = ACIModule(module) @@ -370,16 +371,16 @@ def main(): ), subclass_6=dict( aci_class="l3extIp", - aci_rn="addr-[{0}]".format(address), - module_object=address, - target_filter={"addr": address}, + aci_rn="addr-[{0}]".format(secondary_ip), + module_object=secondary_ip, + target_filter={"addr": secondary_ip}, ), ) aci.get_existing() if state == "present": - aci.payload(aci_class="l3extIp", class_config=dict(addr=address, ipv6Dad="disabled")) + aci.payload(aci_class="l3extIp", class_config=dict(addr=secondary_ip, ipv6Dad="disabled")) aci.get_diff(aci_class="l3extIp") diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index 52110edf1..c5fee236d 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -16,30 +16,34 @@ DOCUMENTATION = r""" --- module: aci_l3out_floating_svi_secondary_ip -short_description: Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip). +short_description: Manages Layer 3 Outside (L3Out) Floating SVI Secondary IP addresses(l3ext:Ip) description: -- Manage Layer 3 Outside (L3Out) interface secondary IP addresses (l3ext:Ip). +- Manages L3Out Floating SVI secondary IP addresses on Cisco ACI fabrics. options: tenant: description: - Name of an existing tenant. type: str aliases: [ tenant_name ] + required: true l3out: description: - Name of an existing L3Out. type: str aliases: [ l3out_name ] + required: true node_profile: description: - Name of the node profile. type: str aliases: [ node_profile_name, logical_node ] + required: true interface_profile: description: - Name of the interface profile. type: str aliases: [ interface_profile_name, logical_interface ] + required: true pod_id: description: - Pod to build the interface on. @@ -47,29 +51,12 @@ node_id: description: - Node to build the interface on for Port-channels and single ports. - - Hyphen separated pair of nodes (e.g. "201-202") for vPCs. type: str - path_ep: + secondary_ip: description: - - Path to interface - - Interface Policy Group name for Port-channels and vPCs - - Port number for single ports (e.g. "eth1/12") + - The secondary floating IP address. type: str - side: - description: - - Provides the side for vPC member interfaces. - type: str - choices: [ A, B ] - address: - description: - - Secondary IP address. - type: str - aliases: [ addr, ip_address] - ipv6_dad: - description: - - IPv6 DAD feature. - type: str - choices: [ enabled, disabled] + aliases: [ secondary_floating_address ] state: description: - Use C(present) or C(absent) for adding or removing. @@ -92,12 +79,12 @@ description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) link: https://developer.cisco.com/docs/apic-mim-ref/ author: -- Marcel Zehnder (@maercu) +- Shreyas Srish (@shrsr) """ EXAMPLES = r""" -- name: Add a new secondary IP to a routed interface - cisco.aci.aci_l3out_interface_secondary_ip: +- name: Create a Floating SVI secondary IP + cisco.aci.aci_l3out_floating_svi_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -107,13 +94,13 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - address: 192.168.10.2/27 + encap: vlan-1 + secondary_ip: 23.45.67.90/24 state: present delegate_to: localhost -- name: Add a new secondary IP to a vPC member - cisco.aci.aci_l3out_interface_secondary_ip: +- name: Remove a Floating SVI secondary IP + cisco.aci.aci_l3out_floating_svi_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -122,15 +109,14 @@ node_profile: my_node_profile interface_profile: my_interface_profile pod_id: 1 - node_id: 201-202 - path_ep: my_vpc_ipg - side: A - address: 192.168.10.2/27 - state: present + node_id: 201 + encap: vlan-1 + secondary_ip: 23.45.67.90/24 + state: absent delegate_to: localhost -- name: Delete a secondary IP - cisco.aci.aci_l3out_interface_secondary_ip: +- name: Query a Floating SVI secondary IP + cisco.aci.aci_l3out_floating_svi_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -140,13 +126,14 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - address: 192.168.10.2/27 - state: absent + encap: vlan-1 + secondary_ip: 23.45.67.90/24 + state: query delegate_to: localhost + register: query_result -- name: Query a secondary IP - cisco.aci.aci_l3out_interface_secondary_ip: +- name: Query all the secondary IPs under a Floating SVI + cisco.aci.aci_l3out_floating_svi_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -156,11 +143,10 @@ interface_profile: my_interface_profile pod_id: 1 node_id: 201 - path_ep: eth1/12 - address: 192.168.10.2/27 + encap: vlan-1 state: query delegate_to: localhost - register: query_result + register: query_results """ RETURN = r""" @@ -284,7 +270,7 @@ 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"]), ) module = AnsibleModule( @@ -295,14 +281,14 @@ def main(): "state", "absent", [ - "address", + "secondary_ip", ], ], [ "state", "present", [ - "address", + "secondary_ip", ], ], ], @@ -315,7 +301,7 @@ def main(): pod_id = module.params.get("pod_id") node_id = module.params.get("node_id") encap = (module.params.get("encap"),) - address = module.params.get("address") + secondary_ip = module.params.get("secondary_ip") state = module.params.get("state") aci = ACIModule(module) @@ -352,16 +338,16 @@ def main(): ), subclass_5=dict( aci_class="l3extIp", - aci_rn="addr-[{0}]".format(address), - module_object=address, - target_filter={"addr": address}, + aci_rn="addr-[{0}]".format(secondary_ip), + module_object=secondary_ip, + target_filter={"addr": secondary_ip}, ), ) aci.get_existing() if state == "present": - aci.payload(aci_class="l3extIp", class_config=dict(addr=address, ipv6Dad="enabled")) + aci.payload(aci_class="l3extIp", class_config=dict(addr=secondary_ip, ipv6Dad="enabled")) aci.get_diff(aci_class="l3extIp") diff --git a/tests/integration/inventory.networking b/tests/integration/inventory.networking index 357f58758..3ad73a97d 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/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml index 8ee0bc327..2fe14cdb6 100644 --- a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml @@ -1,4 +1,4 @@ -# Author: Marcel Zehnder (@maercu) +# Author: Shreyas Srish (@shrsr) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) # SET VARS @@ -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 @@ -107,19 +107,56 @@ node_id: 202 encap: vlan-1 address: 24.45.67.90/24 - external_bridge_group_profile: bridge2 + external_bridge_group_profile: "" state: present register: add_floating2 - - name: Verify nm_add_intf + - name: Create another floating svi with no external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + pod_id: 1 + node_id: 203 + encap: vlan-1 + address: 25.45.67.90/24 + state: present + register: add_floating3 + + - name: Change floating svi with an attempt to delete external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + pod_id: 1 + node_id: 203 + encap: vlan-1 + address: 25.45.67.90/24 + external_bridge_group_profile: "" + state: present + register: change_floating3 + + - 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' + - add_floating_cm is changed + - add_floating_nm is changed + - add_floating_again is not changed + - update_floating is changed + - remove_bridge is changed + - add_floating2 is changed + - add_floating3 is changed + - change_floating3 is not changed + - add_floating_cm.proposed.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" + - add_floating_cm.proposed.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - add_floating_cm.proposed.l3extVirtualLIfP.attributes.encap == "vlan-1" + - add_floating_cm.proposed.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge1" + - add_floating_nm.current.0.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" + - add_floating_nm.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - add_floating_nm.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" + - add_floating_nm.current.0.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge1" + - update_floating.current.0.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge2" + - remove_bridge.current.0.l3extVirtualLIfP.children is not defined + - add_floating2.current.0.l3extVirtualLIfP.attributes.addr == "24.45.67.90/24" + - add_floating2.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-202]-[vlan-1]" + - add_floating2.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" + - add_floating3.current.0.l3extVirtualLIfP.children is not defined - name: Query a floating svi cisco.aci.aci_l3out_floating_svi: @@ -133,8 +170,30 @@ state: query register: query_all_floating + - name: Verify Query ops + assert: + that: + - query_floating is not changed + - query_all_floating is not changed + - query_floating.current.0.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" + - query_floating.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - query_floating.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" + - query_all_floating.current.0.l3extLIfP.children | length == 3 + - name: Remove a floating svi - cisco.aci.aci_l3out_logical_interface_profile: + cisco.aci.aci_l3out_floating_svi: <<: *floating_svi state: absent register: remove_floating + + - name: Verify remove ops + assert: + that: + - remove_floating is changed + - remove_floating.current == [] + + - name: Clean up environment + cisco.aci.aci_tenant: + <<: *aci_info + tenant: ansible_test + state: absent diff --git a/tests/integration/targets/aci_l3out_floating_svi_path/aliases b/tests/integration/targets/aci_l3out_floating_svi_path/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_path/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..cee435793 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_path/tasks/main.yml @@ -0,0 +1,140 @@ +# Author: Shreyas Srish (@shrsr) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + - name: Add interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: Floating + + - name: Create a floating svi in check mode + 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: + <<: *floating_svi + state: present + register: add_floating_nm + + - name: Create a floating svi again + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + state: present + register: add_floating_again + + - name: Update floating svi + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: bridge2 + state: present + register: update_floating + + - name: Delete an external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: "" + state: present + register: remove_bridge + + - 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 + 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 + state: query + register: query_floating + + - name: Query all floating svis + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + state: query + register: query_all_floating + + - name: Remove a floating svi + cisco.aci.aci_l3out_logical_interface_profile: + <<: *floating_svi + state: absent + register: remove_floating diff --git a/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/aliases b/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..cee435793 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_path_secondary_ip/tasks/main.yml @@ -0,0 +1,140 @@ +# Author: Shreyas Srish (@shrsr) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + - name: Add interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: Floating + + - name: Create a floating svi in check mode + 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: + <<: *floating_svi + state: present + register: add_floating_nm + + - name: Create a floating svi again + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + state: present + register: add_floating_again + + - name: Update floating svi + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: bridge2 + state: present + register: update_floating + + - name: Delete an external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: "" + state: present + register: remove_bridge + + - 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 + 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 + state: query + register: query_floating + + - name: Query all floating svis + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + state: query + register: query_all_floating + + - name: Remove a floating svi + cisco.aci.aci_l3out_logical_interface_profile: + <<: *floating_svi + state: absent + register: remove_floating diff --git a/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/aliases b/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported 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 new file mode 100644 index 000000000..cee435793 --- /dev/null +++ b/tests/integration/targets/aci_l3out_floating_svi_secondary_ip/tasks/main.yml @@ -0,0 +1,140 @@ +# Author: Shreyas Srish (@shrsr) +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +# SET VARS +- name: Set vars + set_fact: + aci_info: &aci_info + host: '{{ aci_hostname }}' + username: '{{ aci_username }}' + password: '{{ aci_password }}' + 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") }}' + +# CLEAN ENVIRONMENT +- name: Remove test tenant before we kickoff + cisco.aci.aci_tenant: &tenant_absent + <<: *aci_info + tenant: ansible_test + state: absent + +- name: Verify Cloud and Non-Cloud Sites in use. + include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites + block: # block specifies execution of tasks within, based on conditions + # SETUP ENVIRONMENT + - name: Create domain + cisco.aci.aci_domain: &domain_present + <<: *aci_info + domain: l3outintftest + domain_type: l3dom + state: present + + - name: Create tenant + cisco.aci.aci_tenant: &tenant_present + <<: *tenant_absent + state: present + + - name: Configure VRF + cisco.aci.aci_vrf: &vrf_present + <<: *tenant_present + vrf: l3outintftest + + - name: Create L3Out + cisco.aci.aci_l3out: + <<: *vrf_present + l3out: l3outintftest + domain: l3outintftest + route_control: export + + - name: Crete node profile + cisco.aci.aci_l3out_logical_node_profile: &np_present + <<: *tenant_present + l3out: l3outintftest + node_profile: NODES + + - name: Add interface profile + cisco.aci.aci_l3out_logical_interface_profile: &intf_present + <<: *np_present + interface_profile: Floating + + - name: Create a floating svi in check mode + 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: + <<: *floating_svi + state: present + register: add_floating_nm + + - name: Create a floating svi again + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + state: present + register: add_floating_again + + - name: Update floating svi + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: bridge2 + state: present + register: update_floating + + - name: Delete an external_bridge_group_profile + cisco.aci.aci_l3out_floating_svi: + <<: *floating_svi + external_bridge_group_profile: "" + state: present + register: remove_bridge + + - 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 + 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 + state: query + register: query_floating + + - name: Query all floating svis + cisco.aci.aci_l3out_floating_svi: + <<: *intf_present + state: query + register: query_all_floating + + - name: Remove a floating svi + cisco.aci.aci_l3out_logical_interface_profile: + <<: *floating_svi + state: absent + register: remove_floating From 79c28245a4724137243ff513b66712ee7af4ca49 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Mon, 2 Oct 2023 16:54:12 -0400 Subject: [PATCH 08/19] [ignore] Addition of sub class 6 function to 'aci.py' of module_utils to accommodate creation of a class deeper in the aci object hierarchy --- plugins/module_utils/aci.py | 87 ++++++- plugins/modules/aci_l3out_floating_svi.py | 23 +- .../modules/aci_l3out_floating_svi_path.py | 49 ++-- ...ci_l3out_floating_svi_path_secondary_ip.py | 40 +++- .../aci_l3out_floating_svi_secondary_ip.py | 22 +- plugins/modules/aci_rest.py | 3 +- tests/integration/inventory.networking | 10 +- .../tasks/main.yml | 219 ++++++++++++++---- .../tasks/main.yml | 138 +++++++---- .../tasks/main.yml | 106 +++++---- 10 files changed, 520 insertions(+), 177 deletions(-) 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 From 2b5ce7f391de9b23a482aab274ca174f653f7f0e Mon Sep 17 00:00:00 2001 From: Shreyas Date: Tue, 3 Oct 2023 17:33:38 -0400 Subject: [PATCH 09/19] [ignore] Modified docs to represent relations between the 'floating_svi' module and its child modules --- plugins/modules/aci_l3out_floating_svi.py | 52 ++++++------------- .../modules/aci_l3out_floating_svi_path.py | 10 +++- ...ci_l3out_floating_svi_path_secondary_ip.py | 21 +++----- .../aci_l3out_floating_svi_secondary_ip.py | 24 ++------- 4 files changed, 34 insertions(+), 73 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 1e95029d3..20e7b679f 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -12,7 +12,7 @@ DOCUMENTATION = r""" --- module: aci_l3out_floating_svi -short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:RsPathL3OutAtt) +short_description: Manage Layer 3 Outside (L3Out) interfaces (l3ext:VirtualLIfP) description: - Manage L3Out interfaces on Cisco ACI fabrics. options: @@ -42,11 +42,11 @@ required: true pod_id: description: - - Pod to build the interface on. + - Pod ID to build the interface on. type: str node_id: description: - - Node to build the interface on for Port-channels and single ports. + - Node ID to build the interface on for Port-channels and single ports. type: str encap: description: @@ -76,12 +76,12 @@ type: str ipv6_dad: description: - - IPv6 DAD feature. + - IPv6 Duplicate Address Detection (DAD) feature. type: str choices: [ enabled, disabled] mode: description: - - Interface mode, only used if instance_type is ext-svi + - The mode option for ext-svi interface. type: str choices: [ regular, native, untagged ] dscp: @@ -112,12 +112,15 @@ - cisco.aci.aci - cisco.aci.annotation +notes: +- The C(l3out), C(logical_node_profile) and C(logical_interface_profile) used must exist before using this module in your playbook. + The M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile) and M(cisco.aci.aci_l3out_logical_interface_profile) modules can be used for this. seealso: - module: aci_l3out - module: aci_l3out_logical_node_profile - module: aci_l3out_logical_interface_profile - name: APIC Management Information Model reference - description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) + description: More information about the internal APIC class B(l3ext:VirtualLIfP) link: https://developer.cisco.com/docs/apic-mim-ref/ author: - Shreyas Srish (@shrsr) @@ -310,7 +313,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 +from ansible_collections.cisco.aci.plugins.module_utils.aci import ACIModule, aci_argument_spec, aci_annotation_spec, aci_contract_dscp_spec def main(): @@ -334,41 +337,16 @@ def main(): encap_scope=dict(type="str", choices=["vrf", "local"]), auto_state=dict(type="str", choices=["enabled", "disabled"]), external_bridge_group_profile=dict(type="str"), - dscp=dict( - type="str", - choices=[ - "AF11", - "AF12", - "AF13", - "AF21", - "AF22", - "AF23", - "AF31", - "AF32", - "AF33", - "AF41", - "AF42", - "AF43", - "CS0", - "CS1", - "CS2", - "CS3", - "CS4", - "CS5", - "CS6", - "CS7", - "EF", - "VA", - "unspecified", - ], - aliases=["target_dscp"], - ), + dscp=aci_contract_dscp_spec(direction="dscp") ) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_if=[["state", "present", ["pod_id", "node_id", "encap", "address"]], ["state", "absent", ["pod_id", "node_id", "encap"]]], + required_if=[ + ["state", "present", ["pod_id", "node_id", "encap", "address"]], + ["state", "absent", ["pod_id", "node_id", "encap"]], + ], ) tenant = module.params.get("tenant") diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index f501664c5..5d102afe7 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -112,10 +112,13 @@ - cisco.aci.aci - cisco.aci.annotation +notes: +- The C(floating_svi) used must exist before using this module in your playbook. + The M(cisco.aci.aci_l3out_floating_svi) module can be used for this. seealso: - module: aci_l3out_floating_svi - name: APIC Management Information Model reference - description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) + description: More information about the internal APIC class B(l3ext:RsDynPathAtt)) link: https://developer.cisco.com/docs/apic-mim-ref/ author: - Shreyas Srish (@shrsr) @@ -348,7 +351,10 @@ def main(): module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, - required_if=[["state", "present", ["domain_type", "domain", "floating_ip"]], ["state", "absent", ["domain_type", "domain"]]], + required_if=[ + ["state", "present", ["domain_type", "domain", "floating_ip"]], + ["state", "absent", ["domain_type", "domain"]], + ], ) tenant = module.params.get("tenant") 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 a46e12cbd..770167a98 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -100,11 +100,14 @@ - cisco.aci.aci - cisco.aci.annotation +notes: +- The C(floating_svi) and C(floating_svi_path) used must exist before using this module in your playbook. + The M(cisco.aci.aci_l3out_floating_svi) and M(cisco.aci.aci_l3out_floating_svi_path) modules can be used for this. seealso: - 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) + description: More information about the internal APIC class B(l3ext:Ip) link: https://developer.cisco.com/docs/apic-mim-ref/ author: - Shreyas Srish (@shrsr) @@ -318,20 +321,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - [ - "state", - "absent", - [ - "secondary_ip", - ], - ], - [ - "state", - "present", - [ - "secondary_ip", - ], - ], + ["state", "absent", ["secondary_ip"]], + ["state", "present", ["secondary_ip"]], ], ) diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index efa010a97..c775449f7 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -85,14 +85,12 @@ - cisco.aci.annotation notes: -- This is a test +- The C(floating_svi) used must exist before using this module in your playbook. + The M(cisco.aci.aci_l3out_floating_svi) module can be used for this. seealso: -- module: aci_l3out -- module: aci_l3out_logical_node_profile -- module: aci_l3out_logical_interface_profile - module: aci_l3out_floating_svi - name: APIC Management Information Model reference - description: More information about the internal APIC class B(l3ext:RsPathL3OutAtt) + description: More information about the internal APIC class B(l3ext:Ip) link: https://developer.cisco.com/docs/apic-mim-ref/ author: - Shreyas Srish (@shrsr) @@ -295,20 +293,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - [ - "state", - "absent", - [ - "secondary_ip", - ], - ], - [ - "state", - "present", - [ - "secondary_ip", - ], - ], + ["state", "absent", ["secondary_ip"]], + ["state", "present", ["secondary_ip"]], ], ) From 72d11118152bdfb68c63aebb4f08bb30b3f050ea Mon Sep 17 00:00:00 2001 From: Shreyas Date: Wed, 4 Oct 2023 15:02:14 -0400 Subject: [PATCH 10/19] [ignore] Modified docs to exclude un-used parameters in the 'floating_svi' modules --- plugins/modules/aci_l3out_floating_svi.py | 12 +-- .../modules/aci_l3out_floating_svi_path.py | 17 ++--- ...ci_l3out_floating_svi_path_secondary_ip.py | 30 +++----- .../aci_l3out_floating_svi_secondary_ip.py | 22 ++---- .../tasks/main.yml | 59 ++++++++++---- .../tasks/main.yml | 76 +++++++++++++++---- .../tasks/main.yml | 35 +++++++-- 7 files changed, 168 insertions(+), 83 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 20e7b679f..641aee24a 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -113,12 +113,14 @@ - cisco.aci.annotation notes: -- The C(l3out), C(logical_node_profile) and C(logical_interface_profile) used must exist before using this module in your playbook. - The M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile) and M(cisco.aci.aci_l3out_logical_interface_profile) modules can be used for this. +- The C(tenant), C(l3out), C(logical_node_profile) and C(logical_interface_profile) must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) \ + modules can be used for this. seealso: -- module: aci_l3out -- module: aci_l3out_logical_node_profile -- module: aci_l3out_logical_interface_profile +- module: cisco.aci.aci_tenant +- module: cisco.aci.aci_l3out +- module: cisco.aci.aci_l3out_logical_node_profile +- module: cisco.aci.aci_l3out_logical_interface_profile - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:VirtualLIfP) link: https://developer.cisco.com/docs/apic-mim-ref/ diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index 5d102afe7..a4c388e69 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -55,11 +55,6 @@ - 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. @@ -113,10 +108,15 @@ - cisco.aci.annotation notes: -- The C(floating_svi) used must exist before using this module in your playbook. - The M(cisco.aci.aci_l3out_floating_svi) module can be used for this. +- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and \ + M(cisco.aci.aci_l3out_floating_svi) can be used for this. seealso: -- module: aci_l3out_floating_svi +- module: cisco.aci.aci_tenant +- module: cisco.aci.aci_l3out +- module: cisco.aci.aci_l3out_logical_node_profile +- module: cisco.aci.aci_l3out_logical_interface_profile +- module: cisco.aci.aci_l3out_floating_svi - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:RsDynPathAtt)) link: https://developer.cisco.com/docs/apic-mim-ref/ @@ -337,7 +337,6 @@ 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"]), forged_transmit=dict(type="str", choices=["enabled", "disabled"], default="disabled"), mac_change=dict(type="str", choices=["enabled", "disabled"], default="disabled"), 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 770167a98..0e67d599f 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -59,11 +59,6 @@ - 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. @@ -75,20 +70,11 @@ 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. @@ -101,11 +87,16 @@ - cisco.aci.annotation notes: -- The C(floating_svi) and C(floating_svi_path) used must exist before using this module in your playbook. - The M(cisco.aci.aci_l3out_floating_svi) and M(cisco.aci.aci_l3out_floating_svi_path) modules can be used for this. +- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile), \ + M(cisco.aci.aci_l3out_floating_svi) and M(cisco.aci.aci_l3out_floating_svi_path) can be used for this. seealso: -- module: aci_l3out_floating_svi -- module: aci_l3out_floating_svi_path +- module: cisco.aci.aci_tenant +- module: cisco.aci.aci_l3out +- module: cisco.aci.aci_l3out_logical_node_profile +- module: cisco.aci.aci_l3out_logical_interface_profile +- module: cisco.aci.aci_l3out_floating_svi +- module: cisco.aci.aci_l3out_floating_svi_path - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:Ip) link: https://developer.cisco.com/docs/apic-mim-ref/ @@ -309,12 +300,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"]), - 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( diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index c775449f7..0041e99d8 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -64,15 +64,6 @@ - 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. @@ -85,10 +76,15 @@ - cisco.aci.annotation notes: -- The C(floating_svi) used must exist before using this module in your playbook. - The M(cisco.aci.aci_l3out_floating_svi) module can be used for this. +- The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and \ + M(cisco.aci.aci_l3out_floating_svi) can be used for this. seealso: -- module: aci_l3out_floating_svi +- module: cisco.aci.aci_tenant +- module: cisco.aci.aci_l3out +- module: cisco.aci.aci_l3out_logical_node_profile +- module: cisco.aci.aci_l3out_logical_interface_profile +- module: cisco.aci.aci_l3out_floating_svi - name: APIC Management Information Model reference description: More information about the internal APIC class B(l3ext:Ip) link: https://developer.cisco.com/docs/apic-mim-ref/ @@ -284,9 +280,7 @@ 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( 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 523193528..4f9c5bb6a 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 @@ -63,7 +63,7 @@ interface_profile: Floating - name: Create a floating svi - cisco.aci.aci_l3out_floating_svi: &floating_svi + cisco.aci.aci_l3out_floating_svi: <<: *intf_present pod_id: 1 node_id: 201 @@ -72,7 +72,7 @@ state: present - name: Create a floating svi - cisco.aci.aci_l3out_floating_svi: &floating_svi2 + cisco.aci.aci_l3out_floating_svi: <<: *intf_present pod_id: 1 node_id: 202 @@ -100,7 +100,10 @@ - name: Create a floating svi path of type physical in check_mode cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom floating_ip: 25.45.67.90/24 @@ -111,7 +114,10 @@ - name: Create a floating svi path of type physical in normal mode cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom floating_ip: 25.45.67.90/24 @@ -121,7 +127,10 @@ - name: Create a floating svi path of type physical in normal mode again cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom floating_ip: 25.45.67.90/24 @@ -131,7 +140,10 @@ - name: Update a floating svi path of type physical cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom floating_ip: 25.45.67.90/24 @@ -141,7 +153,10 @@ - name: Create another floating svi path of type physical cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom2 floating_ip: 25.45.67.90/24 @@ -151,7 +166,10 @@ - name: Create a floating svi path of type virtual cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi2 + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 domain_type: vmware domain: vmm_dom floating_ip: 27.45.67.90/24 @@ -164,7 +182,10 @@ - name: Create a floating svi path of type virtual (change enhanced_lag_policy) cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi2 + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 domain_type: vmware domain: vmm_dom floating_ip: 27.45.67.90/24 @@ -177,7 +198,10 @@ - name: Create a floating svi path of type virtual (delete enhanced_lag_policy) cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi2 + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 domain_type: vmware domain: vmm_dom floating_ip: 27.45.67.90/24 @@ -214,7 +238,10 @@ - name: Query a floating svi path cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom state: query @@ -222,7 +249,10 @@ - name: Query all floating svi paths cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 state: query register: query_all_floating @@ -238,7 +268,10 @@ - name: Remove a floating svi path cisco.aci.aci_l3out_floating_svi_path: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom state: absent 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 596ddc752..1e9d9d454 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 @@ -63,7 +63,7 @@ interface_profile: Floating - name: Create a floating svi - cisco.aci.aci_l3out_floating_svi: &floating_svi + cisco.aci.aci_l3out_floating_svi: <<: *intf_present pod_id: 1 node_id: 201 @@ -72,16 +72,22 @@ state: present - name: Create a floating svi path of type physical - cisco.aci.aci_l3out_floating_svi_path: &floating_svi_path - <<: *floating_svi + cisco.aci.aci_l3out_floating_svi_path: + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: physical domain: physical_dom floating_ip: 25.45.67.90/24 state: present - name: Create a floating svi path of type virtual - cisco.aci.aci_l3out_floating_svi_path: &floating_svi_path2 - <<: *floating_svi + cisco.aci.aci_l3out_floating_svi_path: + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 domain_type: vmware domain: virtual floating_ip: 25.45.67.90/24 @@ -89,14 +95,24 @@ - name: Create a floating svi path secondary_ip (virtual) cisco.aci.aci_l3out_floating_svi_path_secondary_ip: - <<: *floating_svi_path2 + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: vmware + domain: virtual secondary_ip: 30.45.67.90/24 state: present - register: add_ip_cm + register: add_ip_virtual - name: Create a floating svi path secondary_ip in check mode cisco.aci.aci_l3out_floating_svi_path_secondary_ip: - <<: *floating_svi_path + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom secondary_ip: 27.45.67.90/24 state: present check_mode: true @@ -104,21 +120,36 @@ - name: Create a floating svi path secondary_ip in normal mode cisco.aci.aci_l3out_floating_svi_path_secondary_ip: - <<: *floating_svi_path + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom 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 + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom 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 + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom secondary_ip: 28.45.67.90/24 state: present register: add_another_ip @@ -130,19 +161,31 @@ - add_ip_nm is changed - add_ip_again is not changed - add_another_ip is changed + - add_ip_virtual.current.0.l3extIp.attributes.addr == "30.45.67.90/24" + - add_ip_cm.proposed.l3extIp.attributes.addr == "27.45.67.90/24" - 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 + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom secondary_ip: 27.45.67.90/24 state: query register: query_ip - name: Query all ips cisco.aci.aci_l3out_floating_svi_path_secondary_ip: - <<: *floating_svi_path + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom state: query register: query_all @@ -156,7 +199,12 @@ - name: Delete a floating svi path secondary_ip cisco.aci.aci_l3out_floating_svi_path_secondary_ip: - <<: *floating_svi_path + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 + domain_type: physical + domain: physical_dom secondary_ip: 27.45.67.90/24 state: absent register: delete_ip 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 57a270997..6457101a5 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 @@ -75,7 +75,10 @@ - name: Create a floating svi secondary_ip in check mode cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 25.45.67.90/24 state: present check_mode: true @@ -83,21 +86,30 @@ - name: Create a floating svi secondary_ip in normal mode cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 25.45.67.90/24 state: present register: add_ip_nm - name: Create a floating svi secondary_ip again cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 25.45.67.90/24 state: present register: add_ip_again - name: Create another floating svi secondary_ip cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 26.45.67.90/24 state: present register: add_another_ip @@ -114,14 +126,20 @@ - name: Query a floating svi secondary_ip cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 25.45.67.90/24 state: query register: query_ip - name: Query all ips cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 state: query register: query_all @@ -135,7 +153,10 @@ - name: Delete a floating svi secondary_ip cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *floating_svi + <<: *intf_present + pod_id: 1 + node_id: 201 + encap: vlan-1 secondary_ip: 25.45.67.90/24 state: absent register: delete_ip From 826480128d8d1d7067df981b5f56b8fe42d1d967 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Thu, 5 Oct 2023 08:59:20 -0400 Subject: [PATCH 11/19] [ignore] Modified test file to include anchors in 'floating_svi_secondary_ip' for a few tasks --- .../tasks/main.yml | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) 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 6457101a5..a3df52fae 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 @@ -63,7 +63,7 @@ interface_profile: Floating - name: Create a floating svi - cisco.aci.aci_l3out_floating_svi: &floating_svi + cisco.aci.aci_l3out_floating_svi: <<: *intf_present pod_id: 1 node_id: 201 @@ -74,7 +74,7 @@ register: add_floating_cm - name: Create a floating svi secondary_ip in check mode - cisco.aci.aci_l3out_floating_svi_secondary_ip: + cisco.aci.aci_l3out_floating_svi_secondary_ip: &floating_svi <<: *intf_present pod_id: 1 node_id: 201 @@ -86,21 +86,13 @@ - name: Create a floating svi secondary_ip in normal mode cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *intf_present - pod_id: 1 - node_id: 201 - encap: vlan-1 - secondary_ip: 25.45.67.90/24 + <<: *floating_svi state: present register: add_ip_nm - name: Create a floating svi secondary_ip again cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *intf_present - pod_id: 1 - node_id: 201 - encap: vlan-1 - secondary_ip: 25.45.67.90/24 + <<: *floating_svi state: present register: add_ip_again @@ -126,11 +118,7 @@ - name: Query a floating svi secondary_ip cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *intf_present - pod_id: 1 - node_id: 201 - encap: vlan-1 - secondary_ip: 25.45.67.90/24 + <<: *floating_svi state: query register: query_ip @@ -153,11 +141,7 @@ - name: Delete a floating svi secondary_ip cisco.aci.aci_l3out_floating_svi_secondary_ip: - <<: *intf_present - pod_id: 1 - node_id: 201 - encap: vlan-1 - secondary_ip: 25.45.67.90/24 + <<: *floating_svi state: absent register: delete_ip From 3e401f6f561c88efbc1c97f098b83eb69a3807d9 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Wed, 11 Oct 2023 13:07:29 -0400 Subject: [PATCH 12/19] [ignore] Added a field for author in the modules of 'floating_svi' --- plugins/modules/aci_l3out_floating_svi.py | 1 + plugins/modules/aci_l3out_floating_svi_path.py | 1 + .../aci_l3out_floating_svi_path_secondary_ip.py | 1 + plugins/modules/aci_l3out_floating_svi_secondary_ip.py | 1 + .../targets/aci_l3out_floating_svi/tasks/main.yml | 10 +++++----- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 641aee24a..3843ad471 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +# Copyright: (c) 2023, Shreyas Srish # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index a4c388e69..43c2be91d 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +# Copyright: (c) 2023, Shreyas Srish # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function 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 0e67d599f..e13fb6f1a 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +# Copyright: (c) 2023, Shreyas Srish # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function diff --git a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py index 0041e99d8..8b6c201e3 100644 --- a/plugins/modules/aci_l3out_floating_svi_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_secondary_ip.py @@ -1,6 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +# Copyright: (c) 2023, Shreyas Srish # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function diff --git a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml index 2fe14cdb6..a2f227926 100644 --- a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml @@ -55,7 +55,7 @@ cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outintftest - node_profile: NODES + node_profile: nodes - name: Add interface profile cisco.aci.aci_l3out_logical_interface_profile: &intf_present @@ -144,17 +144,17 @@ - add_floating3 is changed - change_floating3 is not changed - add_floating_cm.proposed.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" - - add_floating_cm.proposed.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - add_floating_cm.proposed.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" - add_floating_cm.proposed.l3extVirtualLIfP.attributes.encap == "vlan-1" - add_floating_cm.proposed.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge1" - add_floating_nm.current.0.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" - - add_floating_nm.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - add_floating_nm.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" - add_floating_nm.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" - add_floating_nm.current.0.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge1" - update_floating.current.0.l3extVirtualLIfP.children.0.l3extBdProfileCont.children.0.l3extRsBdProfile.attributes.tDn == "uni/tn-ansible_test/bdprofile-bridge2" - remove_bridge.current.0.l3extVirtualLIfP.children is not defined - add_floating2.current.0.l3extVirtualLIfP.attributes.addr == "24.45.67.90/24" - - add_floating2.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-202]-[vlan-1]" + - add_floating2.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-202]-[vlan-1]" - add_floating2.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" - add_floating3.current.0.l3extVirtualLIfP.children is not defined @@ -176,7 +176,7 @@ - query_floating is not changed - query_all_floating is not changed - query_floating.current.0.l3extVirtualLIfP.attributes.addr == "23.45.67.90/24" - - query_floating.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-NODES/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" + - query_floating.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" - query_floating.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" - query_all_floating.current.0.l3extLIfP.children | length == 3 From 6ae5766335db47e3accc0bcfde7d3152fb8a33ca Mon Sep 17 00:00:00 2001 From: Shreyas Date: Wed, 11 Oct 2023 13:12:29 -0400 Subject: [PATCH 13/19] [ignore] Removed the path changes made to 'aci_rest' which is part of another PR --- plugins/modules/aci_rest.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/modules/aci_rest.py b/plugins/modules/aci_rest.py index d1207f464..374c9206f 100644 --- a/plugins/modules/aci_rest.py +++ b/plugins/modules/aci_rest.py @@ -406,8 +406,7 @@ 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.path = path.lstrip("/") - aci.url = "{0}/{1}".format(aci.base_url, aci.path) + aci.url = "{0}/{1}".format(aci.base_url, path.lstrip("/")) if aci.params.get("method") != "get" and not rsp_subtree_preserve: aci.url = update_qsl(aci.url, {"rsp-subtree": "modified"}) From 4101af2097bb821742d14d33a26bab1b26bc142f Mon Sep 17 00:00:00 2001 From: Shreyas Date: Fri, 13 Oct 2023 14:59:14 -0400 Subject: [PATCH 14/19] [ignore] Added ',' to a line of code to conform to black formatting in 'l3out_floating_svi' --- plugins/modules/aci_l3out_floating_svi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 3843ad471..78fa34a8c 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -340,7 +340,7 @@ def main(): encap_scope=dict(type="str", choices=["vrf", "local"]), auto_state=dict(type="str", choices=["enabled", "disabled"]), external_bridge_group_profile=dict(type="str"), - dscp=aci_contract_dscp_spec(direction="dscp") + dscp=aci_contract_dscp_spec(direction="dscp"), ) module = AnsibleModule( From 53921030df89c08f9b788d8d5afb745f86111ae0 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Fri, 20 Oct 2023 12:51:40 -0400 Subject: [PATCH 15/19] [ignore] Modified the name of the examples inside the module 'floating_svi' --- .../modules/aci_l3out_floating_svi_path_secondary_ip.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 e13fb6f1a..e0ae88350 100644 --- a/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py +++ b/plugins/modules/aci_l3out_floating_svi_path_secondary_ip.py @@ -107,7 +107,7 @@ EXAMPLES = r""" - name: Create a Floating SVI path attribute secondary IP - cisco.aci.aci_l3out_floating_svi_path: + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -125,7 +125,7 @@ delegate_to: localhost - name: Remove a Floating SVI path attribute secondary IP - cisco.aci.aci_l3out_floating_svi_path: + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -143,7 +143,7 @@ delegate_to: localhost - name: Query a Floating SVI path attribute secondary IP - cisco.aci.aci_l3out_floating_svi_path: + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: host: apic username: admin password: SomeSecretPassword @@ -162,7 +162,7 @@ register: query_result - name: Query all the secondary IPs under a Floating SVI path attribute - cisco.aci.aci_l3out_floating_svi_path: + cisco.aci.aci_l3out_floating_svi_path_secondary_ip: host: apic username: admin password: SomeSecretPassword From 8f786145fc33769902e81c9e7e6112621870e839 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Fri, 3 Nov 2023 00:55:20 -0400 Subject: [PATCH 16/19] [ignore] Addition of code to incorporate different versions of apic in the 'floating_svi_modules' --- plugins/modules/aci_l3out_floating_svi.py | 7 +- .../modules/aci_l3out_floating_svi_path.py | 58 ++++++++++------- .../aci_l3out_floating_svi/tasks/main.yml | 4 +- .../tasks/main.yml | 65 +++++++++++++++++-- .../tasks/main.yml | 4 +- 5 files changed, 106 insertions(+), 32 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 78fa34a8c..4b28efeb6 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -114,6 +114,7 @@ - cisco.aci.annotation notes: +- The attribute external_bridge_group_profile is only supported in APIC v5.0 and above. - The C(tenant), C(l3out), C(logical_node_profile) and C(logical_interface_profile) must exist before using this module in your playbook. The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) \ modules can be used for this. @@ -376,6 +377,10 @@ def main(): if pod_id and node_id: node_dn = "topology/pod-{0}/node-{1}".format(pod_id, node_id) + child_classes = [] + if external_bridge_group_profile is not None: + child_classes.append("l3extBdProfileCont") + aci.construct_url( root_class=dict( aci_class="fvTenant", @@ -404,7 +409,7 @@ def main(): subclass_4=dict( aci_class="l3extVirtualLIfP", aci_rn="vlifp-[{0}]-[{1}]".format(node_dn, encap), module_object=node_dn, target_filter={"nodeDn": node_dn} ), - child_classes=["l3extBdProfileCont"], + child_classes=child_classes, ) aci.get_existing() diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index 43c2be91d..ccca814f1 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -79,19 +79,16 @@ - This option allows virtual machines to send frames with a mac address. type: str 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: [ enabled, disabled ] - default: disabled promiscuous_mode: description: - The status of promiscuous mode for port groups in an external VMM controller. type: str choices: [ enabled, disabled ] - default: disabled enhanced_lag_policy: description: - The enhanced lag policy of the path. @@ -109,8 +106,10 @@ - cisco.aci.annotation notes: +- The domain of floating path of type physical is only supported in APIC v5.0 and above. +- The attributes forged_transmit, mac_change and promiscuous_mode are only supported in APIC v5.0 and above. - The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and \ + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and M(cisco.aci.aci_l3out_floating_svi) can be used for this. seealso: - module: cisco.aci.aci_tenant @@ -339,9 +338,9 @@ def main(): node_id=dict(type="str", required=True), encap=dict(type="str", required=True), 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"), + 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"]), domain=dict(type="str"), enhanced_lag_policy=dict(type="str"), @@ -366,9 +365,9 @@ 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").capitalize() - mac_change = module.params.get("mac_change").capitalize() - promiscuous_mode = module.params.get("promiscuous_mode").capitalize() + forged_transmit = module.params.get("forged_transmit").capitalize() if module.params.get("forged_transmit") else None + mac_change = module.params.get("mac_change").capitalize() if module.params.get("mac_change") else None + promiscuous_mode = module.params.get("promiscuous_mode").capitalize() if module.params.get("promiscuous_mode") else None domain_type = module.params.get("domain_type") domain = module.params.get("domain") enhanced_lag_policy = module.params.get("enhanced_lag_policy") @@ -430,14 +429,18 @@ def main(): if isinstance(aci.existing, list) and len(aci.existing) > 0: for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}): if child.get("l3extVirtualLIfPLagPolAtt"): - existing_enhanced_lag_policy = ( - child.get("l3extVirtualLIfPLagPolAtt") - .get("children")[0] - .get("l3extRsVSwitchEnhancedLagPol") - .get("attributes") - .get("tDn") - .split("enlacplagp-")[1] - ) + try: + existing_enhanced_lag_policy = ( + child["l3extVirtualLIfPLagPolAtt"] + ["children"][0] + ["l3extRsVSwitchEnhancedLagPol"] + ["attributes"] + ["tDn"] + .split("enlacplagp-")[1] + ) + except (AttributeError, IndexError, KeyError): + existing_enhanced_lag_policy = "" + if enhanced_lag_policy == "": child_configs.append( dict( @@ -465,15 +468,20 @@ def main(): ) child_configs.append(dict(l3extVirtualLIfPLagPolAtt=dict(attributes=dict(), children=child))) + class_config = dict(floatingAddr=floating_ip) + + if forged_transmit: + class_config.update(forgedTransmit=forged_transmit) + if mac_change: + class_config.update(macChange=mac_change) + if promiscuous_mode: + class_config.update(promMode=promiscuous_mode) + if access_encap: + class_config.update(encap=access_encap) + aci.payload( aci_class="l3extRsDynPathAtt", - class_config=dict( - floatingAddr=floating_ip, - forgedTransmit=forged_transmit, - macChange=mac_change, - promMode=promiscuous_mode, - encap=access_encap, - ), + class_config=class_config, child_configs=child_configs, ) diff --git a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml index a2f227926..8f9de3e27 100644 --- a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml @@ -24,7 +24,9 @@ include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml - name: Execute tasks only for non-cloud sites - when: query_cloud.current == [] # This condition will execute only non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites block: # block specifies execution of tasks within, based on conditions # SETUP ENVIRONMENT - name: Create domain 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 4f9c5bb6a..78d7d913b 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 @@ -55,7 +55,7 @@ cisco.aci.aci_l3out_logical_node_profile: &np_present <<: *tenant_present l3out: l3outintftest - node_profile: NODES + node_profile: nodes - name: Add interface profile cisco.aci.aci_l3out_logical_interface_profile: &intf_present @@ -111,6 +111,7 @@ state: present check_mode: true register: add_floating_path_cm + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi path of type physical in normal mode cisco.aci.aci_l3out_floating_svi_path: @@ -124,6 +125,7 @@ access_encap: vlan-1 state: present register: add_floating_path_nm + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi path of type physical in normal mode again cisco.aci.aci_l3out_floating_svi_path: @@ -137,6 +139,7 @@ access_encap: vlan-1 state: present register: add_floating_path_again + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Update a floating svi path of type physical cisco.aci.aci_l3out_floating_svi_path: @@ -150,6 +153,7 @@ access_encap: vlan-2 state: present register: update_floating_path + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create another floating svi path of type physical cisco.aci.aci_l3out_floating_svi_path: @@ -163,6 +167,7 @@ access_encap: vlan-1 state: present register: add_another_floating_path + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi path of type virtual cisco.aci.aci_l3out_floating_svi_path: @@ -179,6 +184,7 @@ enhanced_lag_policy: enhanced state: present register: add_enhanced + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi path of type virtual (change enhanced_lag_policy) cisco.aci.aci_l3out_floating_svi_path: @@ -195,6 +201,7 @@ enhanced_lag_policy: enhanced2 state: present register: change_enhanced + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi path of type virtual (delete enhanced_lag_policy) cisco.aci.aci_l3out_floating_svi_path: @@ -211,6 +218,7 @@ enhanced_lag_policy: "" state: present register: del_enhanced + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Verify present ops assert: @@ -223,11 +231,11 @@ - 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.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.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" @@ -235,6 +243,50 @@ - 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 + when: version.current.0.topSystem.attributes.version is version('5', '>=') + +# Special Case + - name: Create a floating svi path of type virtual with enhanced2 of type l3extRsVSwitchEnhancedLagPol + cisco.aci.aci_l3out_floating_svi_path: + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 + domain_type: vmware + domain: vmm_dom + floating_ip: 27.45.67.90/24 + enhanced_lag_policy: enhanced2 + state: present + register: check_v_four + + - name: Delete enhanced2 of type l3extRsVSwitchEnhancedLagPol + cisco.aci.aci_rest: + <<: *aci_info + path: api/node/mo/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]/vlifplagpolatt/rsvSwitchEnhancedLagPol-[uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont/enlacplagp-enhanced2].json + method: post + content: | + {"l3extRsVSwitchEnhancedLagPol":{"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]/vlifplagpolatt/rsvSwitchEnhancedLagPol-[uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont/enlacplagp-enhanced2]","status":"deleted"}}} + + - name: Create a floating svi path of type virtual with enhanced2 of type l3extRsVSwitchEnhancedLagPol + cisco.aci.aci_l3out_floating_svi_path: + <<: *intf_present + pod_id: 1 + node_id: 202 + encap: vlan-1 + domain_type: vmware + domain: vmm_dom + floating_ip: 27.45.67.90/24 + enhanced_lag_policy: enhanced2 + state: present + register: check_enhanced + + - name: Verify special case + assert: + that: + - check_v_four is changed + - check_enhanced is changed + - check_v_four.current.0.l3extRsDynPathAtt.attributes.floatingAddr == "27.45.67.90/24" + - check_enhanced.current.0.l3extRsDynPathAtt.children.0.l3extVirtualLIfPLagPolAtt.children.0.l3extRsVSwitchEnhancedLagPol.attributes.tDn == "uni/vmmp-VMware/dom-vmm_dom/vswitchpolcont/enlacplagp-enhanced2" - name: Query a floating svi path cisco.aci.aci_l3out_floating_svi_path: @@ -246,6 +298,7 @@ domain: physical_dom state: query register: query_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Query all floating svi paths cisco.aci.aci_l3out_floating_svi_path: @@ -255,16 +308,18 @@ encap: vlan-1 state: query register: query_all_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - 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.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 + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Remove a floating svi path cisco.aci.aci_l3out_floating_svi_path: @@ -276,12 +331,14 @@ domain: physical_dom state: absent register: remove_floating_path + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Verify absent ops assert: that: - remove_floating_path is changed - remove_floating_path.current == [] + when: version.current.0.topSystem.attributes.version is version('5', '>=') # Clean up Environment - name: Remove vSwitch Policy 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 1e9d9d454..0f9e08325 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 @@ -24,7 +24,9 @@ include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml - name: Execute tasks only for non-cloud sites - when: query_cloud.current == [] # This condition will execute only non-cloud sites + when: + - version.current.0.topSystem.attributes.version is version('5', '>=') + - query_cloud.current == [] # This condition will execute only non-cloud sites block: # block specifies execution of tasks within, based on conditions # SETUP ENVIRONMENT - name: Create domain From 26b5141b05d979d3f2c5289b4a26d885da6f99ce Mon Sep 17 00:00:00 2001 From: Shreyas Date: Fri, 3 Nov 2023 13:36:58 -0400 Subject: [PATCH 17/19] [ignore] Addition of notes to attributes in the docs section of 'l3out floating modules' --- plugins/modules/aci_l3out_floating_svi.py | 2 +- .../modules/aci_l3out_floating_svi_path.py | 25 ++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi.py b/plugins/modules/aci_l3out_floating_svi.py index 4b28efeb6..b0e3ca7e3 100644 --- a/plugins/modules/aci_l3out_floating_svi.py +++ b/plugins/modules/aci_l3out_floating_svi.py @@ -96,6 +96,7 @@ description: - The external bridge group profile. - Pass "" as the value to remove an existing external bridge group profile (See Examples). + - This is only supported in APIC v5.0 and above. type: str state: description: @@ -114,7 +115,6 @@ - cisco.aci.annotation notes: -- The attribute external_bridge_group_profile is only supported in APIC v5.0 and above. - The C(tenant), C(l3out), C(logical_node_profile) and C(logical_interface_profile) must exist before using this module in your playbook. The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) \ modules can be used for this. diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index ccca814f1..521d28492 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -63,6 +63,7 @@ domain_type: description: - The domain type of the path. + - The physical domain type is only supported in APIC v5.0 and above. type: str choices: [ physical, vmware ] access_encap: @@ -77,16 +78,19 @@ forged_transmit: description: - This option allows virtual machines to send frames with a mac address. + - This is only supported in APIC v5.0 and above. type: str choices: [ enabled, disabled ] mac_change: description: - The status of the mac address change support for port groups in an external VMM controller. + - This is only supported in APIC v5.0 and above. type: str choices: [ enabled, disabled ] promiscuous_mode: description: - The status of promiscuous mode for port groups in an external VMM controller. + - This is only supported in APIC v5.0 and above. type: str choices: [ enabled, disabled ] enhanced_lag_policy: @@ -106,8 +110,6 @@ - cisco.aci.annotation notes: -- The domain of floating path of type physical is only supported in APIC v5.0 and above. -- The attributes forged_transmit, mac_change and promiscuous_mode are only supported in APIC v5.0 and above. - The C(tenant), C(l3out), C(logical_node_profile), C(logical_interface_profile) and C(floating_svi) must exist before using this module in your playbook. The M(cisco.aci.aci_tenant), M(cisco.aci.aci_l3out), M(cisco.aci.aci_l3out_logical_node_profile), M(cisco.aci.aci_l3out_logical_interface_profile) and M(cisco.aci.aci_l3out_floating_svi) can be used for this. @@ -468,20 +470,15 @@ def main(): ) child_configs.append(dict(l3extVirtualLIfPLagPolAtt=dict(attributes=dict(), children=child))) - class_config = dict(floatingAddr=floating_ip) - - if forged_transmit: - class_config.update(forgedTransmit=forged_transmit) - if mac_change: - class_config.update(macChange=mac_change) - if promiscuous_mode: - class_config.update(promMode=promiscuous_mode) - if access_encap: - class_config.update(encap=access_encap) - aci.payload( aci_class="l3extRsDynPathAtt", - class_config=class_config, + class_config=dict( + floatingAddr=floating_ip, + forgedTransmit=forged_transmit, + macChange=mac_change, + promMode=promiscuous_mode, + encap=access_encap, + ), child_configs=child_configs, ) From ca2d6c8fc7bc42e7ff7b57bb9721c484c8ad21de Mon Sep 17 00:00:00 2001 From: Shreyas Date: Tue, 7 Nov 2023 13:19:02 -0500 Subject: [PATCH 18/19] [ignore] Addition of test statements for 'aci_l3out_floating_svi' to incorporate all versions of apic --- .../aci_l3out_floating_svi/tasks/main.yml | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml index 8f9de3e27..3272baac2 100644 --- a/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml +++ b/tests/integration/targets/aci_l3out_floating_svi/tasks/main.yml @@ -24,9 +24,7 @@ include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml - name: Execute tasks only for non-cloud sites - when: - - version.current.0.topSystem.attributes.version is version('5', '>=') - - query_cloud.current == [] # This condition will execute only non-cloud sites + when: query_cloud.current == [] # This condition will execute only non-cloud sites block: # block specifies execution of tasks within, based on conditions # SETUP ENVIRONMENT - name: Create domain @@ -75,18 +73,21 @@ state: present check_mode: true register: add_floating_cm + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi in normal mode cisco.aci.aci_l3out_floating_svi: <<: *floating_svi state: present register: add_floating_nm + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create a floating svi again cisco.aci.aci_l3out_floating_svi: <<: *floating_svi state: present register: add_floating_again + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Update floating svi cisco.aci.aci_l3out_floating_svi: @@ -94,6 +95,7 @@ external_bridge_group_profile: bridge2 state: present register: update_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Delete an external_bridge_group_profile cisco.aci.aci_l3out_floating_svi: @@ -101,6 +103,7 @@ external_bridge_group_profile: "" state: present register: remove_bridge + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create another floating svi cisco.aci.aci_l3out_floating_svi: @@ -112,6 +115,7 @@ external_bridge_group_profile: "" state: present register: add_floating2 + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Create another floating svi with no external_bridge_group_profile cisco.aci.aci_l3out_floating_svi: @@ -133,6 +137,7 @@ external_bridge_group_profile: "" state: present register: change_floating3 + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Verify present ops assert: @@ -158,6 +163,15 @@ - add_floating2.current.0.l3extVirtualLIfP.attributes.addr == "24.45.67.90/24" - add_floating2.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-202]-[vlan-1]" - add_floating2.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" + when: version.current.0.topSystem.attributes.version is version('5', '>=') + + - name: Verify present ops for all versions + assert: + that: + - add_floating3 is changed + - add_floating3.current.0.l3extVirtualLIfP.attributes.addr == "25.45.67.90/24" + - add_floating3.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-203]-[vlan-1]" + - add_floating3.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" - add_floating3.current.0.l3extVirtualLIfP.children is not defined - name: Query a floating svi @@ -165,12 +179,14 @@ <<: *floating_svi state: query register: query_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Query all floating svis cisco.aci.aci_l3out_floating_svi: <<: *intf_present state: query register: query_all_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Verify Query ops assert: @@ -181,18 +197,21 @@ - query_floating.current.0.l3extVirtualLIfP.attributes.dn == "uni/tn-ansible_test/out-l3outintftest/lnodep-nodes/lifp-Floating/vlifp-[topology/pod-1/node-201]-[vlan-1]" - query_floating.current.0.l3extVirtualLIfP.attributes.encap == "vlan-1" - query_all_floating.current.0.l3extLIfP.children | length == 3 + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Remove a floating svi cisco.aci.aci_l3out_floating_svi: <<: *floating_svi state: absent register: remove_floating + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Verify remove ops assert: that: - remove_floating is changed - remove_floating.current == [] + when: version.current.0.topSystem.attributes.version is version('5', '>=') - name: Clean up environment cisco.aci.aci_tenant: From 870fb1ca73d872d9c3c15560ab4c0ae123df0c36 Mon Sep 17 00:00:00 2001 From: Lionel Hercot Date: Thu, 16 Nov 2023 17:38:39 -0800 Subject: [PATCH 19/19] [ignore] Fix syntax using black on aci_l3out_floating_svi_path --- plugins/modules/aci_l3out_floating_svi_path.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/plugins/modules/aci_l3out_floating_svi_path.py b/plugins/modules/aci_l3out_floating_svi_path.py index 521d28492..1670180b8 100644 --- a/plugins/modules/aci_l3out_floating_svi_path.py +++ b/plugins/modules/aci_l3out_floating_svi_path.py @@ -432,14 +432,9 @@ def main(): for child in aci.existing[0].get("l3extRsDynPathAtt", {}).get("children", {}): if child.get("l3extVirtualLIfPLagPolAtt"): try: - existing_enhanced_lag_policy = ( - child["l3extVirtualLIfPLagPolAtt"] - ["children"][0] - ["l3extRsVSwitchEnhancedLagPol"] - ["attributes"] - ["tDn"] - .split("enlacplagp-")[1] - ) + existing_enhanced_lag_policy = child["l3extVirtualLIfPLagPolAtt"]["children"][0]["l3extRsVSwitchEnhancedLagPol"]["attributes"][ + "tDn" + ].split("enlacplagp-")[1] except (AttributeError, IndexError, KeyError): existing_enhanced_lag_policy = ""