From 2873077d1ffbe1eaba4bae5370bc84357100545a Mon Sep 17 00:00:00 2001 From: Faiz Mohammad Date: Thu, 24 Oct 2024 19:32:59 +0530 Subject: [PATCH 01/16] [minor change] New module for node_mgmt_epg to contract binding --- .../modules/aci_node_mgmt_epg_to_contract.py | 366 ++++++++++++++ .../aci_node_mgmt_epg_to_contract/aliases | 2 + .../tasks/main.yml | 466 ++++++++++++++++++ 3 files changed, 834 insertions(+) create mode 100644 plugins/modules/aci_node_mgmt_epg_to_contract.py create mode 100644 tests/integration/targets/aci_node_mgmt_epg_to_contract/aliases create mode 100644 tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py new file mode 100644 index 000000000..519a80a81 --- /dev/null +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -0,0 +1,366 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) +# Copyright: (c) 2023, Akini Ross (@akinross) +# 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_epg_to_contract +short_description: Bind EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and fv:RsIntraEpg) +description: +- Bind EPGs to Contracts on Cisco ACI fabrics. +notes: +- The C(tenant), C(app_profile), C(EPG), and C(Contract) used must exist before using this module in your playbook. + The M(cisco.aci.aci_tenant), M(cisco.aci.aci_ap), M(cisco.aci.aci_epg), and M(cisco.aci.aci_contract) modules can be used for this. +options: + ap: + description: + - Name of an existing application network profile, that will contain the EPGs. + type: str + aliases: [ app_profile, app_profile_name ] + contract: + description: + - The name of the contract or contract interface. + type: str + aliases: [ contract_name, contract_interface ] + contract_type: + description: + - Determines the type of the Contract. + type: str + required: true + choices: [ consumer, provider, taboo, interface, intra_epg ] + epg: + description: + - The name of the end point group. + type: str + aliases: [ epg_name ] + priority: + description: + - QoS class. + - The APIC defaults to C(unspecified) when unset during creation. + type: str + choices: [ level1, level2, level3, level4, level5, level6, unspecified ] + provider_match: + description: + - The matching algorithm for Provided Contracts. + - The APIC defaults to C(at_least_one) when unset during creation. + type: str + choices: [ all, at_least_one, at_most_one, none ] + contract_label: + description: + - Contract label to match + type: str + subject_label: + description: + - Subject label to match + type: str + 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 + tenant: + description: + - Name of an existing tenant. + type: str + aliases: [ tenant_name ] +extends_documentation_fragment: +- cisco.aci.aci +- cisco.aci.annotation + +seealso: +- module: cisco.aci.aci_ap +- module: cisco.aci.aci_epg +- module: cisco.aci.aci_contract +- name: APIC Management Information Model reference + description: More information about the internal APIC classes B(fv:RsCons), B(fv:RsProv), B(fv:RsProtBy), B(fv:RsConsIf), and B(fv:RsIntraEpg). + link: https://developer.cisco.com/docs/apic-mim-ref/ +author: +- Jacob McGill (@jmcgill298) +- Akini Ross (@akinross) +""" + +EXAMPLES = r""" +- name: Add a new contract to EPG binding + cisco.aci.aci_inbepg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + tenant: mgmt + epg: anstest + contract: anstest_http + contract_type: provider + state: present + delegate_to: localhost + +- name: Remove an existing contract to EPG binding + cisco.aci.aci_inbepg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + tenant: mgmt + epg: anstest + contract: anstest_http + contract_type: provider + state: absent + delegate_to: localhost + +- name: Query a specific contract to EPG binding + cisco.aci.aci_inbepg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + tenant: anstest + epg: anstest + contract: anstest_http + contract_type: provider + state: query + delegate_to: localhost + register: query_result + +- name: Query all provider contract to EPG bindings + cisco.aci.aci_inbepg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + contract_type: provider + 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 +from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING + + +def main(): + argument_spec = aci_argument_spec() + argument_spec.update(aci_annotation_spec()) + argument_spec.update( + contract_type=dict(type="str", choices=["consumer", "provider", "taboo", "interface"], required=True), + epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True) + epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects + contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects + priority=dict(type="str", default="unspecified", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]), + provider_match=dict(type="str", choices=["all", "at_least_one", "at_most_one", "none"]), + state=dict(type="str", default="present", choices=["absent", "present", "query"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "absent", ["epg", "contract"]], + ["state", "present", ["epg","contract"]], + ] + ) + + epg_type = module.params.get("type") + contract = module.params.get("contract") + contract_type = module.params.get("contract_type") + epg = module.params.get("epg") + priority = module.params.get("priority") + provider_match = module.params.get("provider_match") + state = module.params.get("state") + + if epg_type=="in_band": + aci_class = ACI_CLASS_MAPPING[contract_type]["class"] + aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"] + aci_name = ACI_CLASS_MAPPING[contract_type]["name"] + class_config={"matchT": provider_match, "prio": priority, aci_name: contract} + + if provider_match is not None: + provider_match = PROVIDER_MATCH_MAPPING[provider_match] + + if contract_type != "provider" and provider_match is not None: + module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts") + + elif epg_type=="out_of_band": + aci_class = "mgmtRsOoBProv" + aci_rn = "rsooBProv" + aci_name = "tnVzOOBBrCPName" + class_config={"prio": priority, aci_name: contract} + + if contract_type != "provider": + module.fail_json(msg="out_of_band EPG only supports Provider contract attachment.") + + + else: + module.fail_json(msg="epg_type can either be \"in_band\" or \"out_of_band\" only.") + + + class_Map = { + "in_band": [dict(epg_class="mgmtInB", + epg_rn="inb-{0}")], + + "out_of_band": [dict(epg_class="mgmtOoB", + epg_rn="oob-{0}" + )] + } + + aci = ACIModule(module) + aci.construct_url( + root_class=dict( + aci_class="fvTenant", + aci_rn="tn-mgmt", + module_object="mgmt", + target_filter={"name": "mgmt"}, + ), + subclass_1=dict( + aci_class="mgmtMgmtP", + aci_rn="mgmtp-default", + module_object="default", + target_filter={"name": "default"}, + ), + subclass_2=dict( + aci_class=class_Map[epg_type][0]["epg_class"], + aci_rn=class_Map[epg_type][0]["epg_rn"].format(epg), + module_object=epg, + target_filter={"name": epg}, + ), + subclass_3=dict( + aci_class=aci_class, + aci_rn="{0}{1}".format(aci_rn, contract), + module_object=contract, + target_filter={aci_name: contract}, + ) + ) + + aci.get_existing() + + if state == "present": + child_configs = [] + aci.payload( + aci_class=aci_class, + class_config=class_config, + child_configs=child_configs, + ) + + aci.get_diff(aci_class=aci_class) + + aci.post_config() + + elif state == "absent": + aci.delete_config() + + aci.exit_json() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/aliases b/tests/integration/targets/aci_node_mgmt_epg_to_contract/aliases new file mode 100644 index 000000000..209b793f9 --- /dev/null +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/aliases @@ -0,0 +1,2 @@ +# No ACI simulator yet, so not enabled +# unsupported diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml new file mode 100644 index 000000000..b0a04514d --- /dev/null +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -0,0 +1,466 @@ +# Test code for the ACI modules +# Copyright: (c) 2017, Jacob McGill (@jmcgill298) +# Copyright: (c) 2023, Akini Ross (@akinross) + +# 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: Verify Cloud and Non-Cloud Sites in use. + ansible.builtin.include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml + +- name: remove tenant for tests to kick off + cisco.aci.aci_tenant: &aci_tenant_present + 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: debug + tenant: mgmt + state: present + register: tenant_present + + +- 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: creating new OOB EPG for testing + cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_present + 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") }}' + epg: anstest_oob + type: out_of_band + state: present + + - name: creating new INB EPG for testing + cisco.aci.aci_node_mgmt_epg: &aci_inb_epg_present + <<: *aci_oob_epg_present + epg: anstest_inb + type: in_band + bd: inb + encap: vlan-1604 + + - name: ensure inband contract exists for tests to kick off + cisco.aci.aci_contract: &inb_contract_present + 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") }}' + tenant: mgmt + contract: "{{ item }}" + with_items: ["aci_inb_http", "aci_inb_https", "anstest_inb_db", "anstest_inb_no_previous", "anstest_inb_no_lb_no_v"] + + - name: ensure out-of-band contract exists for tests to kick off + cisco.aci.aci_oob_contract: &oob_contract_present + 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") }}' + contract: "{{ item }}" + with_items: ["aci_oob_http", "aci_oob_https", "anstest_oob_db", "anstest_oob_no_previous", "anstest_oob_no_lb_no_v"] + + - name: bind inb contract to inband epg - check mode works + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present + <<: *aci_oob_epg_present + contract_type: provider + contract: aci_inb_http + epg: anstest_inb + type: in_band + check_mode: true + register: provide_present_check_mode + + - name: bind inb contract to inband epg - provide works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: provide_present + + - name: bind inb contract to epg - consume works + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present + <<: *aci_inb_epg_provide_present + contract_type: consumer + contract: anstest_inb_db + register: consume_present + + - name: bind inb contract to inband epg - add additional contract + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + provider_match: at_most_one" + register: provide_present2 + + - name: bind inb contract to epg - idempotency works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: idempotent_present + + - name: bind oob contract to out-of-band epg - check mode works + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present + <<: *aci_oob_epg_present + contract_type: provider + contract: aci_inb_http + epg: anstest_inb + type: in_band + check_mode: true + register: provide_present_check_mode + + - name: bind oob contract to out-of-band epg - provide works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: provide_present + + - name: bind inb contract to epg - consume works + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present + <<: *aci_inb_epg_provide_present + contract_type: consumer + contract: anstest_inb_db + register: consume_present + + - name: bind inb contract to inband epg - add additional contract + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + provider_match: at_most_one" + register: provide_present2 + + - name: bind inb contract to epg - idempotency works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: idempotent_present + + - name: missing param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_tenant_present + contract_type: provider + ignore_errors: true + register: missing_param_present + + - name: missing required param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_tenant_present + ignore_errors: true + register: missing_required_present + + - name: incompatible param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_present + provider_match: all + ignore_errors: true + register: incompatible_present + + - name: present assertions + ansible.builtin.assert: + that: + - provide_present_check_mode is changed + - provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' + - provide_present is changed + - provide_present.sent == provide_present_check_mode.sent + - provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - provide_present.previous == [] + - consume_present is changed + - consume_present.previous == [] + - consume_present.sent.fvRsCons.attributes.tnVzBrCPName == 'anstest_inb_db' + - provide_present2 is changed + - provide_present2.previous == [] + - missing_param_present is failed + - 'missing_param_present.msg == "state is present but all of the following are missing: ap, contract, epg"' + - missing_required_present is failed + - 'missing_required_present.msg == "missing required arguments: contract_type"' + - incompatible_present is failed + - incompatible_present.msg == "the 'provider_match' is only configurable for Provided Contracts" + + - name: bind taboo contract to inband epg + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + contract_type: taboo + register: taboo_present + + - name: bind interface contract to epg + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + contract_type: interface + register: interface_present + + - name: present assertions for taboo, interface and intra_epg contract types + assert: + that: + - taboo_present is changed + - taboo_present.previous == [] + - taboo_present.current.0.fvRsProtBy.attributes.tnVzTabooName == 'aci_inb_https' + - interface_present is changed + - interface_present.previous == [] + - interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'aci_inb_https' + + # TEST NO PREVIOUS + - name: create epg contract to epg with no previous (check mode) + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_to_contract_no_previous + <<: *aci_inb_epg_consume_present + contract: anstest_inb_no_previous + no_previous: true + check_mode: true + register: epg_to_contract_present_no_previous_cm + + - name: create epg contract to epg with no previous + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_pg_to_contract_no_previous + register: epg_to_contract_present_no_previous + + - name: create epg contract to epg with no previous again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_previous + register: epg_to_contract_present_no_previous_again + + - name: update epg contract to epg with no previous + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_previous + priority: level1 + register: update_epg_to_contract_present_no_previous + + - name: delete epg contract to epg with no previous + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_previous + state: absent + register: delete_epg_to_contract_present_no_previous + + - name: delete epg contract to epg with no previous again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_previous + state: absent + register: delete_epg_to_contract_present_no_previous_again + + - name: no previous asserts + ansible.builtin.assert: + that: + - epg_to_contract_present_no_previous_cm is changed + - epg_to_contract_present_no_previous_cm.current == [] + - epg_to_contract_present_no_previous_cm.previous == [] + - epg_to_contract_present_no_previous_cm.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" + - epg_to_contract_present_no_previous_cm.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" + - epg_to_contract_present_no_previous is changed + - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" + - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" + - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.prio == "unspecified" + - epg_to_contract_present_no_previous.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" + - epg_to_contract_present_no_previous.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" + - epg_to_contract_present_no_previous.previous == [] + - epg_to_contract_present_no_previous_again is changed + - epg_to_contract_present_no_previous_again.current == epg_to_contract_present_no_previous.current + - epg_to_contract_present_no_previous_again.proposed == epg_to_contract_present_no_previous.proposed + - epg_to_contract_present_no_previous_again.previous == [] + - update_epg_to_contract_present_no_previous is changed + - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" + - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" + - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.prio == "level1" + - delete_epg_to_contract_present_no_previous is changed + - delete_epg_to_contract_present_no_previous.current == [] + - delete_epg_to_contract_present_no_previous.previous == [] + - delete_epg_to_contract_present_no_previous.proposed == {} + - delete_epg_to_contract_present_no_previous_again is changed + - delete_epg_to_contract_present_no_previous_again.current == [] + - delete_epg_to_contract_present_no_previous_again.previous == [] + - delete_epg_to_contract_present_no_previous_again.proposed == {} + + # TEST NO PREVIOUS & NO VERIFICATION + - name: create epg contract to epg with no previous & no verify (check mode) + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_to_contract_no_lb_no_v + <<: *aci_inb_epg_consume_present + contract: anstest_inb_no_lb_no_v + no_previous: true + no_verify: true + check_mode: true + register: epg_to_contract_present_no_lb_no_v_cm + + - name: create epg contract to epg with no look bac & no verify + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_lb_no_v + register: epg_to_contract_present_no_lb_no_v + + - name: create epg contract to epg with no previous again & no verify + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_lb_no_v + register: epg_to_contract_present_no_lb_no_v_again + + - name: update epg contract to epg with no previous & no verify + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_lb_no_v + priority: level1 + register: update_epg_to_contract_present_no_lb_no_v + + - name: delete epg contract to epg with no previous & no verify + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_lb_no_v + state: absent + register: delete_epg_to_contract_present_no_lb_no_v + + - name: delete epg contract to epg with no previous again & no verify + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_to_contract_no_lb_no_v + state: absent + register: delete_epg_to_contract_present_no_lb_no_v_again + + - name: no previous & no verify asserts + ansible.builtin.assert: + that: + - epg_to_contract_present_no_lb_no_v_cm is changed + - epg_to_contract_present_no_lb_no_v_cm.current.0 == epg_to_contract_present_no_lb_no_v_cm.proposed + - epg_to_contract_present_no_lb_no_v_cm.previous == [] + - epg_to_contract_present_no_lb_no_v_cm.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_lb_no_v" + - epg_to_contract_present_no_lb_no_v_cm.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" + - epg_to_contract_present_no_lb_no_v is changed + - epg_to_contract_present_no_lb_no_v.current.0 == epg_to_contract_present_no_lb_no_v.proposed + - epg_to_contract_present_no_lb_no_v.previous == [] + - epg_to_contract_present_no_lb_no_v_again is changed + - epg_to_contract_present_no_lb_no_v_again.current == epg_to_contract_present_no_lb_no_v.current + - epg_to_contract_present_no_lb_no_v_again.proposed == epg_to_contract_present_no_lb_no_v.proposed + - epg_to_contract_present_no_lb_no_v_again.previous == [] + - update_epg_to_contract_present_no_lb_no_v is changed + - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_lb_no_v" + - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" + - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.prio == "level1" + - delete_epg_to_contract_present_no_lb_no_v is changed + - delete_epg_to_contract_present_no_lb_no_v.current == [] + - delete_epg_to_contract_present_no_lb_no_v.previous == [] + - delete_epg_to_contract_present_no_lb_no_v.proposed == {} + - delete_epg_to_contract_present_no_lb_no_v_again is changed + - delete_epg_to_contract_present_no_lb_no_v_again.current == [] + - delete_epg_to_contract_present_no_lb_no_v_again.previous == [] + - delete_epg_to_contract_present_no_lb_no_v_again.proposed == {} + + - name: get binding + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present2 + state: query + register: query_provide_contract + + - name: get binding + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_present + state: query + register: query_consume_contract + + - name: get all bindings + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_tenant_present + state: query + tenant: "{{ fakevar | default(omit) }}" + contract_type: provider + epg_type: in_band + register: query_all + + - name: missing required param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_tenant_present + tenant: "{{ fakevar | default(omit) }}" + state: query + epg_type: in_band + ignore_errors: true + register: missing_required_query + + - name: query assertions + ansible.builtin.assert: + that: + - query_provide_contract is not changed + - query_provide_contract.current != [] + - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rsprov-aci_inb_https.json" in query_provide_contract.url' + - query_consume_contract is not changed + - query_consume_contract.current != [] + - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_db.json" in query_consume_contract.url' + - query_all is not changed + - '"class/fvRsProv.json" in query_all.url' + - missing_required_query is failed + - 'missing_required_query.msg == "missing required arguments: contract_type"' + + - name: delete consume binding - check mode works + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_absent + <<: *aci_inb_epg_consume_present + state: absent + check_mode: true + register: consume_absent_check_mode + + - name: delete consume binding - deletion works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_absent + register: consume_absent + + - name: delete provide binding - deletion works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + state: absent + register: provide_absent + + - name: delete provide binding - deletion works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present2 + state: absent + register: provide_absent2 + + - name: delete consume binding - idempotency works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_absent + register: consume_absent_idempotent + + - name: missing param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_absent + contract: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: missing_param_absent + + - name: missing required param - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_absent + contract_type: "{{ fakevar | default(omit) }}" + ignore_errors: true + register: missing_required_absent + + - name: absent assertions + ansible.builtin.assert: + that: + - consume_absent_check_mode is changed + - consume_absent_check_mode.previous.0.fvRsCons is defined + - consume_absent is changed + - consume_absent.previous == consume_absent_check_mode.previous + - provide_absent is changed + - provide_absent.previous.0.fvRsProv is defined + - provide_absent2 is changed + - consume_absent_idempotent is not changed + - consume_absent_idempotent.previous == [] + - missing_param_absent is failed + - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' + - missing_required_absent is failed + - 'missing_required_absent.msg == "missing required arguments: contract_type"' + + - name: cleanup contracts + cisco.aci.aci_contract: + <<: *aci_tenant_present + state: absent + contract: "{{ item }}" + with_items: ["aci_inb_http", "aci_inb_https", "anstest_inb_db", "anstest_inb_no_previous", "anstest_inb_no_lb_no_v"] + + - name: cleanup OOB epg + cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_absent + <<: *aci_oob_epg_present + state: absent + + - name: cleanup INB epg + cisco.aci.aci_node_mgmt_epg: + <<: *aci_oob_epg_absent + epg: anstest_inb + type: in_band From b9278dab83f9587a9f8751fc23c3befbc2b23cab Mon Sep 17 00:00:00 2001 From: Faiz Mohammad Date: Sun, 24 Nov 2024 21:47:08 +0530 Subject: [PATCH 02/16] fixed syntax in aci_node_mgmt_epg_to_contract test yml file --- .../modules/aci_node_mgmt_epg_to_contract.py | 2 +- .../tasks/main.yml | 471 +++++++----------- 2 files changed, 173 insertions(+), 300 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index 519a80a81..f328bac7f 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -254,7 +254,7 @@ def main(): argument_spec.update(aci_annotation_spec()) argument_spec.update( contract_type=dict(type="str", choices=["consumer", "provider", "taboo", "interface"], required=True), - epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True) + epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True), epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects priority=dict(type="str", default="unspecified", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]), diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index b0a04514d..185f8ed6f 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -1,6 +1,5 @@ # Test code for the ACI modules -# Copyright: (c) 2017, Jacob McGill (@jmcgill298) -# Copyright: (c) 2023, Akini Ross (@akinross) +# Copyright: (c) 2024, Faiz Mohammad (@faizmoh) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -9,181 +8,165 @@ 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: Verify Cloud and Non-Cloud Sites in use. - ansible.builtin.include_tasks: ../../../../../../integration/targets/aci_cloud_provider/tasks/main.yml - -- name: remove tenant for tests to kick off - cisco.aci.aci_tenant: &aci_tenant_present - host: "{{ aci_hostname }}" - username: "{{ aci_username }}" - password: "{{ aci_password }}" +# SET VARS +- 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: debug - tenant: mgmt - state: present - register: tenant_present + output_level: '{{ aci_output_level | default("info") }}' +- name: Query system information + cisco.aci.aci_system: + <<: *aci_info + id: 1 + state: query + register: version + +- 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: creating new OOB EPG for testing cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_present - 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") }}' + <<: *aci_info epg: anstest_oob type: out_of_band state: present - name: creating new INB EPG for testing cisco.aci.aci_node_mgmt_epg: &aci_inb_epg_present - <<: *aci_oob_epg_present + <<: *aci_info epg: anstest_inb type: in_band bd: inb encap: vlan-1604 + state: present - - name: ensure inband contract exists for tests to kick off - cisco.aci.aci_contract: &inb_contract_present - 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") }}' - tenant: mgmt - contract: "{{ item }}" - with_items: ["aci_inb_http", "aci_inb_https", "anstest_inb_db", "anstest_inb_no_previous", "anstest_inb_no_lb_no_v"] - - - name: ensure out-of-band contract exists for tests to kick off - cisco.aci.aci_oob_contract: &oob_contract_present - 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") }}' - contract: "{{ item }}" - with_items: ["aci_oob_http", "aci_oob_https", "anstest_oob_db", "anstest_oob_no_previous", "anstest_oob_no_lb_no_v"] - + # CREATE INB - name: bind inb contract to inband epg - check mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present - <<: *aci_oob_epg_present + <<: *aci_info contract_type: provider contract: aci_inb_http epg: anstest_inb type: in_band + state: present check_mode: true - register: provide_present_check_mode + register: inb_provide_present_check_mode - name: bind inb contract to inband epg - provide works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present - register: provide_present + register: inb_provide_present - name: bind inb contract to epg - consume works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present <<: *aci_inb_epg_provide_present contract_type: consumer contract: anstest_inb_db - register: consume_present + register: inb_consume_present - name: bind inb contract to inband epg - add additional contract cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 <<: *aci_inb_epg_provide_present contract: aci_inb_https - provider_match: at_most_one" - register: provide_present2 + provider_match: at_most_one + register: inb_provide_present2 - name: bind inb contract to epg - idempotency works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present - register: idempotent_present + register: inb_idempotent_present + + # CREATE OOB - name: bind oob contract to out-of-band epg - check mode works - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present - <<: *aci_oob_epg_present + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present + <<: *aci_info contract_type: provider - contract: aci_inb_http - epg: anstest_inb - type: in_band + contract: aci_oob_http + epg: anstest_oob + type: out_of_band + state: present check_mode: true - register: provide_present_check_mode + register: oob_provide_present_check_mode - name: bind oob contract to out-of-band epg - provide works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present - register: provide_present - - - name: bind inb contract to epg - consume works - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present - <<: *aci_inb_epg_provide_present - contract_type: consumer - contract: anstest_inb_db - register: consume_present + <<: *aci_oob_epg_provide_present + register: oob_provide_present - - name: bind inb contract to inband epg - add additional contract - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 - <<: *aci_inb_epg_provide_present - contract: aci_inb_https - provider_match: at_most_one" - register: provide_present2 + - name: bind oob contract to out-of-band epg aci- add additional contract + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present2 + <<: *aci_oob_epg_provide_present + contract: aci_oob_https + provider_match: at_most_one + register: oob_provide_present2 - - name: bind inb contract to epg - idempotency works + - name: bind oob contract to epg - idempotency works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present - register: idempotent_present + <<: *aci_oob_epg_provide_present + register: oob_idempotent_present + #MISSING PARAMS - name: missing param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_tenant_present - contract_type: provider + <<: *aci_oob_epg_provide_present + epg: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_param_present - name: missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_tenant_present + <<: *aci_oob_epg_provide_present + contract_type: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_required_present - name: incompatible param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_consume_present - provider_match: all + <<: *aci_oob_epg_provide_present + contract_type: consumer ignore_errors: true register: incompatible_present - name: present assertions ansible.builtin.assert: that: - - provide_present_check_mode is changed - - provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' - - provide_present is changed - - provide_present.sent == provide_present_check_mode.sent - - provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - - provide_present.previous == [] - - consume_present is changed - - consume_present.previous == [] - - consume_present.sent.fvRsCons.attributes.tnVzBrCPName == 'anstest_inb_db' - - provide_present2 is changed - - provide_present2.previous == [] - - missing_param_present is failed - - 'missing_param_present.msg == "state is present but all of the following are missing: ap, contract, epg"' - - missing_required_present is failed - - 'missing_required_present.msg == "missing required arguments: contract_type"' - - incompatible_present is failed - - incompatible_present.msg == "the 'provider_match' is only configurable for Provided Contracts" - + - inb_provide_present_check_mode is changed + - inb_provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' + - inb_provide_present is changed + - inb_provide_present.sent == provide_present_check_mode.sent + - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - inb_provide_present.previous == [] + - inb_consume_present is changed + - inb_consume_present.previous == [] + - inb_consume_present.sent.fvRsCons.attributes.tnVzBrCPName == 'anstest_inb_db' + - inb_provide_present2 is changed + - inb_provide_present2.previous == [] + - oob_provide_present_check_mode is changed + - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_inb_http' + - oob_provide_present is changed + - oob_provide_present.sent == provide_present_check_mode.sent + - oob_provide_present.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' + - oob_provide_present.previous == [] + - oob_provide_present2 is changed + - oob_provide_present2.previous == [] + - missing_param_present is failed + - 'missing_param_present.msg == "state is present but all of the following are missing: epg"' + - missing_required_present is failed + - 'missing_required_present.msg == "missing required arguments: contract_type"' + - incompatible_present is failed + - incompatible_present.msg == "out_of_band EPG only supports Provider contract attachment." + + #TABOO/INTERFACE - name: bind taboo contract to inband epg cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present @@ -191,231 +174,124 @@ contract_type: taboo register: taboo_present - - name: bind interface contract to epg + - name: bind interface contract to inband epg cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present contract: aci_inb_https contract_type: interface register: interface_present - - name: present assertions for taboo, interface and intra_epg contract types + - name: present assertions for taboo, and interface contract types assert: that: - - taboo_present is changed - - taboo_present.previous == [] - - taboo_present.current.0.fvRsProtBy.attributes.tnVzTabooName == 'aci_inb_https' - - interface_present is changed - - interface_present.previous == [] - - interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'aci_inb_https' - - # TEST NO PREVIOUS - - name: create epg contract to epg with no previous (check mode) - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_to_contract_no_previous - <<: *aci_inb_epg_consume_present - contract: anstest_inb_no_previous - no_previous: true - check_mode: true - register: epg_to_contract_present_no_previous_cm - - - name: create epg contract to epg with no previous - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_pg_to_contract_no_previous - register: epg_to_contract_present_no_previous - - - name: create epg contract to epg with no previous again - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_previous - register: epg_to_contract_present_no_previous_again - - - name: update epg contract to epg with no previous + - taboo_present is changed + - taboo_present.previous == [] + - taboo_present.current.0.fvRsProtBy.attributes.tnVzTabooName == 'aci_inb_https' + - interface_present is changed + - interface_present.previous == [] + - interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'aci_inb_https' + + # QUERY + - name: get inb binding for provide cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_previous - priority: level1 - register: update_epg_to_contract_present_no_previous - - - name: delete epg contract to epg with no previous - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_previous - state: absent - register: delete_epg_to_contract_present_no_previous + <<: *aci_inb_epg_provide_present2 + state: query + register: query_inb_provide_contract - - name: delete epg contract to epg with no previous again + - name: get inb binding for consume cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_previous - state: absent - register: delete_epg_to_contract_present_no_previous_again - - - name: no previous asserts - ansible.builtin.assert: - that: - - epg_to_contract_present_no_previous_cm is changed - - epg_to_contract_present_no_previous_cm.current == [] - - epg_to_contract_present_no_previous_cm.previous == [] - - epg_to_contract_present_no_previous_cm.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" - - epg_to_contract_present_no_previous_cm.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" - - epg_to_contract_present_no_previous is changed - - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" - - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" - - epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.prio == "unspecified" - - epg_to_contract_present_no_previous.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" - - epg_to_contract_present_no_previous.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" - - epg_to_contract_present_no_previous.previous == [] - - epg_to_contract_present_no_previous_again is changed - - epg_to_contract_present_no_previous_again.current == epg_to_contract_present_no_previous.current - - epg_to_contract_present_no_previous_again.proposed == epg_to_contract_present_no_previous.proposed - - epg_to_contract_present_no_previous_again.previous == [] - - update_epg_to_contract_present_no_previous is changed - - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_previous" - - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" - - update_epg_to_contract_present_no_previous.current.0.fvRsCons.attributes.prio == "level1" - - delete_epg_to_contract_present_no_previous is changed - - delete_epg_to_contract_present_no_previous.current == [] - - delete_epg_to_contract_present_no_previous.previous == [] - - delete_epg_to_contract_present_no_previous.proposed == {} - - delete_epg_to_contract_present_no_previous_again is changed - - delete_epg_to_contract_present_no_previous_again.current == [] - - delete_epg_to_contract_present_no_previous_again.previous == [] - - delete_epg_to_contract_present_no_previous_again.proposed == {} - - # TEST NO PREVIOUS & NO VERIFICATION - - name: create epg contract to epg with no previous & no verify (check mode) - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_to_contract_no_lb_no_v <<: *aci_inb_epg_consume_present - contract: anstest_inb_no_lb_no_v - no_previous: true - no_verify: true - check_mode: true - register: epg_to_contract_present_no_lb_no_v_cm - - - name: create epg contract to epg with no look bac & no verify - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_lb_no_v - register: epg_to_contract_present_no_lb_no_v - - - name: create epg contract to epg with no previous again & no verify - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_lb_no_v - register: epg_to_contract_present_no_lb_no_v_again - - - name: update epg contract to epg with no previous & no verify - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_lb_no_v - priority: level1 - register: update_epg_to_contract_present_no_lb_no_v - - - name: delete epg contract to epg with no previous & no verify - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_lb_no_v - state: absent - register: delete_epg_to_contract_present_no_lb_no_v + state: query + register: query_inb_consume_contract - - name: delete epg contract to epg with no previous again & no verify + - name: get oob binding cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_to_contract_no_lb_no_v - state: absent - register: delete_epg_to_contract_present_no_lb_no_v_again - - - name: no previous & no verify asserts - ansible.builtin.assert: - that: - - epg_to_contract_present_no_lb_no_v_cm is changed - - epg_to_contract_present_no_lb_no_v_cm.current.0 == epg_to_contract_present_no_lb_no_v_cm.proposed - - epg_to_contract_present_no_lb_no_v_cm.previous == [] - - epg_to_contract_present_no_lb_no_v_cm.proposed.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_lb_no_v" - - epg_to_contract_present_no_lb_no_v_cm.proposed.fvRsCons.attributes.annotation == "orchestrator:ansible" - - epg_to_contract_present_no_lb_no_v is changed - - epg_to_contract_present_no_lb_no_v.current.0 == epg_to_contract_present_no_lb_no_v.proposed - - epg_to_contract_present_no_lb_no_v.previous == [] - - epg_to_contract_present_no_lb_no_v_again is changed - - epg_to_contract_present_no_lb_no_v_again.current == epg_to_contract_present_no_lb_no_v.current - - epg_to_contract_present_no_lb_no_v_again.proposed == epg_to_contract_present_no_lb_no_v.proposed - - epg_to_contract_present_no_lb_no_v_again.previous == [] - - update_epg_to_contract_present_no_lb_no_v is changed - - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.dn == "uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_no_lb_no_v" - - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.annotation == "orchestrator:ansible" - - update_epg_to_contract_present_no_lb_no_v.current.0.fvRsCons.attributes.prio == "level1" - - delete_epg_to_contract_present_no_lb_no_v is changed - - delete_epg_to_contract_present_no_lb_no_v.current == [] - - delete_epg_to_contract_present_no_lb_no_v.previous == [] - - delete_epg_to_contract_present_no_lb_no_v.proposed == {} - - delete_epg_to_contract_present_no_lb_no_v_again is changed - - delete_epg_to_contract_present_no_lb_no_v_again.current == [] - - delete_epg_to_contract_present_no_lb_no_v_again.previous == [] - - delete_epg_to_contract_present_no_lb_no_v_again.proposed == {} - - - name: get binding - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present2 + <<: *aci_oob_epg_provide_present2 state: query - register: query_provide_contract + register: query_oob_provide_contract - - name: get binding + - name: get all inband bindings cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_consume_present + <<: *aci_info state: query - register: query_consume_contract + epg_type: in_band + register: query_inb_all - - name: get all bindings + - name: get all out_of_band bindings cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_tenant_present + <<: *aci_info state: query - tenant: "{{ fakevar | default(omit) }}" - contract_type: provider - epg_type: in_band - register: query_all + epg_type: out_of_band + register: query_oob_all - name: missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_tenant_present - tenant: "{{ fakevar | default(omit) }}" + <<: *aci_info state: query - epg_type: in_band + epg_type: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_required_query - name: query assertions ansible.builtin.assert: that: - - query_provide_contract is not changed - - query_provide_contract.current != [] - - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rsprov-aci_inb_https.json" in query_provide_contract.url' - - query_consume_contract is not changed - - query_consume_contract.current != [] - - '"uni/tn-ansible_test/ap-anstest/epg-anstest/rscons-anstest_inb_db.json" in query_consume_contract.url' - - query_all is not changed - - '"class/fvRsProv.json" in query_all.url' - - missing_required_query is failed - - 'missing_required_query.msg == "missing required arguments: contract_type"' - - - name: delete consume binding - check mode works + - query_inb_provide_contract is not changed + - query_inb_provide_contract.current != [] + - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https.json" in query_provide_contract.url' + - query_inb_consume_contract is not changed + - query_inb_consume_contract.current != [] + - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db.json" in query_consume_contract.url' + - query_oob_provide_contract is not changed + - query_oob_provide_contract.current != [] + - '"uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsoobprov-aci_oob_https.json" in query_provide_contract.url' + - query_inb_all is not changed + - '"class/fvRsProv.json" in query_all.url' + - query_oob_all is not changed + - '"class/mgmtRsOoBProv.json" in query_all.url' + - missing_required_query is failed + - 'missing_required_query.msg == "missing required arguments: epg_type"' + + - name: delete inb consume binding - check mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_absent <<: *aci_inb_epg_consume_present state: absent check_mode: true register: consume_absent_check_mode - - name: delete consume binding - deletion works + - name: delete inb consume binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent - - name: delete provide binding - deletion works + - name: delete inb provide binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present state: absent - register: provide_absent + register: inb_provide_absent - - name: delete provide binding - deletion works + - name: delete inb provide binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: absent - register: provide_absent2 + register: inb_provide_absent2 - - name: delete consume binding - idempotency works + - name: delete inb consume binding - idempotency works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent_idempotent + - name: delete oob provide binding - deletion works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present + state: absent + register: oob_provide_absent_check_mode + + - name: delete provide binding - deletion works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present2 + state: absent + register: oob_provide_absent2 + - name: missing param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent @@ -426,41 +302,38 @@ - name: missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent - contract_type: "{{ fakevar | default(omit) }}" + epg_type: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_required_absent - name: absent assertions ansible.builtin.assert: that: - - consume_absent_check_mode is changed - - consume_absent_check_mode.previous.0.fvRsCons is defined - - consume_absent is changed - - consume_absent.previous == consume_absent_check_mode.previous - - provide_absent is changed - - provide_absent.previous.0.fvRsProv is defined - - provide_absent2 is changed - - consume_absent_idempotent is not changed - - consume_absent_idempotent.previous == [] - - missing_param_absent is failed - - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' - - missing_required_absent is failed - - 'missing_required_absent.msg == "missing required arguments: contract_type"' - - - name: cleanup contracts - cisco.aci.aci_contract: - <<: *aci_tenant_present - state: absent - contract: "{{ item }}" - with_items: ["aci_inb_http", "aci_inb_https", "anstest_inb_db", "anstest_inb_no_previous", "anstest_inb_no_lb_no_v"] - + - consume_absent_check_mode is changed + - consume_absent_check_mode.previous.0.fvRsCons is defined + - consume_absent is changed + - consume_absent.previous == consume_absent_check_mode.previous + - inb_provide_absent is changed + - inb_provide_absent.previous.0.fvRsProv is defined + - inb_provide_absent2 is changed + - consume_absent_idempotent is not changed + - consume_absent_idempotent.previous == [] + - oob_provide_absent is changed + - oob_provide_absent.previous.0.mgmtRsOoBProv is defined + - oob_provide_absent2 is changed + - missing_param_absent is failed + - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' + - missing_required_absent is failed + - 'missing_required_absent.msg == "missing required arguments: epg_type"' + + #CLEANUP - name: cleanup OOB epg cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_absent <<: *aci_oob_epg_present state: absent - name: cleanup INB epg - cisco.aci.aci_node_mgmt_epg: - <<: *aci_oob_epg_absent - epg: anstest_inb - type: in_band + cisco.aci.aci_node_mgmt_epg: + <<: *aci_oob_epg_absent + epg: anstest_inb + type: in_band From 5ab580aa869666d8c16e68a3dc50267ef7e4aa11 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Fri, 6 Dec 2024 18:18:30 +0530 Subject: [PATCH 03/16] fixed the provider match mapping --- plugins/modules/aci_node_mgmt_epg_to_contract.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index f328bac7f..c896801f8 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -248,6 +248,7 @@ 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.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING +provider_match_map = def main(): argument_spec = aci_argument_spec() @@ -277,6 +278,8 @@ def main(): epg = module.params.get("epg") priority = module.params.get("priority") provider_match = module.params.get("provider_match") + if provider_match is not None: + provider_match = PROVIDER_MATCH_MAPPING[provider_match] state = module.params.get("state") if epg_type=="in_band": From 5b7f5f46d8205887a42c008fae85902bd29f2e14 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Sun, 15 Dec 2024 12:47:00 +0530 Subject: [PATCH 04/16] fixed errors in node_mgmt_epg_to_contract test.yml file. Only query_contract.url does not exist remain --- .../modules/aci_node_mgmt_epg_to_contract.py | 18 ++---- .../tasks/main.yml | 59 ++++++++++++------- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index c896801f8..e97b9fc59 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -248,17 +248,15 @@ 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.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING -provider_match_map = - def main(): argument_spec = aci_argument_spec() argument_spec.update(aci_annotation_spec()) argument_spec.update( contract_type=dict(type="str", choices=["consumer", "provider", "taboo", "interface"], required=True), - epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True), + epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True), # required for querying as provider class for INB and OOB are different epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects - priority=dict(type="str", default="unspecified", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]), + priority=dict(type="str", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]), provider_match=dict(type="str", choices=["all", "at_least_one", "at_most_one", "none"]), state=dict(type="str", default="present", choices=["absent", "present", "query"]), ) @@ -268,11 +266,11 @@ def main(): supports_check_mode=True, required_if=[ ["state", "absent", ["epg", "contract"]], - ["state", "present", ["epg","contract"]], + ["state", "present", ["epg", "contract"]], ] ) - epg_type = module.params.get("type") + epg_type = module.params.get("epg_type") contract = module.params.get("contract") contract_type = module.params.get("contract_type") epg = module.params.get("epg") @@ -288,24 +286,20 @@ def main(): aci_name = ACI_CLASS_MAPPING[contract_type]["name"] class_config={"matchT": provider_match, "prio": priority, aci_name: contract} - if provider_match is not None: - provider_match = PROVIDER_MATCH_MAPPING[provider_match] - if contract_type != "provider" and provider_match is not None: module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts") elif epg_type=="out_of_band": aci_class = "mgmtRsOoBProv" - aci_rn = "rsooBProv" + aci_rn = "rsooBProv-" aci_name = "tnVzOOBBrCPName" class_config={"prio": priority, aci_name: contract} if contract_type != "provider": module.fail_json(msg="out_of_band EPG only supports Provider contract attachment.") - else: - module.fail_json(msg="epg_type can either be \"in_band\" or \"out_of_band\" only.") + module.fail_json("epg_type is {0}".format(epg_type)) class_Map = { diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 185f8ed6f..ac06ba080 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -33,20 +33,30 @@ - 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: creating new OOB EPG for testing - cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_present + - name: ensuring OOB EPG doesn't exist before + cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_absent <<: *aci_info epg: anstest_oob type: out_of_band - state: present + state: absent - - name: creating new INB EPG for testing - cisco.aci.aci_node_mgmt_epg: &aci_inb_epg_present + - name: ensuring INB EPG doesn't exist before + cisco.aci.aci_node_mgmt_epg: &aci_inb_epg_absent <<: *aci_info epg: anstest_inb type: in_band bd: inb encap: vlan-1604 + state: absent + + - name: creating new OOB EPG for testing + cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_present + <<: *aci_oob_epg_absent + state: present + + - name: creating new INB EPG for testing + cisco.aci.aci_node_mgmt_epg: &aci_inb_epg_present + <<: *aci_inb_epg_absent state: present # CREATE INB @@ -143,7 +153,7 @@ - inb_provide_present_check_mode is changed - inb_provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' - inb_provide_present is changed - - inb_provide_present.sent == provide_present_check_mode.sent + - inb_provide_present.sent == inb_provide_present_check_mode.sent - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - inb_provide_present.previous == [] - inb_consume_present is changed @@ -152,9 +162,9 @@ - inb_provide_present2 is changed - inb_provide_present2.previous == [] - oob_provide_present_check_mode is changed - - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_inb_http' + - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' - oob_provide_present is changed - - oob_provide_present.sent == provide_present_check_mode.sent + - oob_provide_present.sent == oob_provide_present_check_mode.sent - oob_provide_present.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' - oob_provide_present.previous == [] - oob_provide_present2 is changed @@ -210,19 +220,31 @@ state: query register: query_oob_provide_contract - - name: get all inband bindings + - name: Get all inband bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info - state: query epg_type: in_band + state: query + contract_type: provider register: query_inb_all + ignore_errors: yes + + - name: Debug query_inb_all + debug: + var: query_inb_all - name: get all out_of_band bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info - state: query epg_type: out_of_band + state: query + contract_type: provider register: query_oob_all + ignore_errors: yes + + - name: Debug query_oob_all + debug: + var: query_oob_all - name: missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: @@ -237,13 +259,13 @@ that: - query_inb_provide_contract is not changed - query_inb_provide_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https.json" in query_provide_contract.url' + - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https.json" in query_inb_provide_contract.url' - query_inb_consume_contract is not changed - query_inb_consume_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db.json" in query_consume_contract.url' + - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db.json" in query_inb_consume_contract.url' - query_oob_provide_contract is not changed - query_oob_provide_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsoobprov-aci_oob_https.json" in query_provide_contract.url' + - '"uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_https.json" in query_oob_provide_contract.url' - query_inb_all is not changed - '"class/fvRsProv.json" in query_all.url' - query_oob_all is not changed @@ -328,12 +350,9 @@ #CLEANUP - name: cleanup OOB epg - cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_absent - <<: *aci_oob_epg_present - state: absent + cisco.aci.aci_node_mgmt_epg: + <<: *aci_oob_epg_absent - name: cleanup INB epg cisco.aci.aci_node_mgmt_epg: - <<: *aci_oob_epg_absent - epg: anstest_inb - type: in_band + <<: *aci_inb_epg_absent From 84c9550e3475d5d2f89cbd437a669f66749d8892 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Sun, 15 Dec 2024 16:37:16 +0530 Subject: [PATCH 05/16] fixed all errors and removed debug blocks. test.yml passes all checks now --- .../tasks/main.yml | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index ac06ba080..535adc7ac 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -18,7 +18,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") }}' - name: Query system information cisco.aci.aci_system: @@ -66,7 +66,7 @@ contract_type: provider contract: aci_inb_http epg: anstest_inb - type: in_band + epg_type: in_band state: present check_mode: true register: inb_provide_present_check_mode @@ -220,36 +220,31 @@ state: query register: query_oob_provide_contract - - name: Get all inband bindings + - name: Get all inband provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: in_band + tenant: "{{ fakevar | default(omit) }}" state: query contract_type: provider register: query_inb_all ignore_errors: yes - - name: Debug query_inb_all - debug: - var: query_inb_all - - name: get all out_of_band bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: out_of_band + tenant: "{{ fakevar | default(omit) }}" state: query contract_type: provider register: query_oob_all ignore_errors: yes - - name: Debug query_oob_all - debug: - var: query_oob_all - - name: missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info state: query + contract_type: provider epg_type: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_required_query @@ -267,9 +262,9 @@ - query_oob_provide_contract.current != [] - '"uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_https.json" in query_oob_provide_contract.url' - query_inb_all is not changed - - '"class/fvRsProv.json" in query_all.url' + - query_inb_all.filter_string == "?rsp-subtree=full&rsp-subtree-class=fvRsProv" - query_oob_all is not changed - - '"class/mgmtRsOoBProv.json" in query_all.url' + - query_oob_all.filter_string == "?rsp-subtree=full&rsp-subtree-class=mgmtRsOoBProv" - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"' @@ -291,7 +286,7 @@ state: absent register: inb_provide_absent - - name: delete inb provide binding - deletion works + - name: delete inb provide binding 2 - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: absent @@ -306,9 +301,9 @@ cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present state: absent - register: oob_provide_absent_check_mode + register: oob_provide_absent - - name: delete provide binding - deletion works + - name: delete oob provide binding 2 - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present2 state: absent From 0a94b86215a5de6fe735ac37075c0da4ff45215f Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Mon, 16 Dec 2024 19:17:32 +0530 Subject: [PATCH 06/16] fixed black formatting --- .../modules/aci_node_mgmt_epg_to_contract.py | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index e97b9fc59..4841a0367 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -248,12 +248,15 @@ 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.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING + def main(): argument_spec = aci_argument_spec() argument_spec.update(aci_annotation_spec()) argument_spec.update( contract_type=dict(type="str", choices=["consumer", "provider", "taboo", "interface"], required=True), - epg_type=dict(type="str", aliases=["type"], choices=["in_band","out_of_band"], required=True), # required for querying as provider class for INB and OOB are different + epg_type=dict( + type="str", aliases=["type"], choices=["in_band", "out_of_band"], required=True + ), # required for querying as provider class for INB and OOB are different epg=dict(type="str", aliases=["epg_name"]), # Not required for querying all objects contract=dict(type="str", aliases=["contract_name", "contract_interface"]), # Not required for querying all objects priority=dict(type="str", choices=["level1", "level2", "level3", "level4", "level5", "level6", "unspecified"]), @@ -267,49 +270,41 @@ def main(): required_if=[ ["state", "absent", ["epg", "contract"]], ["state", "present", ["epg", "contract"]], - ] + ], ) epg_type = module.params.get("epg_type") contract = module.params.get("contract") contract_type = module.params.get("contract_type") epg = module.params.get("epg") - priority = module.params.get("priority") - provider_match = module.params.get("provider_match") + priority = module.params.get("priority") + provider_match = module.params.get("provider_match") if provider_match is not None: provider_match = PROVIDER_MATCH_MAPPING[provider_match] state = module.params.get("state") - if epg_type=="in_band": + if epg_type == "in_band": aci_class = ACI_CLASS_MAPPING[contract_type]["class"] aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"] aci_name = ACI_CLASS_MAPPING[contract_type]["name"] - class_config={"matchT": provider_match, "prio": priority, aci_name: contract} + class_config = {"matchT": provider_match, "prio": priority, aci_name: contract} if contract_type != "provider" and provider_match is not None: module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts") - elif epg_type=="out_of_band": - aci_class = "mgmtRsOoBProv" - aci_rn = "rsooBProv-" - aci_name = "tnVzOOBBrCPName" - class_config={"prio": priority, aci_name: contract} + elif epg_type == "out_of_band": + aci_class = "mgmtRsOoBProv" + aci_rn = "rsooBProv-" + aci_name = "tnVzOOBBrCPName" + class_config = {"prio": priority, aci_name: contract} - if contract_type != "provider": - module.fail_json(msg="out_of_band EPG only supports Provider contract attachment.") + if contract_type != "provider": + module.fail_json(msg="out_of_band EPG only supports Provider contract attachment.") else: - module.fail_json("epg_type is {0}".format(epg_type)) - + module.fail_json("epg_type is {0}".format(epg_type)) - class_Map = { - "in_band": [dict(epg_class="mgmtInB", - epg_rn="inb-{0}")], - - "out_of_band": [dict(epg_class="mgmtOoB", - epg_rn="oob-{0}" - )] - } + class_Map = {"in_band": [dict(epg_class="mgmtInB", epg_rn="inb-{0}")], "out_of_band": [dict(epg_class="mgmtOoB", epg_rn="oob-{0}")]} aci = ACIModule(module) aci.construct_url( @@ -336,7 +331,7 @@ def main(): aci_rn="{0}{1}".format(aci_rn, contract), module_object=contract, target_filter={aci_name: contract}, - ) + ), ) aci.get_existing() From 804e7586bdc6c6da676db8d1660fca1da057c082 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Sun, 19 Jan 2025 19:23:51 +0530 Subject: [PATCH 07/16] modified module and test file for accomodating all the comments of the PR. Shall test to merge Root and SubClass-1 into a single Root class now --- .../modules/aci_node_mgmt_epg_to_contract.py | 103 +++---- .../tasks/main.yml | 285 +++++++++++++----- 2 files changed, 254 insertions(+), 134 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index 4841a0367..9fafde259 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -1,8 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright: (c) 2017, Jacob McGill (@jmcgill298) -# Copyright: (c) 2023, Akini Ross (@akinross) +# Copyright: (c) 2025, Faiz Mohammad (@Ziaf007) # 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 @@ -13,19 +12,14 @@ DOCUMENTATION = r""" --- -module: aci_epg_to_contract -short_description: Bind EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and fv:RsIntraEpg) +module: aci_node_mgmt_epg_to_contract +short_description: Bind Node Mgmt EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and mgmt:RsOoBProv) description: -- Bind EPGs to Contracts on Cisco ACI fabrics. +- Bind Node mgmt EPGs to Contracts on Cisco ACI fabrics. notes: -- The C(tenant), C(app_profile), C(EPG), and C(Contract) used must exist before using this module in your playbook. - The M(cisco.aci.aci_tenant), M(cisco.aci.aci_ap), M(cisco.aci.aci_epg), and M(cisco.aci.aci_contract) modules can be used for this. +- The C(Node Mgmt EPG), and C(Contract) used must exist before using this module in your playbook. + The M(cisco.aci.aci_node_mgmt_epg), M(cisco.aci.aci_oob_contract) and M(cisco.aci.aci_contract) modules can be used for this. options: - ap: - description: - - Name of an existing application network profile, that will contain the EPGs. - type: str - aliases: [ app_profile, app_profile_name ] contract: description: - The name of the contract or contract interface. @@ -36,15 +30,15 @@ - Determines the type of the Contract. type: str required: true - choices: [ consumer, provider, taboo, interface, intra_epg ] + choices: [ consumer, provider, taboo, interface ] epg: description: - - The name of the end point group. + - The name of the Node Mgmt end point group. type: str aliases: [ epg_name ] priority: description: - - QoS class. + - Quality of Service (QoS) class. - The APIC defaults to C(unspecified) when unset during creation. type: str choices: [ level1, level2, level3, level4, level5, level6, unspecified ] @@ -54,14 +48,6 @@ - The APIC defaults to C(at_least_one) when unset during creation. type: str choices: [ all, at_least_one, at_most_one, none ] - contract_label: - description: - - Contract label to match - type: str - subject_label: - description: - - Subject label to match - type: str state: description: - Use C(present) or C(absent) for adding or removing. @@ -69,50 +55,47 @@ type: str choices: [ absent, present, query ] default: present - tenant: - description: - - Name of an existing tenant. - type: str - aliases: [ tenant_name ] extends_documentation_fragment: - cisco.aci.aci - cisco.aci.annotation seealso: -- module: cisco.aci.aci_ap -- module: cisco.aci.aci_epg +- module: cisco.aci.aci_node_mgmt_epg - module: cisco.aci.aci_contract +- module: cisco.aci.aci_oob_contract - name: APIC Management Information Model reference - description: More information about the internal APIC classes B(fv:RsCons), B(fv:RsProv), B(fv:RsProtBy), B(fv:RsConsIf), and B(fv:RsIntraEpg). + description: More information about the internal APIC classes B(fv:RsCons), B(fv:RsProv), B(fv:RsProtBy), B(fv:RsConsIf), and B(mgmt:RsOoBProv). link: https://developer.cisco.com/docs/apic-mim-ref/ author: -- Jacob McGill (@jmcgill298) -- Akini Ross (@akinross) +- Faiz Mohammad (@Ziaf007) """ EXAMPLES = r""" -- name: Add a new contract to EPG binding - cisco.aci.aci_inbepg_to_contract: +- name: Add a new contract to Inband EPG binding + cisco.aci.aci_node_mgmt_epg_to_contract: host: apic username: admin password: SomeSecretPassword - tenant: mgmt epg: anstest + epg_type: in_band contract: anstest_http - contract_type: provider + contract_type: consumer + priority: level2 state: present delegate_to: localhost -- name: Remove an existing contract to EPG binding - cisco.aci.aci_inbepg_to_contract: +- name: Add a new contract to Out-of-Band EPG binding + cisco.aci.aci_node_mgmt_epg_to_contract: host: apic username: admin password: SomeSecretPassword - tenant: mgmt epg: anstest + epg_type: out_of_band contract: anstest_http contract_type: provider - state: absent + priority: level3 + provider_match: at_least_one + state: present delegate_to: localhost - name: Query a specific contract to EPG binding @@ -120,10 +103,10 @@ host: apic username: admin password: SomeSecretPassword - tenant: anstest epg: anstest + epg_type: in_band contract: anstest_http - contract_type: provider + contract_type: consumer state: query delegate_to: localhost register: query_result @@ -137,6 +120,18 @@ state: query delegate_to: localhost register: query_result + +- name: Remove an existing contract to Inband EPG binding + cisco.aci.aci_inbepg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + epg: anstest + epg_type: in_band + contract: anstest_http + contract_type: consumer + state: absent + delegate_to: localhost """ RETURN = r""" @@ -284,26 +279,28 @@ def main(): state = module.params.get("state") if epg_type == "in_band": + + if contract_type != "provider" and provider_match is not None: + module.fail_json(msg="the provider_match is only configurable for Provider Contracts") + aci_class = ACI_CLASS_MAPPING[contract_type]["class"] aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"] aci_name = ACI_CLASS_MAPPING[contract_type]["name"] class_config = {"matchT": provider_match, "prio": priority, aci_name: contract} - if contract_type != "provider" and provider_match is not None: - module.fail_json(msg="the 'provider_match' is only configurable for Provided Contracts") - elif epg_type == "out_of_band": + + if contract_type != "provider": + module.fail_json(msg="only provider contract_type is supported for out_of_band epg_type.") + + if provider_match is not None: + module.fail_json(msg="The provider_match argument is not supported for out_of_band Provider contracts") + aci_class = "mgmtRsOoBProv" aci_rn = "rsooBProv-" aci_name = "tnVzOOBBrCPName" class_config = {"prio": priority, aci_name: contract} - if contract_type != "provider": - module.fail_json(msg="out_of_band EPG only supports Provider contract attachment.") - - else: - module.fail_json("epg_type is {0}".format(epg_type)) - class_Map = {"in_band": [dict(epg_class="mgmtInB", epg_rn="inb-{0}")], "out_of_band": [dict(epg_class="mgmtOoB", epg_rn="oob-{0}")]} aci = ACIModule(module) @@ -337,11 +334,9 @@ def main(): aci.get_existing() if state == "present": - child_configs = [] aci.payload( aci_class=aci_class, class_config=class_config, - child_configs=child_configs, ) aci.get_diff(aci_class=aci_class) diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 535adc7ac..957b8f4cb 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -1,5 +1,5 @@ # Test code for the ACI modules -# Copyright: (c) 2024, Faiz Mohammad (@faizmoh) +# Copyright: (c) 2025, Faiz Mohammad (@faizmoh) # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) @@ -30,9 +30,12 @@ - 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 +- name: Execute tasks only for ACI v5+ and 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 + # CLEAN ENVIRONMENT - name: ensuring OOB EPG doesn't exist before cisco.aci.aci_node_mgmt_epg: &aci_oob_epg_absent <<: *aci_info @@ -60,7 +63,7 @@ state: present # CREATE INB - - name: bind inb contract to inband epg - check mode works + - name: bind inb provider contract to inband epg - Check Mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present <<: *aci_info contract_type: provider @@ -71,33 +74,97 @@ check_mode: true register: inb_provide_present_check_mode - - name: bind inb contract to inband epg - provide works + - name: bind inb provider contract to inband epg - Normal Mode works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present register: inb_provide_present - - name: bind inb contract to epg - consume works + - name: bind additional inb provider contract to inband epg - add additional contract + cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + provider_match: at_most_one + register: inb_provide_present2 + + - name: bind inb provider contract to epg again - idempotency works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: inb_idempotent_present + + - name: Assert Inband Provider Contract was created + ansible.builtin.assert: + that: + - inb_provide_present_check_mode is changed + - inb_provide_present_check_mode.previous == [] + - inb_provide_present_check_mode.current == [] + - inb_provide_present_check_mode.sent.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" + - inb_provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' + - inb_provide_present is changed + - inb_provide_present.previous == [] + - inb_provide_present.sent == inb_provide_present_check_mode.sent + - inb_provide_present.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" + - inb_provide_present.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - inb_provide_present.current.0.fvRsProv.attributes.prio == "unspecified" + - inb_provide_present2 is changed + - inb_provide_present2.previous == [] + - inb_provide_present2.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https" + - inb_provide_present2.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_https" + - inb_provide_present2.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - inb_provide_present2.current.0.fvRsProv.attributes.prio == "unspecified" + - inb_provide_present2.current.0.fvRsProv.attributes.matchT == "AtmostOne" + - inb_idempotent_present is not changed + - inb_idempotent_present.previous.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" + - inb_idempotent_present.previous.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - inb_idempotent_present.previous.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - inb_idempotent_present.previous.0.fvRsProv.attributes.prio == "unspecified" + - inb_idempotent_present.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" + - inb_idempotent_present.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - inb_idempotent_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' + - inb_idempotent_present.current.0.fvRsProv.attributes.prio == "unspecified" + + - name: bind inb consumer contract to epg cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present <<: *aci_inb_epg_provide_present contract_type: consumer contract: anstest_inb_db register: inb_consume_present - - name: bind inb contract to inband epg - add additional contract - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 + - name: bind taboo contract to inband epg + cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present contract: aci_inb_https - provider_match: at_most_one - register: inb_provide_present2 + contract_type: taboo + register: taboo_present - - name: bind inb contract to epg - idempotency works + - name: bind interface contract to inband epg cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present - register: inb_idempotent_present + contract: aci_inb_https + contract_type: interface + register: interface_present + + - name: Assert all type Inband Contracts are created + ansible.builtin.assert: + that: + - inb_consume_present is changed + - inb_consume_present.previous == [] + - inb_consume_present.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - inb_consume_present.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - inb_consume_present.current.0.fvRsCons.attributes.annotation == 'orchestrator:ansible' + - inb_consume_present.current.0.fvRsCons.attributes.prio == "unspecified" + - taboo_present is changed + - taboo_present.previous == [] + - taboo_present.current.0.fvRsProtBy.attributes.tnVzTabooName == 'aci_inb_https' + - taboo_present.current.0.fvRsProtBy.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprotBy-aci_inb_https" + - interface_present is changed + - interface_present.previous == [] + - interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'aci_inb_https' + - interface_present.current.0.fvRsConsIf.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsconsIf-aci_inb_https" # CREATE OOB - - name: bind oob contract to out-of-band epg - check mode works + - name: bind oob provider contract to out-of-band epg - Check Mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present <<: *aci_info contract_type: provider @@ -108,23 +175,105 @@ check_mode: true register: oob_provide_present_check_mode - - name: bind oob contract to out-of-band epg - provide works + - name: bind oob provider contract to out-of-band epg - Normal Mode works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present register: oob_provide_present - - name: bind oob contract to out-of-band epg aci- add additional contract + - name: bind oob Provider contract to out-of-band epg - add additional contract cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present2 <<: *aci_oob_epg_provide_present contract: aci_oob_https - provider_match: at_most_one register: oob_provide_present2 - - name: bind oob contract to epg - idempotency works + - name: bind oob provider contract to epg again - idempotency works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present register: oob_idempotent_present + - name: Assert OOB Contract was created + ansible.builtin.assert: + that: + - oob_provide_present_check_mode is changed + - oob_provide_present_check_mode.previous == [] + - oob_provide_present_check_mode.current == [] + - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' + - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" + - oob_provide_present is changed + - oob_provide_present.previous == [] + - oob_provide_present.sent == oob_provide_present_check_mode.sent + - oob_provide_present.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' + - oob_provide_present.sent.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" + - oob_provide_present.current.0.mgmtRsOoBProv.attributes.prio == "unspecified" + - oob_provide_present.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' + - oob_provide_present2 is changed + - oob_provide_present2.previous == [] + - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' + - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_https' + - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_https" + - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.prio == "unspecified" + + # UPDATE + - name: Update inb consumer contract - check mode + cisco.aci.aci_node_mgmt_epg_to_contract: &update_inb_consumer_contract + <<: *aci_inb_epg_consume_present + priority: "level6" + check_mode: true + register: upd_inb_consumer_check_mode + + - name: Update inb consumer contract - normal mode + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_present + priority: "level6" + register: upd_inb_consumer + + - name: Update inb consumer contract - again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *update_inb_consumer_contract + register: upd_inb_consumer_again + + - name: Update oob provider contract + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present + priority: "level4" + register: upd_oob_provider + + - name: Assert Contract Update operations + ansible.builtin.assert: + that: + - upd_inb_consumer_check_mode is changed + - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.prio == "unspecified" + - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.prio == "unspecified" + - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.prio == "level6" + - upd_inb_consumer is changed + - upd_inb_consumer.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer.previous.0.fvRsCons.attributes.prio == "unspecified" + - upd_inb_consumer.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer.current.0.fvRsCons.attributes.prio == "level6" + - upd_inb_consumer_again is not changed + - upd_inb_consumer_again.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer_again.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer_again.previous.0.fvRsCons.attributes.prio == "level6" + - upd_inb_consumer_again.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" + - upd_inb_consumer_again.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer_again.current.0.fvRsCons.attributes.prio == "level6" + - upd_oob_provider is changed + - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" + - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" + - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.prio == "unspecified" + - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" + - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" + - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.prio == "level4" + + #MISSING PARAMS - name: missing param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: @@ -140,81 +289,56 @@ ignore_errors: true register: missing_required_present - - name: incompatible param - failure message works + - name: incompatible param OOB - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present contract_type: consumer ignore_errors: true - register: incompatible_present + register: oob_incompatible_present - - name: present assertions + - name: incompatible param OOB provider_match - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present + provider_match: "at_most_one" + ignore_errors: true + register: oob_incompatible_present2 + + - name: incompatible param INB - failure message works + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + contract_type: consumer + provider_match: at_least_one + ignore_errors: true + register: inb_incompatible_present + + - name: Assert Missing parameter failure messages ansible.builtin.assert: - that: - - inb_provide_present_check_mode is changed - - inb_provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' - - inb_provide_present is changed - - inb_provide_present.sent == inb_provide_present_check_mode.sent - - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - - inb_provide_present.previous == [] - - inb_consume_present is changed - - inb_consume_present.previous == [] - - inb_consume_present.sent.fvRsCons.attributes.tnVzBrCPName == 'anstest_inb_db' - - inb_provide_present2 is changed - - inb_provide_present2.previous == [] - - oob_provide_present_check_mode is changed - - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' - - oob_provide_present is changed - - oob_provide_present.sent == oob_provide_present_check_mode.sent - - oob_provide_present.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' - - oob_provide_present.previous == [] - - oob_provide_present2 is changed - - oob_provide_present2.previous == [] + that: - missing_param_present is failed - 'missing_param_present.msg == "state is present but all of the following are missing: epg"' - missing_required_present is failed - 'missing_required_present.msg == "missing required arguments: contract_type"' - - incompatible_present is failed - - incompatible_present.msg == "out_of_band EPG only supports Provider contract attachment." - - #TABOO/INTERFACE - - name: bind taboo contract to inband epg - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present - contract: aci_inb_https - contract_type: taboo - register: taboo_present - - - name: bind interface contract to inband epg - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present - contract: aci_inb_https - contract_type: interface - register: interface_present - - - name: present assertions for taboo, and interface contract types - assert: - that: - - taboo_present is changed - - taboo_present.previous == [] - - taboo_present.current.0.fvRsProtBy.attributes.tnVzTabooName == 'aci_inb_https' - - interface_present is changed - - interface_present.previous == [] - - interface_present.current.0.fvRsConsIf.attributes.tnVzCPIfName == 'aci_inb_https' + - oob_incompatible_present is failed + - 'oob_incompatible_present.msg == "only provider contract_type is supported for out_of_band epg_type."' + - oob_incompatible_present2 is failed + - 'oob_incompatible_present2.msg == "The provider_match argument is not supported for out_of_band Provider contracts"' + - inb_incompatible_present is failed + - 'inb_incompatible_present.msg == "the provider_match is only configurable for Provider Contracts"' # QUERY - - name: get inb binding for provide + - name: get inb binding for provider contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: query register: query_inb_provide_contract - - name: get inb binding for consume + - name: get inb binding for consumer contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_present state: query register: query_inb_consume_contract - - name: get oob binding + - name: get oob binding for provider contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present2 state: query @@ -230,7 +354,7 @@ register: query_inb_all ignore_errors: yes - - name: get all out_of_band bindings + - name: get all out_of_band provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: out_of_band @@ -249,7 +373,7 @@ ignore_errors: true register: missing_required_query - - name: query assertions + - name: Assert INB & OOB contracts were queried ansible.builtin.assert: that: - query_inb_provide_contract is not changed @@ -268,42 +392,43 @@ - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"' - - name: delete inb consume binding - check mode works + # DELETE + - name: delete inb consumer binding - check mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_absent <<: *aci_inb_epg_consume_present state: absent check_mode: true register: consume_absent_check_mode - - name: delete inb consume binding - deletion works + - name: delete inb consumer binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent - - name: delete inb provide binding - deletion works + - name: delete inb provider binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present state: absent register: inb_provide_absent - - name: delete inb provide binding 2 - deletion works + - name: delete inb provider binding 2 - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: absent register: inb_provide_absent2 - - name: delete inb consume binding - idempotency works + - name: delete inb consumer binding - idempotency works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent_idempotent - - name: delete oob provide binding - deletion works + - name: delete oob provider binding - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present state: absent register: oob_provide_absent - - name: delete oob provide binding 2 - deletion works + - name: delete oob provider binding 2 - deletion works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present2 state: absent @@ -323,7 +448,7 @@ ignore_errors: true register: missing_required_absent - - name: absent assertions + - name: Assert that INB & OOB Contract were deleted ansible.builtin.assert: that: - consume_absent_check_mode is changed From 788ec4ccb0b41435f1ee5201bd34220fcaaf67c8 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Thu, 23 Jan 2025 09:00:07 +0530 Subject: [PATCH 08/16] 1) merged root class and Subclass 1 as per request 2) fixed some linting 3) modified the query assertations accordingly in test file All checks passed in test file. PLAY RECAP ********************************************************************* azure_cloud : ok=8 changed=0 unreachable=0 failed=0 skipped=51 rescued=0 ignored=0 cn-dmz-apic-m1-02-v42 : ok=7 changed=0 unreachable=0 failed=0 skipped=52 rescued=0 ignored=0 cn-dmz-apic-m1-03-v52 : ok=55 changed=24 unreachable=0 failed=0 skipped=4 rescued=0 ignored=8 cn-dmz-apic-m1-04-v602h : ok=55 changed=24 unreachable=0 failed=0 skipped=4 rescued=0 ignored=8 Module ready for review --- .../modules/aci_node_mgmt_epg_to_contract.py | 45 +++++++++++++------ .../tasks/main.yml | 17 ++++--- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index 9fafde259..2cd500d1b 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -305,30 +305,47 @@ def main(): aci = ACIModule(module) aci.construct_url( + # root_class=dict( + # aci_class="fvTenant", + # aci_rn="tn-mgmt", + # module_object="mgmt", + # target_filter={"name": "mgmt"} + # ), + # subclass_1=dict( + # aci_class="mgmtMgmtP", + # aci_rn="mgmtp-default", + # module_object="default", + # target_filter={"name": "default"} + # ), + # subclass_2=dict( + # aci_class=class_Map[epg_type][0]["epg_class"], + # aci_rn=class_Map[epg_type][0]["epg_rn"].format(epg), + # module_object=epg, + # target_filter={"name": epg} + # ), + # subclass_3=dict( + # aci_class=aci_class, + # aci_rn="{0}{1}".format(aci_rn, contract), + # module_object=contract, + # target_filter={aci_name: contract} + # ) root_class=dict( - aci_class="fvTenant", - aci_rn="tn-mgmt", - module_object="mgmt", - target_filter={"name": "mgmt"}, + # aci_class="fvTenant", + aci_rn="tn-mgmt/mgmtp-default", + module_object=None ), subclass_1=dict( - aci_class="mgmtMgmtP", - aci_rn="mgmtp-default", - module_object="default", - target_filter={"name": "default"}, - ), - subclass_2=dict( aci_class=class_Map[epg_type][0]["epg_class"], aci_rn=class_Map[epg_type][0]["epg_rn"].format(epg), module_object=epg, - target_filter={"name": epg}, + target_filter={"name": epg} ), - subclass_3=dict( + subclass_2=dict( aci_class=aci_class, aci_rn="{0}{1}".format(aci_rn, contract), module_object=contract, - target_filter={aci_name: contract}, - ), + target_filter={aci_name: contract} + ) ) aci.get_existing() diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 957b8f4cb..7908e1c83 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -62,7 +62,7 @@ <<: *aci_inb_epg_absent state: present - # CREATE INB + # CREATE - INB - name: bind inb provider contract to inband epg - Check Mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present <<: *aci_info @@ -163,7 +163,7 @@ - interface_present.current.0.fvRsConsIf.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsconsIf-aci_inb_https" - # CREATE OOB + # CREATE - OOB - name: bind oob provider contract to out-of-band epg - Check Mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present <<: *aci_info @@ -378,17 +378,20 @@ that: - query_inb_provide_contract is not changed - query_inb_provide_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https.json" in query_inb_provide_contract.url' + - '"/api/class/mgmtInB.json" in query_inb_provide_contract.url' + - query_inb_provide_contract.filter_string is search('query-target-filter=eq\(mgmtInB.name,"anstest_inb"\)') + - query_inb_provide_contract.filter_string is search('rsp-subtree-filter=eq\(fvRsProv.tnVzBrCPName,"aci_inb_https"\)') - query_inb_consume_contract is not changed - query_inb_consume_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db.json" in query_inb_consume_contract.url' + - query_inb_consume_contract.filter_string is search('query-target-filter=eq\\(mgmtInB.name,"anstest_inb"\\)') + - query_inb_consume_contract.filter_string is search('rsp-subtree-filter=eq\\(fvRsCons.tnVzBrCPName,"anstest_inb_db"\\)') - query_oob_provide_contract is not changed - query_oob_provide_contract.current != [] - - '"uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_https.json" in query_oob_provide_contract.url' + - '"/api/class/mgmtOoB.json" in query_oob_provide_contract.url' - query_inb_all is not changed - - query_inb_all.filter_string == "?rsp-subtree=full&rsp-subtree-class=fvRsProv" + - query_inb_all.filter_string == "" - query_oob_all is not changed - - query_oob_all.filter_string == "?rsp-subtree=full&rsp-subtree-class=mgmtRsOoBProv" + - query_oob_all.filter_string == "" - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"' From 6772728db12cd96cb4217f565524826e2dca9494 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Thu, 20 Mar 2025 12:32:43 +0530 Subject: [PATCH 09/16] all changes made as requested. Tests are pending and for some reason seem to fail. Pushing to branch so one can pull to their local and test --- plugins/module_utils/constants.py | 14 ++ .../modules/aci_node_mgmt_epg_to_contract.py | 91 ++++++------ .../tasks/main.yml | 138 ++++++++---------- 3 files changed, 119 insertions(+), 124 deletions(-) diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index 35b209978..0ccdf81aa 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -139,6 +139,11 @@ "rn": "rsprov-", "name": "tnVzBrCPName", }, + oob_provider={ + "class": "mgmtRsOoBProv", + "rn": "rsooBProv-", + "name": "tnVzOOBBrCPName", + }, taboo={ "class": "fvRsProtBy", "rn": "rsprotBy-", @@ -441,3 +446,12 @@ MATCH_ACCESS_POLICIES_SELECTOR_TYPE = dict(range="range", all="ALL") MANAGEMENT_EPG_TYPE = dict(ooband="oob", inband="inb") + +MANAGEMENT_EPG_CLASS_MAPPING = dict( + in_band= + {"epg_class":"mgmtInB", + "epg_rn":"inb-"}, + out_of_band= + {"epg_class":"mgmtOoB", + "epg_rn":"oob-"} + ) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index 2cd500d1b..eab43742d 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -13,7 +13,7 @@ DOCUMENTATION = r""" --- module: aci_node_mgmt_epg_to_contract -short_description: Bind Node Mgmt EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf, and mgmt:RsOoBProv) +short_description: Bind Node Mgmt EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf and mgmt:RsOoBProv) description: - Bind Node mgmt EPGs to Contracts on Cisco ACI fabrics. notes: @@ -36,6 +36,13 @@ - The name of the Node Mgmt end point group. type: str aliases: [ epg_name ] + epg_type: + description: + - The type of the Node Mgmt end point group. + type: str + required: true + aliases: [ type ] + choices: [ in_band, out_of_band ] priority: description: - Quality of Service (QoS) class. @@ -79,8 +86,9 @@ epg: anstest epg_type: in_band contract: anstest_http - contract_type: consumer + contract_type: provider priority: level2 + provider_match: at_least_one state: present delegate_to: localhost @@ -94,7 +102,20 @@ contract: anstest_http contract_type: provider priority: level3 - provider_match: at_least_one + state: present + delegate_to: localhost + +- name: Update a contract of Inband EPG binding + cisco.aci.aci_node_mgmt_epg_to_contract: + host: apic + username: admin + password: SomeSecretPassword + epg: anstest + epg_type: in_band + contract: anstest_http + contract_type: provider + priority: level5 + provider_match: all state: present delegate_to: localhost @@ -241,7 +262,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.constants import ACI_CLASS_MAPPING, CONTRACT_LABEL_MAPPING, PROVIDER_MATCH_MAPPING, SUBJ_LABEL_MAPPING +from ansible_collections.cisco.aci.plugins.module_utils.constants import ACI_CLASS_MAPPING, MANAGEMENT_EPG_CLASS_MAPPING, PROVIDER_MATCH_MAPPING def main(): @@ -292,61 +313,31 @@ def main(): if contract_type != "provider": module.fail_json(msg="only provider contract_type is supported for out_of_band epg_type.") - + if provider_match is not None: - module.fail_json(msg="The provider_match argument is not supported for out_of_band Provider contracts") + module.fail_json(msg="The provider_match argument is not supported for out_of_band Provider contracts") - aci_class = "mgmtRsOoBProv" - aci_rn = "rsooBProv-" - aci_name = "tnVzOOBBrCPName" + aci_class = ACI_CLASS_MAPPING["oob_provider"]["class"] + aci_rn = ACI_CLASS_MAPPING["oob_provider"]["rn"] + aci_name = ACI_CLASS_MAPPING["oob_provider"]["name"] class_config = {"prio": priority, aci_name: contract} - class_Map = {"in_band": [dict(epg_class="mgmtInB", epg_rn="inb-{0}")], "out_of_band": [dict(epg_class="mgmtOoB", epg_rn="oob-{0}")]} - aci = ACIModule(module) aci.construct_url( - # root_class=dict( - # aci_class="fvTenant", - # aci_rn="tn-mgmt", - # module_object="mgmt", - # target_filter={"name": "mgmt"} - # ), - # subclass_1=dict( - # aci_class="mgmtMgmtP", - # aci_rn="mgmtp-default", - # module_object="default", - # target_filter={"name": "default"} - # ), - # subclass_2=dict( - # aci_class=class_Map[epg_type][0]["epg_class"], - # aci_rn=class_Map[epg_type][0]["epg_rn"].format(epg), - # module_object=epg, - # target_filter={"name": epg} - # ), - # subclass_3=dict( - # aci_class=aci_class, - # aci_rn="{0}{1}".format(aci_rn, contract), - # module_object=contract, - # target_filter={aci_name: contract} - # ) root_class=dict( - # aci_class="fvTenant", aci_rn="tn-mgmt/mgmtp-default", - module_object=None - ), + module_object=None, + ), subclass_1=dict( - aci_class=class_Map[epg_type][0]["epg_class"], - aci_rn=class_Map[epg_type][0]["epg_rn"].format(epg), - module_object=epg, - target_filter={"name": epg} - ), - subclass_2=dict( - aci_class=aci_class, - aci_rn="{0}{1}".format(aci_rn, contract), - module_object=contract, - target_filter={aci_name: contract} - ) - ) + aci_class=MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_class"], + aci_rn="{0}{1}".format(MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_rn"],epg), + module_object=epg, target_filter={"name": epg} + ), + subclass_2=dict(aci_class=aci_class, + aci_rn="{0}{1}".format(aci_rn, contract), + module_object=contract, + target_filter={aci_name: contract}) + ) aci.get_existing() diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 7908e1c83..56ff369b6 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -63,7 +63,7 @@ state: present # CREATE - INB - - name: bind inb provider contract to inband epg - Check Mode works + - name: Attach Provider contract to Inband EPG (check_mode) cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present <<: *aci_info contract_type: provider @@ -74,24 +74,27 @@ check_mode: true register: inb_provide_present_check_mode - - name: bind inb provider contract to inband epg - Normal Mode works + - name: Attach Provider contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present + priority: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'unspecified' + provider_match: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'AtleastOne' + state: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'present' register: inb_provide_present - - name: bind additional inb provider contract to inband epg - add additional contract + - name: Attach Provider contract to Inband EPG again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + register: inb_idempotent_present + + - name: Attach one more Provider contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 <<: *aci_inb_epg_provide_present contract: aci_inb_https provider_match: at_most_one register: inb_provide_present2 - - name: bind inb provider contract to epg again - idempotency works - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present - register: inb_idempotent_present - - - name: Assert Inband Provider Contract was created + - name: Assert Provider Contracts were attached to Inband EPG ansible.builtin.assert: that: - inb_provide_present_check_mode is changed @@ -106,6 +109,7 @@ - inb_provide_present.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - inb_provide_present.current.0.fvRsProv.attributes.prio == "unspecified" + - inb_provide_present.current.0.fvRsProv.attributes.matchT == "AtleastOne" - inb_provide_present2 is changed - inb_provide_present2.previous == [] - inb_provide_present2.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https" @@ -123,28 +127,29 @@ - inb_idempotent_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - inb_idempotent_present.current.0.fvRsProv.attributes.prio == "unspecified" - - name: bind inb consumer contract to epg + - name: Attach Consumer contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_present <<: *aci_inb_epg_provide_present contract_type: consumer contract: anstest_inb_db + provider_match: "{{ fakevar | default(omit) }}" register: inb_consume_present - - name: bind taboo contract to inband epg + - name: Attach Taboo contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present + <<: *aci_inb_epg_consume_present contract: aci_inb_https contract_type: taboo register: taboo_present - - name: bind interface contract to inband epg + - name: Attach Interface contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present + <<: *aci_inb_epg_consume_present contract: aci_inb_https contract_type: interface register: interface_present - - name: Assert all type Inband Contracts are created + - name: Assert all Contracts to Inband EPG were created ansible.builtin.assert: that: - inb_consume_present is changed @@ -164,7 +169,7 @@ # CREATE - OOB - - name: bind oob provider contract to out-of-band epg - Check Mode works + - name: Attach Provider contract to Out-of-Band EPG (check_mode) cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present <<: *aci_info contract_type: provider @@ -175,23 +180,23 @@ check_mode: true register: oob_provide_present_check_mode - - name: bind oob provider contract to out-of-band epg - Normal Mode works + - name: Attach Provider contract to Out-of-Band EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present register: oob_provide_present - - name: bind oob Provider contract to out-of-band epg - add additional contract + - name: Attach Provider contract to Out-of-Band EPG again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present + register: oob_idempotent_present + + - name: Attach one more Provider contract to Out-of-Band EPG cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present2 <<: *aci_oob_epg_provide_present contract: aci_oob_https register: oob_provide_present2 - - name: bind oob provider contract to epg again - idempotency works - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_oob_epg_provide_present - register: oob_idempotent_present - - - name: Assert OOB Contract was created + - name: Assert Provider contracts to Out-of-Band EPG were attached ansible.builtin.assert: that: - oob_provide_present_check_mode is changed @@ -214,25 +219,26 @@ - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.prio == "unspecified" # UPDATE - - name: Update inb consumer contract - check mode + - name: Update Consumer Contract to Inband EPG (check_mode) cisco.aci.aci_node_mgmt_epg_to_contract: &update_inb_consumer_contract <<: *aci_inb_epg_consume_present priority: "level6" check_mode: true register: upd_inb_consumer_check_mode - - name: Update inb consumer contract - normal mode + - name: Update Consumer Contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_consume_present - priority: "level6" + <<: *update_inb_consumer_contract register: upd_inb_consumer - - name: Update inb consumer contract - again + - name: Update Provider Contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *update_inb_consumer_contract - register: upd_inb_consumer_again + <<: *aci_inb_epg_provide_present + priority: "level4" + provider_match: at_least_one + register: upd_inb_provider - - name: Update oob provider contract + - name: Update Provider Contract to Out-of-Band EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present priority: "level4" @@ -242,68 +248,52 @@ ansible.builtin.assert: that: - upd_inb_consumer_check_mode is changed - - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_consumer_check_mode.previous.0.fvRsCons.attributes.prio == "unspecified" - - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_consumer_check_mode.current.0.fvRsCons.attributes.prio == "unspecified" - - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_consumer_check_mode.proposed.fvRsCons.attributes.prio == "level6" - upd_inb_consumer is changed - - upd_inb_consumer.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_consumer.previous.0.fvRsCons.attributes.prio == "unspecified" - - upd_inb_consumer.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_consumer.current.0.fvRsCons.attributes.prio == "level6" - - upd_inb_consumer_again is not changed - - upd_inb_consumer_again.previous.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer_again.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - - upd_inb_consumer_again.previous.0.fvRsCons.attributes.prio == "level6" - - upd_inb_consumer_again.current.0.fvRsCons.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rscons-anstest_inb_db" - - upd_inb_consumer_again.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - - upd_inb_consumer_again.current.0.fvRsCons.attributes.prio == "level6" + - upd_inb_provider is changed + - upd_inb_provider.previous.0.fvRsProv.attributes.prio == "unspecified" + - upd_inb_provider.previous.0.fvRsProv.attributes.matchT == "AtleastOne" + - upd_inb_provider.current.0.fvRsProv.attributes.prio == "level4" + - upd_inb_provider.current.0.fvRsProv.attributes.matchT == "AtleastOne" - upd_oob_provider is changed - - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" - - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.prio == "unspecified" - - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" - - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.prio == "level4" #MISSING PARAMS - - name: missing param - failure message works + - name: Missing parameter - epg_name cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present epg: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_param_present - - name: missing required param - failure message works + - name: Missing Required parameter - contract_type cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present contract_type: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_required_present - - name: incompatible param OOB - failure message works + - name: Incompatible parameter - consumer contract to Out-of-Band EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present contract_type: consumer ignore_errors: true register: oob_incompatible_present - - name: incompatible param OOB provider_match - failure message works + - name: Incompatible parameter - provider_match with Out-of-Band EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present provider_match: "at_most_one" ignore_errors: true register: oob_incompatible_present2 - - name: incompatible param INB - failure message works + - name: Incompatible parameter - provider_match in consumer contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present contract_type: consumer @@ -311,7 +301,7 @@ ignore_errors: true register: inb_incompatible_present - - name: Assert Missing parameter failure messages + - name: Assert Failure messages ansible.builtin.assert: that: - missing_param_present is failed @@ -326,25 +316,25 @@ - 'inb_incompatible_present.msg == "the provider_match is only configurable for Provider Contracts"' # QUERY - - name: get inb binding for provider contract + - name: Query Inband EPG for Provider contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: query register: query_inb_provide_contract - - name: get inb binding for consumer contract + - name: Query Inband EPG for Consumer contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_present state: query register: query_inb_consume_contract - - name: get oob binding for provider contract + - name: Query Out-of-Band EPG for Provider contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present2 state: query register: query_oob_provide_contract - - name: Get all inband provider bindings + - name: Get all Inband EPG provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: in_band @@ -354,7 +344,7 @@ register: query_inb_all ignore_errors: yes - - name: get all out_of_band provider bindings + - name: get all Out_of_Band EPG provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: out_of_band @@ -403,35 +393,35 @@ check_mode: true register: consume_absent_check_mode - - name: delete inb consumer binding - deletion works + - name: delete inb consumer binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent - - name: delete inb provider binding - deletion works + - name: delete inb consumer binding again + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_consume_absent + register: consume_absent_idempotent + + - name: delete inb provider binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present state: absent register: inb_provide_absent - - name: delete inb provider binding 2 - deletion works + - name: delete inb provider binding 2 cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present2 state: absent register: inb_provide_absent2 - - name: delete inb consumer binding - idempotency works - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_consume_absent - register: consume_absent_idempotent - - - name: delete oob provider binding - deletion works + - name: delete oob provider binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present state: absent register: oob_provide_absent - - name: delete oob provider binding 2 - deletion works + - name: delete oob provider binding 2 cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present2 state: absent From 34d7092edc8c99a74bd743b285e017bb4d50020d Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Sat, 22 Mar 2025 14:47:53 +0530 Subject: [PATCH 10/16] moved the common block aci_class/rn/name outside of the individual epg block. Fixed some typos --- plugins/module_utils/constants.py | 8 +-- .../modules/aci_node_mgmt_epg_to_contract.py | 53 ++++++++++--------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index 0ccdf81aa..c499d6146 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -449,9 +449,9 @@ MANAGEMENT_EPG_CLASS_MAPPING = dict( in_band= - {"epg_class":"mgmtInB", - "epg_rn":"inb-"}, + {"epg_class": "mgmtInB", + "epg_rn": "inb-"}, out_of_band= - {"epg_class":"mgmtOoB", - "epg_rn":"oob-"} + {"epg_class": "mgmtOoB", + "epg_rn": "oob-"} ) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index eab43742d..f292eb3d1 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -13,11 +13,11 @@ DOCUMENTATION = r""" --- module: aci_node_mgmt_epg_to_contract -short_description: Bind Node Mgmt EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf and mgmt:RsOoBProv) +short_description: Bind Node Management EPGs to Contracts (fv:RsCons, fv:RsProv, fv:RsProtBy, fv:RsConsIf and mgmt:RsOoBProv) description: -- Bind Node mgmt EPGs to Contracts on Cisco ACI fabrics. +- Bind Node Management EPGs to Contracts on Cisco ACI fabrics. notes: -- The C(Node Mgmt EPG), and C(Contract) used must exist before using this module in your playbook. +- The C(epg) and C(contract) used must exist before using this module in your playbook. The M(cisco.aci.aci_node_mgmt_epg), M(cisco.aci.aci_oob_contract) and M(cisco.aci.aci_contract) modules can be used for this. options: contract: @@ -33,12 +33,12 @@ choices: [ consumer, provider, taboo, interface ] epg: description: - - The name of the Node Mgmt end point group. + - The name of the Node Management end point group. type: str aliases: [ epg_name ] epg_type: description: - - The type of the Node Mgmt end point group. + - The type of the Node Management end point group. type: str required: true aliases: [ type ] @@ -120,7 +120,7 @@ delegate_to: localhost - name: Query a specific contract to EPG binding - cisco.aci.aci_inbepg_to_contract: + cisco.aci.aci_node_mgmt_epg_to_contract: host: apic username: admin password: SomeSecretPassword @@ -133,7 +133,7 @@ register: query_result - name: Query all provider contract to EPG bindings - cisco.aci.aci_inbepg_to_contract: + cisco.aci.aci_node_mgmt_epg_to_contract: host: apic username: admin password: SomeSecretPassword @@ -143,7 +143,7 @@ register: query_result - name: Remove an existing contract to Inband EPG binding - cisco.aci.aci_inbepg_to_contract: + cisco.aci.aci_node_mgmt_epg_to_contract: host: apic username: admin password: SomeSecretPassword @@ -299,14 +299,13 @@ def main(): provider_match = PROVIDER_MATCH_MAPPING[provider_match] state = module.params.get("state") + identifier = None if epg_type == "in_band": if contract_type != "provider" and provider_match is not None: module.fail_json(msg="the provider_match is only configurable for Provider Contracts") - aci_class = ACI_CLASS_MAPPING[contract_type]["class"] - aci_rn = ACI_CLASS_MAPPING[contract_type]["rn"] - aci_name = ACI_CLASS_MAPPING[contract_type]["name"] + identifier = contract_type class_config = {"matchT": provider_match, "prio": priority, aci_name: contract} elif epg_type == "out_of_band": @@ -317,27 +316,33 @@ def main(): if provider_match is not None: module.fail_json(msg="The provider_match argument is not supported for out_of_band Provider contracts") - aci_class = ACI_CLASS_MAPPING["oob_provider"]["class"] - aci_rn = ACI_CLASS_MAPPING["oob_provider"]["rn"] - aci_name = ACI_CLASS_MAPPING["oob_provider"]["name"] + identifier = "oob_provider" class_config = {"prio": priority, aci_name: contract} + aci_class = ACI_CLASS_MAPPING[identifier]["class"] + aci_rn = ACI_CLASS_MAPPING[identifier]["rn"] + aci_name = ACI_CLASS_MAPPING[identifier]["name"] + aci = ACIModule(module) aci.construct_url( root_class=dict( + aci_class="mgmtp", aci_rn="tn-mgmt/mgmtp-default", module_object=None, - ), + ), subclass_1=dict( - aci_class=MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_class"], - aci_rn="{0}{1}".format(MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_rn"],epg), - module_object=epg, target_filter={"name": epg} - ), - subclass_2=dict(aci_class=aci_class, - aci_rn="{0}{1}".format(aci_rn, contract), - module_object=contract, - target_filter={aci_name: contract}) - ) + aci_class=MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_class"], + aci_rn="{0}{1}".format(MANAGEMENT_EPG_CLASS_MAPPING[epg_type]["epg_rn"], epg), + module_object=epg, + target_filter={"name": epg}, + ), + subclass_2=dict( + aci_class=aci_class, + aci_rn="{0}{1}".format(aci_rn, contract), + module_object=contract, + target_filter={aci_name: contract}, + ), + ) aci.get_existing() From 4c45f4f3789f16db6b59116566d8b437ba43f250 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Wed, 26 Mar 2025 03:33:20 +0530 Subject: [PATCH 11/16] reformatted constants.py with black -l 159. Should pass sanity now --- plugins/module_utils/constants.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index c499d6146..857f3bdc6 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -447,11 +447,4 @@ MANAGEMENT_EPG_TYPE = dict(ooband="oob", inband="inb") -MANAGEMENT_EPG_CLASS_MAPPING = dict( - in_band= - {"epg_class": "mgmtInB", - "epg_rn": "inb-"}, - out_of_band= - {"epg_class": "mgmtOoB", - "epg_rn": "oob-"} - ) +MANAGEMENT_EPG_CLASS_MAPPING = dict(in_band={"epg_class": "mgmtInB", "epg_rn": "inb-"}, out_of_band={"epg_class": "mgmtOoB", "epg_rn": "oob-"}) From abebab6519728115c5ecb3d470c9638d11e9f4be Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Thu, 27 Mar 2025 02:43:24 +0530 Subject: [PATCH 12/16] replaced aci_name with respective contract MO name --- plugins/modules/aci_node_mgmt_epg_to_contract.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index f292eb3d1..3c77f5c7d 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -306,7 +306,7 @@ def main(): module.fail_json(msg="the provider_match is only configurable for Provider Contracts") identifier = contract_type - class_config = {"matchT": provider_match, "prio": priority, aci_name: contract} + class_config = {"matchT": provider_match, "prio": priority, "tnVzBrCPName": contract} elif epg_type == "out_of_band": @@ -317,7 +317,7 @@ def main(): module.fail_json(msg="The provider_match argument is not supported for out_of_band Provider contracts") identifier = "oob_provider" - class_config = {"prio": priority, aci_name: contract} + class_config = {"prio": priority, "tnVzOOBBrCPName": contract} aci_class = ACI_CLASS_MAPPING[identifier]["class"] aci_rn = ACI_CLASS_MAPPING[identifier]["rn"] From a7dbc41b3ba0cae13e899586c7f86de84ebad60e Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Tue, 15 Apr 2025 21:51:15 +0530 Subject: [PATCH 13/16] sent-->proposed. some asserts remaining --- plugins/modules/aci_node_mgmt_epg_to_contract.py | 2 +- .../targets/aci_node_mgmt_epg_to_contract/tasks/main.yml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/modules/aci_node_mgmt_epg_to_contract.py b/plugins/modules/aci_node_mgmt_epg_to_contract.py index 3c77f5c7d..32b3b4669 100644 --- a/plugins/modules/aci_node_mgmt_epg_to_contract.py +++ b/plugins/modules/aci_node_mgmt_epg_to_contract.py @@ -306,7 +306,7 @@ def main(): module.fail_json(msg="the provider_match is only configurable for Provider Contracts") identifier = contract_type - class_config = {"matchT": provider_match, "prio": priority, "tnVzBrCPName": contract} + class_config = {"matchT": provider_match, "prio": priority, ACI_CLASS_MAPPING[contract_type]["name"]: contract} elif epg_type == "out_of_band": diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 56ff369b6..070fd7900 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -100,8 +100,8 @@ - inb_provide_present_check_mode is changed - inb_provide_present_check_mode.previous == [] - inb_provide_present_check_mode.current == [] - - inb_provide_present_check_mode.sent.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" - - inb_provide_present_check_mode.sent.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' + - inb_provide_present_check_mode.proposed.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" + - inb_provide_present_check_mode.proposed.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' - inb_provide_present is changed - inb_provide_present.previous == [] - inb_provide_present.sent == inb_provide_present_check_mode.sent @@ -202,8 +202,8 @@ - oob_provide_present_check_mode is changed - oob_provide_present_check_mode.previous == [] - oob_provide_present_check_mode.current == [] - - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' - - oob_provide_present_check_mode.sent.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" + - oob_provide_present_check_mode.proposed.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' + - oob_provide_present_check_mode.proposed.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" - oob_provide_present is changed - oob_provide_present.previous == [] - oob_provide_present.sent == oob_provide_present_check_mode.sent From 4d1c8454367fa338edaf7420d62f38ac1a363003 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Wed, 16 Apr 2025 17:59:01 +0530 Subject: [PATCH 14/16] test file changes needed --- .../tasks/main.yml | 98 ++++++++----------- 1 file changed, 40 insertions(+), 58 deletions(-) diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 070fd7900..490d8b5da 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -77,9 +77,9 @@ - name: Attach Provider contract to Inband EPG cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present - priority: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'unspecified' - provider_match: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'AtleastOne' - state: "{{ fakevar | default(omit) }}" # >>>> Defaults to 'present' + priority: "{{ fakevar | default(omit) }}" # >>>> Omitting to test Default behaviour + provider_match: "{{ fakevar | default(omit) }}" # >>>> Omitting to test Default behaviour + state: "{{ fakevar | default(omit) }}" # >>>> Omitting to test Default behaviour register: inb_provide_present - name: Attach Provider contract to Inband EPG again @@ -87,13 +87,6 @@ <<: *aci_inb_epg_provide_present register: inb_idempotent_present - - name: Attach one more Provider contract to Inband EPG - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_provide_present2 - <<: *aci_inb_epg_provide_present - contract: aci_inb_https - provider_match: at_most_one - register: inb_provide_present2 - - name: Assert Provider Contracts were attached to Inband EPG ansible.builtin.assert: that: @@ -104,19 +97,11 @@ - inb_provide_present_check_mode.proposed.fvRsProv.attributes.tnVzBrCPName == 'aci_inb_http' - inb_provide_present is changed - inb_provide_present.previous == [] - - inb_provide_present.sent == inb_provide_present_check_mode.sent - inb_provide_present.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" - inb_provide_present.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" - inb_provide_present.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - inb_provide_present.current.0.fvRsProv.attributes.prio == "unspecified" - inb_provide_present.current.0.fvRsProv.attributes.matchT == "AtleastOne" - - inb_provide_present2 is changed - - inb_provide_present2.previous == [] - - inb_provide_present2.current.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_https" - - inb_provide_present2.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_https" - - inb_provide_present2.current.0.fvRsProv.attributes.annotation == 'orchestrator:ansible' - - inb_provide_present2.current.0.fvRsProv.attributes.prio == "unspecified" - - inb_provide_present2.current.0.fvRsProv.attributes.matchT == "AtmostOne" - inb_idempotent_present is not changed - inb_idempotent_present.previous.0.fvRsProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/inb-anstest_inb/rsprov-aci_inb_http" - inb_idempotent_present.previous.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" @@ -254,14 +239,20 @@ - upd_inb_consumer is changed - upd_inb_consumer.previous.0.fvRsCons.attributes.prio == "unspecified" - upd_inb_consumer.current.0.fvRsCons.attributes.prio == "level6" + - upd_inb_consumer.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - upd_inb_consumer.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" - upd_inb_provider is changed - upd_inb_provider.previous.0.fvRsProv.attributes.prio == "unspecified" - upd_inb_provider.previous.0.fvRsProv.attributes.matchT == "AtleastOne" - upd_inb_provider.current.0.fvRsProv.attributes.prio == "level4" - upd_inb_provider.current.0.fvRsProv.attributes.matchT == "AtleastOne" + - upd_inb_provider.previous.0.fvRsProv.attributes.tnVzBrCPName == "anstest_inb_http" + - upd_inb_provider.current.0.fvRsProv.attributes.tnVzBrCPName == "anstest_inb_http" - upd_oob_provider is changed - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.prio == "unspecified" - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.prio == "level4" + - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.name == "aci_oob_http" + - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.name == "aci_oob_http" #MISSING PARAMS @@ -318,7 +309,7 @@ # QUERY - name: Query Inband EPG for Provider contract cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present2 + <<: *aci_inb_epg_provide_present state: query register: query_inb_provide_contract @@ -330,11 +321,11 @@ - name: Query Out-of-Band EPG for Provider contract cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_oob_epg_provide_present2 + <<: *aci_oob_epg_provide_present state: query register: query_oob_provide_contract - - name: Get all Inband EPG provider bindings + - name: Get all Inband EPG provider bindings # Should have more than 1 contract to demonstrate query all. Create one if necessary, no need to register in a variable cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: in_band @@ -344,7 +335,7 @@ register: query_inb_all ignore_errors: yes - - name: get all Out_of_Band EPG provider bindings + - name: Get all Out_of_Band EPG provider bindings # Should have more than 1 contract to demonstrate query all. Create one if necessary, no need to register in a variable cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: out_of_band @@ -354,7 +345,7 @@ register: query_oob_all ignore_errors: yes - - name: missing required param - failure message works + - name: Missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info state: query @@ -363,78 +354,62 @@ ignore_errors: true register: missing_required_query + +# ADD MORE ASSERTS FOR QUERY CURRENT attributes +# add length assertion for all queries + - name: Assert INB & OOB contracts were queried ansible.builtin.assert: that: - query_inb_provide_contract is not changed - query_inb_provide_contract.current != [] - - '"/api/class/mgmtInB.json" in query_inb_provide_contract.url' - - query_inb_provide_contract.filter_string is search('query-target-filter=eq\(mgmtInB.name,"anstest_inb"\)') - - query_inb_provide_contract.filter_string is search('rsp-subtree-filter=eq\(fvRsProv.tnVzBrCPName,"aci_inb_https"\)') - query_inb_consume_contract is not changed - query_inb_consume_contract.current != [] - - query_inb_consume_contract.filter_string is search('query-target-filter=eq\\(mgmtInB.name,"anstest_inb"\\)') - - query_inb_consume_contract.filter_string is search('rsp-subtree-filter=eq\\(fvRsCons.tnVzBrCPName,"anstest_inb_db"\\)') - query_oob_provide_contract is not changed - query_oob_provide_contract.current != [] - - '"/api/class/mgmtOoB.json" in query_oob_provide_contract.url' - query_inb_all is not changed - - query_inb_all.filter_string == "" - query_oob_all is not changed - - query_oob_all.filter_string == "" - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"' # DELETE - - name: delete inb consumer binding - check mode works + - name: Delete inb consumer binding - check mode works cisco.aci.aci_node_mgmt_epg_to_contract: &aci_inb_epg_consume_absent <<: *aci_inb_epg_consume_present state: absent check_mode: true register: consume_absent_check_mode - - name: delete inb consumer binding + - name: Delete inb consumer binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent - - name: delete inb consumer binding again + - name: Delete inb consumer binding again cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent register: consume_absent_idempotent - - name: delete inb provider binding + - name: Delete inb provider binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present state: absent register: inb_provide_absent - - name: delete inb provider binding 2 - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_inb_epg_provide_present2 - state: absent - register: inb_provide_absent2 - - - name: delete oob provider binding + - name: Delete oob provider binding cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_oob_epg_provide_present state: absent register: oob_provide_absent - - name: delete oob provider binding 2 - cisco.aci.aci_node_mgmt_epg_to_contract: - <<: *aci_oob_epg_provide_present2 - state: absent - register: oob_provide_absent2 - - - name: missing param - failure message works + - name: Missing param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent contract: "{{ fakevar | default(omit) }}" ignore_errors: true register: missing_param_absent - - name: missing required param - failure message works + - name: Missing required param - failure message works cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_consume_absent epg_type: "{{ fakevar | default(omit) }}" @@ -445,27 +420,34 @@ ansible.builtin.assert: that: - consume_absent_check_mode is changed - - consume_absent_check_mode.previous.0.fvRsCons is defined + - consume_absent_check_mode.previous.0.fvRsCons is defined + # add proposed + # add current + # check all attributes in check mode - consume_absent is changed - consume_absent.previous == consume_absent_check_mode.previous - - inb_provide_absent is changed - - inb_provide_absent.previous.0.fvRsProv is defined - - inb_provide_absent2 is changed + - consume_absent.current == [] + - consume_absent.previous.0.fvRsCons.tnVzBrCPName == "anstest_inb_db" + # add all other attributes as well - consume_absent_idempotent is not changed + - consume_absent_idempotent.current == [] - consume_absent_idempotent.previous == [] + - inb_provide_absent is changed + - inb_provide_absent.current == [] + - inb_provide_absent.previous.0.fvRsProv.attributes.tnVzBRcPName == "aci_inb_http" - oob_provide_absent is changed - - oob_provide_absent.previous.0.mgmtRsOoBProv is defined - - oob_provide_absent2 is changed + - oob_provide_absent.previous.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' + - oob_provide_absent.current == [] - missing_param_absent is failed - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' - missing_required_absent is failed - 'missing_required_absent.msg == "missing required arguments: epg_type"' #CLEANUP - - name: cleanup OOB epg + - name: Cleanup OOB epg cisco.aci.aci_node_mgmt_epg: <<: *aci_oob_epg_absent - - name: cleanup INB epg + - name: Cleanup INB epg cisco.aci.aci_node_mgmt_epg: <<: *aci_inb_epg_absent From 0d36e15dc1389f00055269a09a3e267607c944d8 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Thu, 24 Apr 2025 18:29:02 +0530 Subject: [PATCH 15/16] all assertions completed as requested. Tests pass as well --- .../tasks/main.yml | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 490d8b5da..053afeefc 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -175,12 +175,6 @@ <<: *aci_oob_epg_provide_present register: oob_idempotent_present - - name: Attach one more Provider contract to Out-of-Band EPG - cisco.aci.aci_node_mgmt_epg_to_contract: &aci_oob_epg_provide_present2 - <<: *aci_oob_epg_provide_present - contract: aci_oob_https - register: oob_provide_present2 - - name: Assert Provider contracts to Out-of-Band EPG were attached ansible.builtin.assert: that: @@ -196,12 +190,6 @@ - oob_provide_present.sent.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_http" - oob_provide_present.current.0.mgmtRsOoBProv.attributes.prio == "unspecified" - oob_provide_present.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' - - oob_provide_present2 is changed - - oob_provide_present2.previous == [] - - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.annotation == 'orchestrator:ansible' - - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_https' - - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.dn == "uni/tn-mgmt/mgmtp-default/oob-anstest_oob/rsooBProv-aci_oob_https" - - oob_provide_present2.current.0.mgmtRsOoBProv.attributes.prio == "unspecified" # UPDATE - name: Update Consumer Contract to Inband EPG (check_mode) @@ -246,13 +234,13 @@ - upd_inb_provider.previous.0.fvRsProv.attributes.matchT == "AtleastOne" - upd_inb_provider.current.0.fvRsProv.attributes.prio == "level4" - upd_inb_provider.current.0.fvRsProv.attributes.matchT == "AtleastOne" - - upd_inb_provider.previous.0.fvRsProv.attributes.tnVzBrCPName == "anstest_inb_http" - - upd_inb_provider.current.0.fvRsProv.attributes.tnVzBrCPName == "anstest_inb_http" + - upd_inb_provider.previous.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - upd_inb_provider.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" - upd_oob_provider is changed - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.prio == "unspecified" - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.prio == "level4" - - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.name == "aci_oob_http" - - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.name == "aci_oob_http" + - upd_oob_provider.previous.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" + - upd_oob_provider.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" #MISSING PARAMS @@ -307,6 +295,16 @@ - 'inb_incompatible_present.msg == "the provider_match is only configurable for Provider Contracts"' # QUERY + - name: Create another Provider contract to Inband EPG + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_inb_epg_provide_present + contract: aci_inb_https + + - name: Create another Provider contract to Out-of-Band EPG + cisco.aci.aci_node_mgmt_epg_to_contract: + <<: *aci_oob_epg_provide_present + contract: aci_oob_https + - name: Query Inband EPG for Provider contract cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_inb_epg_provide_present @@ -325,7 +323,7 @@ state: query register: query_oob_provide_contract - - name: Get all Inband EPG provider bindings # Should have more than 1 contract to demonstrate query all. Create one if necessary, no need to register in a variable + - name: Get all Inband EPG provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: in_band @@ -335,7 +333,7 @@ register: query_inb_all ignore_errors: yes - - name: Get all Out_of_Band EPG provider bindings # Should have more than 1 contract to demonstrate query all. Create one if necessary, no need to register in a variable + - name: Get all Out_of_Band EPG provider bindings cisco.aci.aci_node_mgmt_epg_to_contract: <<: *aci_info epg_type: out_of_band @@ -354,21 +352,26 @@ ignore_errors: true register: missing_required_query - -# ADD MORE ASSERTS FOR QUERY CURRENT attributes -# add length assertion for all queries - - name: Assert INB & OOB contracts were queried ansible.builtin.assert: that: - query_inb_provide_contract is not changed - - query_inb_provide_contract.current != [] + - query_inb_provide_contract.current.0.mgmtInB.attributes.name == "anstest_inb" + - query_inb_provide_contract.current.0.mgmtInB.children.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - query_inb_provide_contract.current.0.mgmtInB.children.0.fvRsProv.attributes.prio == "level4" + - query_inb_provide_contract.current.0.mgmtInB.children.0.fvRsProv.attributes.matchT == "AtleastOne" - query_inb_consume_contract is not changed - - query_inb_consume_contract.current != [] + - query_inb_consume_contract.current.0.mgmtInB.attributes.name == "anstest_inb" + - query_inb_consume_contract.current.0.mgmtInB.children.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - query_inb_consume_contract.current.0.mgmtInB.children.0.fvRsCons.attributes.prio == "level6" - query_oob_provide_contract is not changed - - query_oob_provide_contract.current != [] + - query_oob_provide_contract.current.0.mgmtOoB.attributes.name == "anstest_oob" + - query_oob_provide_contract.current.0.mgmtOoB.children.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" + - query_oob_provide_contract.current.0.mgmtOoB.children.0.mgmtRsOoBProv.attributes.prio == "level4" - query_inb_all is not changed + - query_inb_all.current | length > 1 - query_oob_all is not changed + - query_oob_all.current | length > 1 - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"' @@ -421,22 +424,25 @@ that: - consume_absent_check_mode is changed - consume_absent_check_mode.previous.0.fvRsCons is defined - # add proposed - # add current - # check all attributes in check mode + - consume_absent_check_mode.proposed == {} + - consume_absent_check_mode.current.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - consume_absent_check_mode.current.0.fvRsCons.attributes.prio == "level6" - consume_absent is changed - consume_absent.previous == consume_absent_check_mode.previous - consume_absent.current == [] - - consume_absent.previous.0.fvRsCons.tnVzBrCPName == "anstest_inb_db" - # add all other attributes as well + - consume_absent.previous.0.fvRsCons.attributes.tnVzBrCPName == "anstest_inb_db" + - consume_absent.previous.0.fvRsCons.attributes.prio == "level6" - consume_absent_idempotent is not changed - consume_absent_idempotent.current == [] - consume_absent_idempotent.previous == [] - inb_provide_absent is changed - inb_provide_absent.current == [] - - inb_provide_absent.previous.0.fvRsProv.attributes.tnVzBRcPName == "aci_inb_http" + - inb_provide_absent.previous.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - inb_provide_absent.previous.0.fvRsProv.attributes.prio == "level4" + - inb_provide_absent.previous.0.fvRsProv.attributes.matchT == "AtleastOne" - oob_provide_absent is changed - oob_provide_absent.previous.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == 'aci_oob_http' + - oob_provide_absent.previous.0.mgmtRsOoBProv.attributes.prio == 'level4' - oob_provide_absent.current == [] - missing_param_absent is failed - 'missing_param_absent.msg == "state is absent but all of the following are missing: contract"' From 4039642728b28604d6ec6e05d55d664641866240 Mon Sep 17 00:00:00 2001 From: Ziaf007 Date: Tue, 13 May 2025 16:57:23 +0530 Subject: [PATCH 16/16] all tests pass. module completely ready --- .../aci_node_mgmt_epg_to_contract/tasks/main.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml index 053afeefc..66d70a880 100644 --- a/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml +++ b/tests/integration/targets/aci_node_mgmt_epg_to_contract/tasks/main.yml @@ -370,8 +370,18 @@ - query_oob_provide_contract.current.0.mgmtOoB.children.0.mgmtRsOoBProv.attributes.prio == "level4" - query_inb_all is not changed - query_inb_all.current | length > 1 + - query_inb_all.current.0.fvRsProv.attributes.tnVzBrCPName == "aci_inb_http" + - query_inb_all.current.0.fvRsProv.attributes.prio == "level4" + - query_inb_all.current.0.fvRsProv.attributes.matchT == "AtleastOne" + - query_inb_all.current.1.fvRsProv.attributes.tnVzBrCPName == "aci_inb_https" + - query_inb_all.current.1.fvRsProv.attributes.prio == "unspecified" + - query_inb_all.current.1.fvRsProv.attributes.matchT == "AtleastOne" - query_oob_all is not changed - query_oob_all.current | length > 1 + - query_oob_all.current.0.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_http" + - query_oob_all.current.0.mgmtRsOoBProv.attributes.prio == "level4" + - query_oob_all.current.1.mgmtRsOoBProv.attributes.tnVzOOBBrCPName == "aci_oob_https" + - query_oob_all.current.1.mgmtRsOoBProv.attributes.prio == "unspecified" - missing_required_query is failed - 'missing_required_query.msg == "missing required arguments: epg_type"'