From 86aa9cbfa2eba08373fc3978c8fc9ee3ea3aad54 Mon Sep 17 00:00:00 2001 From: Samita B <98932546+samiib@users.noreply.github.com> Date: Wed, 28 Feb 2024 08:38:39 +1000 Subject: [PATCH] [minor change] Added modules aci_ bd_to_netflow_monitor_policy and aci_bd_rogue_exception_mac and fixed missing clean-up in bd_to_l3out tests (#600) --- plugins/modules/aci_bd_rogue_exception_mac.py | 299 ++++++++++++++++++ .../aci_bd_to_netflow_monitor_policy.py | 292 +++++++++++++++++ .../aci_bd_rogue_exception_mac/aliases | 2 + .../aci_bd_rogue_exception_mac/tasks/main.yml | 186 +++++++++++ .../targets/aci_bd_to_l3out/tasks/main.yml | 10 + .../aci_bd_to_netflow_monitor_policy/aliases | 2 + .../tasks/main.yml | 191 +++++++++++ 7 files changed, 982 insertions(+) create mode 100644 plugins/modules/aci_bd_rogue_exception_mac.py create mode 100644 plugins/modules/aci_bd_to_netflow_monitor_policy.py create mode 100644 tests/integration/targets/aci_bd_rogue_exception_mac/aliases create mode 100644 tests/integration/targets/aci_bd_rogue_exception_mac/tasks/main.yml create mode 100644 tests/integration/targets/aci_bd_to_netflow_monitor_policy/aliases create mode 100644 tests/integration/targets/aci_bd_to_netflow_monitor_policy/tasks/main.yml diff --git a/plugins/modules/aci_bd_rogue_exception_mac.py b/plugins/modules/aci_bd_rogue_exception_mac.py new file mode 100644 index 000000000..8174f00db --- /dev/null +++ b/plugins/modules/aci_bd_rogue_exception_mac.py @@ -0,0 +1,299 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) +# 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": "certified"} + +DOCUMENTATION = r""" +--- +module: aci_bd_rogue_exception_mac +short_description: Manage Rogue Exception MAC (fv:RogueExceptionMac) +description: +- Manage Rogue Exception MACs in BD's on Cisco ACI fabrics. +- Only available in APIC version 5.2 or later. +options: + bd: + description: + - The name of the Bridge Domain. + type: str + aliases: [ bd_name, bridge_domain ] + tenant: + description: + - The name of the Tenant. + type: str + aliases: [ tenant_name ] + mac: + description: + - MAC address to except from Rogue processing. + type: str + description: + description: + - The description for the Rogue Exception MAC. + type: str + aliases: [ descr ] + 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: +- The C(tenant) and C(bd) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant) module and M(cisco.aci.aci_bd) can be used for these. +seealso: +- module: cisco.aci.aci_bd +- module: cisco.aci.aci_tenant +- name: APIC Management Information Model reference + description: More information about the internal APIC class B(fv:RogueExceptionMac). + link: https://developer.cisco.com/docs/apic-mim-ref/ +author: +- Samita Bhattacharjee (@samitab) +""" + +EXAMPLES = r""" +- name: Create a Rogue Exception MAC + cisco.aci.aci_bd_rogue_exception_mac: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + mac: "AA:BB:CC:DD:EE:11" + description: 1st MAC + state: present + delegate_to: localhost + +- name: Get all Rogue Exception MACs + cisco.aci.aci_bd_rogue_exception_mac: + host: apic + username: admin + password: SomeSecretPassword + state: query + delegate_to: localhost + +- name: Get all Rogue Exception MACs in specified Tenant + cisco.aci.aci_bd_rogue_exception_mac: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + state: query + delegate_to: localhost + register: query_result + +- name: Get specific Rogue Exception MAC + cisco.aci.aci_bd_rogue_exception_mac: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + mac: "AA:BB:CC:DD:EE:11" + state: query + delegate_to: localhost + register: query_result + +- name: Remove a Rogue Exception MAC from a Bridge Domain + cisco.aci.aci_bd_rogue_exception_mac: + host: apic + username: admin + password: SomeSecretPassword + tenant: production + bd: database + mac: "AA:BB:CC:DD:EE:11" + state: absent + delegate_to: localhost +""" + +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( + bd=dict(type="str", aliases=["bd_name", "bridge_domain"]), # Not required for querying all objects + tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects + mac=dict(type="str"), # Not required for querying all objects + description=dict(type="str", aliases=["descr"]), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "present", ["bd", "mac", "tenant"]], + ["state", "absent", ["bd", "mac", "tenant"]], + ], + ) + + aci = ACIModule(module) + + description = module.params.get("description") + tenant = module.params.get("tenant") + bd = module.params.get("bd") + mac = module.params.get("mac") + state = module.params.get("state") + + 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="fvBD", + aci_rn="BD-{0}".format(bd), + module_object=bd, + target_filter={"name": bd}, + ), + subclass_2=dict( + aci_class="fvRogueExceptionMac", + aci_rn="rgexpmac-{0}".format(mac), + module_object=mac, + target_filter={"mac": mac}, + ), + ) + + aci.get_existing() + + if state == "present": + aci.payload( + aci_class="fvRogueExceptionMac", + class_config=dict( + descr=description, + mac=mac, + ), + ) + + aci.get_diff(aci_class="fvRogueExceptionMac") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/aci_bd_to_netflow_monitor_policy.py b/plugins/modules/aci_bd_to_netflow_monitor_policy.py new file mode 100644 index 000000000..5e79a072c --- /dev/null +++ b/plugins/modules/aci_bd_to_netflow_monitor_policy.py @@ -0,0 +1,292 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) +# 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": "certified"} + +DOCUMENTATION = r""" +--- +module: aci_bd_to_netflow_monitor_policy +short_description: Bind Bridge Domain to Netflow Monitor Policy (fv:RsBDToNetflowMonitorPol) +description: +- Bind Bridge Domain to Netflow Monitor Policy on Cisco ACI fabrics. +options: + bd: + description: + - The name of the Bridge Domain. + type: str + aliases: [ bd_name, bridge_domain ] + tenant: + description: + - The name of the Tenant. + type: str + aliases: [ tenant_name ] + netflow_monitor_policy: + description: + - The name of the Netflow Monitor Policy. + type: str + aliases: [ netflow_monitor, netflow_monitor_name, name ] + filter_type: + description: + - Choice of filter type while setting NetFlow Monitor Policies. + type: str + choices: [ce, ipv4, ipv6, unspecified] + aliases: [ filter, type ] + 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: +- The C(bd) and C(netflow_monitor_policy) parameters should exist before using this module. + The M(cisco.aci.aci_bd) and C(aci_netflow_monitor_policy) can be used for this. +seealso: +- module: cisco.aci.aci_bd +- module: cisco.aci.aci_netflow_monitor_policy +- name: APIC Management Information Model reference + description: More information about the internal APIC class B(fv:RsBDToNetflowMonitorPol). + link: https://developer.cisco.com/docs/apic-mim-ref/ +author: +- Samita Bhattacharjee (@samitab) +""" + +EXAMPLES = r""" +- name: Bind Bridge Domain to Netflow Monitor Policy + cisco.aci.aci_bd_to_netflow_monitor_policy: + host: apic + username: admin + password: SomeSecretPassword + validate_certs: false + bd: web_servers + netflow_monitor_policy: prod_netflow_monitor_policy + tenant: prod + filter_type: ipv4 + state: present + delegate_to: localhost + +- name: Query all Bridge Domains bound to Netflow Monitor Policy + cisco.aci.aci_bd_to_netflow_monitor_policy: + host: apic + username: admin + password: SomeSecretPassword + validate_certs: true + state: query + delegate_to: localhost + register: query_result + +- name: Query specific Bridge Domain(s) bound to an Netflow Monitor Policy + cisco.aci.aci_bd_to_netflow_monitor_policy: + host: apic + username: admin + password: SomeSecretPassword + validate_certs: true + bd: web_servers + netflow_monitor_policy: prod_netflow_monitor_policy + tenant: prod + state: query + delegate_to: localhost + register: query_result + +- name: Unbind Bridge Domain from Netflow Monitor Policy + cisco.aci.aci_bd_to_netflow_monitor_policy: + host: apic + username: admin + password: SomeSecretPassword + validate_certs: true + bd: web_servers + netflow_monitor_policy: prod_netflow_monitor_policy + tenant: prod + filter_type: ipv4 + state: absent + delegate_to: localhost +""" + +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( + bd=dict(type="str", aliases=["bd_name", "bridge_domain"]), # Not required for querying all objects + netflow_monitor_policy=dict(type="str", aliases=["netflow_monitor", "netflow_monitor_name", "name"]), # Not required for querying all objects + filter_type=dict(type="str", choices=["ce", "ipv4", "ipv6", "unspecified"], aliases=["filter", "type"]), # Not required for querying all objects + tenant=dict(type="str", aliases=["tenant_name"]), # Not required for querying all objects + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "present", ["bd", "netflow_monitor_policy", "tenant", "filter_type"]], + ["state", "absent", ["bd", "netflow_monitor_policy", "tenant", "filter_type"]], + ], + ) + + bd = module.params.get("bd") + netflow_monitor_policy = module.params.get("netflow_monitor_policy") + filter_type = module.params.get("filter_type") + state = module.params.get("state") + tenant = module.params.get("tenant") + + aci = ACIModule(module) + 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="fvBD", + aci_rn="BD-{0}".format(bd), + module_object=bd, + target_filter={"name": bd}, + ), + subclass_2=dict( + aci_class="fvRsBDToNetflowMonitorPol", + aci_rn="rsBDToNetflowMonitorPol-[{0}]-{1}".format(netflow_monitor_policy, filter_type), + module_object=netflow_monitor_policy, + target_filter={"tnNetflowMonitorPolName": netflow_monitor_policy}, + ), + ) + + aci.get_existing() + + if state == "present": + aci.payload( + aci_class="fvRsBDToNetflowMonitorPol", + class_config=dict(tnNetflowMonitorPolName=netflow_monitor_policy, fltType=filter_type), + ) + + aci.get_diff(aci_class="fvRsBDToNetflowMonitorPol") + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/aci_bd_rogue_exception_mac/aliases b/tests/integration/targets/aci_bd_rogue_exception_mac/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_bd_rogue_exception_mac/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_bd_rogue_exception_mac/tasks/main.yml b/tests/integration/targets/aci_bd_rogue_exception_mac/tasks/main.yml new file mode 100644 index 000000000..7aebbb44d --- /dev/null +++ b/tests/integration/targets/aci_bd_rogue_exception_mac/tasks/main.yml @@ -0,0 +1,186 @@ +# Test code for the ACI modules +# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + ansible.builtin.fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.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") }}' + +- name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +# CLEAN ENVIRONMENT +- name: Remove the ansible_tenant + cisco.aci.aci_tenant: &aci_tenant_absent + <<: *aci_info + state: absent + tenant: ansible_test + +- name: Verify Cloud and Non-Cloud Sites in use. + ansible.builtin.include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: Execute tasks only for non-cloud sites and APIC version >= 5.2 + when: query_cloud.current == [] and version.current.0.topSystem.attributes.version is version('5.2', '>=') + block: + - name: Create tenant + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_tenant_absent + state: present + register: tenant_present + + - name: Ensure bd exists for tests to kick off + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + register: bd_present + + - name: Ensure rogue exception mac does not exist for tests to kick off + cisco.aci.aci_bd_rogue_exception_mac: &aci_rogue_exception_mac_absent + <<: *aci_bd_present + state: absent + mac: "AA:BB:CC:DD:EE:11" + description: 1st MAC + + - name: Ensure second rogue exception mac does not exist for tests to kick off + cisco.aci.aci_bd_rogue_exception_mac: &aci_rogue_exception_mac_absent_2 + <<: *aci_rogue_exception_mac_absent + mac: "AA-BB-CC-DD-EE-22" + description: 2nd MAC + + + - name: Create first rogue exception mac in bd (check_mode) + cisco.aci.aci_bd_rogue_exception_mac: &aci_bd_rogue_exception_mac_present + <<: *aci_rogue_exception_mac_absent + state: present + check_mode: true + register: cm_bd_rogue_exception_mac + + - name: Create first rogue exception mac in bd (normal_mode) + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + register: nm_bd_rogue_exception_mac + + - name: Create first rogue exception mac in bd again - testing idempotency + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + register: bd_rogue_exception_mac_idempotency + + - name: Create second rogue exception mac in bd + cisco.aci.aci_bd_rogue_exception_mac: &aci_bd_rogue_exception_mac_present_2 + <<: *aci_rogue_exception_mac_absent_2 + state: present + register: nm_bd_rogue_exception_mac_2 + + - name: Asserts for creation tasks + ansible.builtin.assert: + that: + - cm_bd_rogue_exception_mac is changed + - cm_bd_rogue_exception_mac.previous == [] + - cm_bd_rogue_exception_mac.current == [] + - cm_bd_rogue_exception_mac.proposed.fvRogueExceptionMac.attributes.dn == "uni/tn-ansible_test/BD-anstest/rgexpmac-AA:BB:CC:DD:EE:11" + - cm_bd_rogue_exception_mac.proposed.fvRogueExceptionMac.attributes.mac == "AA:BB:CC:DD:EE:11" + - cm_bd_rogue_exception_mac.proposed.fvRogueExceptionMac.attributes.descr == "1st MAC" + - nm_bd_rogue_exception_mac is changed + - nm_bd_rogue_exception_mac.current.0.fvRogueExceptionMac.attributes.dn == "uni/tn-ansible_test/BD-anstest/rgexpmac-AA:BB:CC:DD:EE:11" + - nm_bd_rogue_exception_mac.current.0.fvRogueExceptionMac.attributes.mac == "AA:BB:CC:DD:EE:11" + - nm_bd_rogue_exception_mac.current.0.fvRogueExceptionMac.attributes.descr == "1st MAC" + - bd_rogue_exception_mac_idempotency is not changed + - bd_rogue_exception_mac_idempotency.current == bd_rogue_exception_mac_idempotency.previous + - bd_rogue_exception_mac_idempotency.sent == {} + - nm_bd_rogue_exception_mac_2 is changed + - nm_bd_rogue_exception_mac_2.current.0.fvRogueExceptionMac.attributes.dn == "uni/tn-ansible_test/BD-anstest/rgexpmac-AA:BB:CC:DD:EE:22" + - nm_bd_rogue_exception_mac_2.current.0.fvRogueExceptionMac.attributes.mac == "AA:BB:CC:DD:EE:22" + - nm_bd_rogue_exception_mac_2.current.0.fvRogueExceptionMac.attributes.descr == "2nd MAC" + + - name: Query all bds bound to rogue exception mac + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_tenant_present + state: query + output_level: debug + register: query_all_bd_to_rogue_exception_mac + + - name: Query first bd with first rogue exception mac + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + state: query + output_level: debug + register: query_first_bd_to_rogue_exception_mac + + - name: Asserts query tasks + ansible.builtin.assert: + that: + - query_all_bd_to_rogue_exception_mac is not changed + - '"fvRogueExceptionMac" in query_all_bd_to_rogue_exception_mac.filter_string' + - query_all_bd_to_rogue_exception_mac.current.0.fvTenant.children.0.fvBD.children | length == 2 + - query_all_bd_to_rogue_exception_mac.current.0.fvTenant.children.0.fvBD.attributes.name == "anstest" + - query_all_bd_to_rogue_exception_mac.current.0.fvTenant.children.0.fvBD.children.0.fvRogueExceptionMac.attributes.rn == "rgexpmac-AA:BB:CC:DD:EE:22" + - query_all_bd_to_rogue_exception_mac.current.0.fvTenant.children.0.fvBD.children.1.fvRogueExceptionMac.attributes.rn == "rgexpmac-AA:BB:CC:DD:EE:11" + - query_first_bd_to_rogue_exception_mac is not changed + - '"tn-ansible_test/BD-anstest/rgexpmac-AA:BB:CC:DD:EE:11.json" in query_first_bd_to_rogue_exception_mac.url' + + - name: Delete first rogue exception mac (check_mode) + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + state: absent + check_mode: true + register: cm_unbind_bd_to_rogue_exception_mac + + - name: Delete first rogue exception mac (normal_mode) + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + state: absent + register: nm_unbind_bd_to_rogue_exception_mac + + - name: Delete first rogue exception mac again - testing idempotency + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present + state: absent + register: unbind_bd_to_rogue_exception_mac_idempotency + + - name: Delete second rogue exception mac + cisco.aci.aci_bd_rogue_exception_mac: + <<: *aci_bd_rogue_exception_mac_present_2 + state: absent + register: nm_unbind_bd_to_rogue_exception_mac_2 + + - name: Asserts for deletion tasks + ansible.builtin.assert: + that: + - cm_unbind_bd_to_rogue_exception_mac is changed + - cm_unbind_bd_to_rogue_exception_mac.current == cm_unbind_bd_to_rogue_exception_mac.previous + - cm_unbind_bd_to_rogue_exception_mac.proposed == {} + - nm_unbind_bd_to_rogue_exception_mac is changed + - nm_unbind_bd_to_rogue_exception_mac.previous != [] + - nm_unbind_bd_to_rogue_exception_mac.proposed == {} + - nm_unbind_bd_to_rogue_exception_mac.current == [] + - nm_unbind_bd_to_rogue_exception_mac.previous == cm_unbind_bd_to_rogue_exception_mac.current + - unbind_bd_to_rogue_exception_mac_idempotency is not changed + - unbind_bd_to_rogue_exception_mac_idempotency.previous == [] + - unbind_bd_to_rogue_exception_mac_idempotency.current == [] + - unbind_bd_to_rogue_exception_mac_idempotency.previous == [] + - nm_unbind_bd_to_rogue_exception_mac_2 is changed + - nm_unbind_bd_to_rogue_exception_mac_2.previous != [] + - nm_unbind_bd_to_rogue_exception_mac_2.current == [] + + - name: Delete tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent + when: tenant_present is changed diff --git a/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml b/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml index 34222eace..94e7b6db4 100644 --- a/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml +++ b/tests/integration/targets/aci_bd_to_l3out/tasks/main.yml @@ -186,11 +186,21 @@ <<: *aci_bd_present state: absent + - name: delete bd_2 - cleanup before ending tests + cisco.aci.aci_bd: + <<: *aci_bd_present_2 + state: absent + - name: delete l3out - cleanup before ending tests cisco.aci.aci_l3out: <<: *aci_l3_out_present state: absent + - name: delete l3out_2 - cleanup before ending tests + cisco.aci.aci_l3out: + <<: *aci_l3_out_present_2 + state: absent + - name: delete vrf - cleanup before ending tests cisco.aci.aci_vrf: <<: *aci_vrf_present diff --git a/tests/integration/targets/aci_bd_to_netflow_monitor_policy/aliases b/tests/integration/targets/aci_bd_to_netflow_monitor_policy/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_bd_to_netflow_monitor_policy/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_bd_to_netflow_monitor_policy/tasks/main.yml b/tests/integration/targets/aci_bd_to_netflow_monitor_policy/tasks/main.yml new file mode 100644 index 000000000..9a7a44d16 --- /dev/null +++ b/tests/integration/targets/aci_bd_to_netflow_monitor_policy/tasks/main.yml @@ -0,0 +1,191 @@ +# Test code for the ACI modules +# Copyright: (c) 2024, Samita Bhattacharjee (@samitab) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Test that we have an ACI APIC host, ACI username and ACI password + ansible.builtin.fail: + msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' + when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined + +- name: Set vars + ansible.builtin.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 the ansible_tenant + cisco.aci.aci_tenant: &aci_tenant_absent + <<: *aci_info + state: absent + tenant: ansible_test + +- name: Verify Cloud and Non-Cloud Sites in use. + ansible.builtin.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 + - name: Create tenant + cisco.aci.aci_tenant: &aci_tenant_present + <<: *aci_tenant_absent + state: present + + - name: Create first netflow monitor policy + cisco.aci.aci_netflow_monitor_policy: + <<: *aci_tenant_absent + netflow_monitor_policy: ansible_netflow_monitor_policy + state: present + + - name: Create second netflow monitor policy + cisco.aci.aci_netflow_monitor_policy: + <<: *aci_tenant_absent + netflow_monitor_policy: ansible_netflow_monitor_policy_2 + state: present + + - name: Create first bd + cisco.aci.aci_bd: &aci_bd_present + <<: *aci_tenant_present + bd: anstest + + - name: Create second bd + cisco.aci.aci_bd: &aci_bd_present_2 + <<: *aci_tenant_present + bd: anstest_2 + + - name: Ensure first binding bd to netflow monitor policy does not exist + cisco.aci.aci_bd_to_netflow_monitor_policy: &aci_bd_to_netflow_monitor_policy_absent + <<: *aci_bd_present + netflow_monitor_policy: ansible_netflow_monitor_policy + filter_type: ipv4 + state: absent + + - name: Ensure second binding bd to netflow monitor policy does not exist + cisco.aci.aci_bd_to_netflow_monitor_policy: &aci_bd_to_netflow_monitor_policy_absent_2 + <<: *aci_bd_present_2 + netflow_monitor_policy: ansible_netflow_monitor_policy_2 + filter_type: ipv6 + state: absent + + - name: Bind bd to netflow monitor policy - first binding (check_mode) + cisco.aci.aci_bd_to_netflow_monitor_policy: &aci_bd_to_netflow_monitor_policy_present + <<: *aci_bd_to_netflow_monitor_policy_absent + state: present + check_mode: true + register: cm_bd_to_netflow_monitor_policy + + - name: Bind bd to netflow monitor policy - first binding (normal_mode) + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + register: nm_bd_to_netflow_monitor_policy + + - name: Bind bd to netflow monitor policy again - testing idempotency + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + register: bd_to_netflow_monitor_policy_idempotency + + - name: Bind bd to netflow monitor policy again - second binding + cisco.aci.aci_bd_to_netflow_monitor_policy: &aci_bd_to_netflow_monitor_policy_present_2 + <<: *aci_bd_to_netflow_monitor_policy_absent_2 + state: present + register: nm_bd_to_netflow_monitor_policy_2 + + - name: Asserts for creation tasks + ansible.builtin.assert: + that: + - cm_bd_to_netflow_monitor_policy is changed + - cm_bd_to_netflow_monitor_policy.previous == [] + - cm_bd_to_netflow_monitor_policy.current == [] + - cm_bd_to_netflow_monitor_policy.proposed.fvRsBDToNetflowMonitorPol.attributes.dn == "uni/tn-ansible_test/BD-anstest/rsBDToNetflowMonitorPol-[ansible_netflow_monitor_policy]-ipv4" + - cm_bd_to_netflow_monitor_policy.proposed.fvRsBDToNetflowMonitorPol.attributes.tnNetflowMonitorPolName == "ansible_netflow_monitor_policy" + - nm_bd_to_netflow_monitor_policy is changed + - nm_bd_to_netflow_monitor_policy.current.0.fvRsBDToNetflowMonitorPol.attributes.dn == "uni/tn-ansible_test/BD-anstest/rsBDToNetflowMonitorPol-[ansible_netflow_monitor_policy]-ipv4" + - nm_bd_to_netflow_monitor_policy.current.0.fvRsBDToNetflowMonitorPol.attributes.tnNetflowMonitorPolName == "ansible_netflow_monitor_policy" + - bd_to_netflow_monitor_policy_idempotency is not changed + - bd_to_netflow_monitor_policy_idempotency.current == bd_to_netflow_monitor_policy_idempotency.previous + - bd_to_netflow_monitor_policy_idempotency.sent == {} + - nm_bd_to_netflow_monitor_policy_2 is changed + - nm_bd_to_netflow_monitor_policy_2.current.0.fvRsBDToNetflowMonitorPol.attributes.dn == "uni/tn-ansible_test/BD-anstest_2/rsBDToNetflowMonitorPol-[ansible_netflow_monitor_policy_2]-ipv6" + - nm_bd_to_netflow_monitor_policy_2.current.0.fvRsBDToNetflowMonitorPol.attributes.tnNetflowMonitorPolName == "ansible_netflow_monitor_policy_2" + + - name: Query all bds bound to netflow monitor policies + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_tenant_present + state: query + output_level: debug + register: query_all_bd_to_netflow_monitor_policy + + - name: Query first bd bound to first netflow monitor policy + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + state: query + output_level: debug + register: query_first_bd_to_netflow_monitor_policy + + - name: Asserts query tasks + ansible.builtin.assert: + that: + - query_all_bd_to_netflow_monitor_policy is not changed + - '"fvRsBDToNetflowMonitorPol" in query_all_bd_to_netflow_monitor_policy.filter_string' + - query_all_bd_to_netflow_monitor_policy.current.0.fvTenant.children | length >= 2 + - query_all_bd_to_netflow_monitor_policy.current.0.fvTenant.children.0.fvBD.attributes.name == "anstest_2" + - query_all_bd_to_netflow_monitor_policy.current.0.fvTenant.children.0.fvBD.children.0.fvRsBDToNetflowMonitorPol.attributes.tRn == "monitorpol-ansible_netflow_monitor_policy_2" + - query_all_bd_to_netflow_monitor_policy.current.0.fvTenant.children.1.fvBD.attributes.name == "anstest" + - query_all_bd_to_netflow_monitor_policy.current.0.fvTenant.children.1.fvBD.children.0.fvRsBDToNetflowMonitorPol.attributes.tRn == "monitorpol-ansible_netflow_monitor_policy" + - query_first_bd_to_netflow_monitor_policy is not changed + - '"tn-ansible_test/BD-anstest/rsBDToNetflowMonitorPol-[ansible_netflow_monitor_policy]-ipv4.json" in query_first_bd_to_netflow_monitor_policy.url' + + - name: Unbind bd to netflow monitor policy - first binding (check_mode) + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + state: absent + check_mode: true + register: cm_unbind_bd_to_netflow_monitor_policy + + - name: Unbind bd to netflow_monitor_policy - first binding (normal_mode) + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + state: absent + register: nm_unbind_bd_to_netflow_monitor_policy + + - name: Unbind bd to netflow_monitor_policy again - testing idempotency + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present + state: absent + register: unbind_bd_to_netflow_monitor_policy_idempotency + + - name: Unbind bd to netflow_monitor_policy - second binding + cisco.aci.aci_bd_to_netflow_monitor_policy: + <<: *aci_bd_to_netflow_monitor_policy_present_2 + state: absent + register: nm_unbind_bd_to_netflow_monitor_policy_2 + + - name: Asserts for deletion tasks + ansible.builtin.assert: + that: + - cm_unbind_bd_to_netflow_monitor_policy is changed + - cm_unbind_bd_to_netflow_monitor_policy.current == cm_unbind_bd_to_netflow_monitor_policy.previous + - cm_unbind_bd_to_netflow_monitor_policy.proposed == {} + - nm_unbind_bd_to_netflow_monitor_policy is changed + - nm_unbind_bd_to_netflow_monitor_policy.previous != [] + - nm_unbind_bd_to_netflow_monitor_policy.proposed == {} + - nm_unbind_bd_to_netflow_monitor_policy.current == [] + - nm_unbind_bd_to_netflow_monitor_policy.previous == cm_unbind_bd_to_netflow_monitor_policy.current + - unbind_bd_to_netflow_monitor_policy_idempotency is not changed + - unbind_bd_to_netflow_monitor_policy_idempotency.proposed == {} + - unbind_bd_to_netflow_monitor_policy_idempotency.current == [] + - unbind_bd_to_netflow_monitor_policy_idempotency.previous == [] + - nm_unbind_bd_to_netflow_monitor_policy_2 is changed + - nm_unbind_bd_to_netflow_monitor_policy_2.previous != [] + - nm_unbind_bd_to_netflow_monitor_policy_2.current == [] + + - name: Delete tenant - cleanup before ending tests + cisco.aci.aci_tenant: + <<: *aci_tenant_present + state: absent