From f7287e895c93a36f84455a30a7b446b73ffbe15e Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:32:57 +0530 Subject: [PATCH 01/12] [minor_change] Added ndo_l3out_node_group_policy module to manage L3Out Node/Interface Group Policy --- plugins/module_utils/template.py | 34 + .../modules/ndo_l3out_node_group_policy.py | 316 ++++++++++ .../ndo_l3out_node_group_policy/aliases | 2 + .../tasks/main.yml | 591 ++++++++++++++++++ 4 files changed, 943 insertions(+) create mode 100644 plugins/modules/ndo_l3out_node_group_policy.py create mode 100644 tests/integration/targets/ndo_l3out_node_group_policy/aliases create mode 100644 tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml diff --git a/plugins/module_utils/template.py b/plugins/module_utils/template.py index 011e5e7d..62bd0593 100644 --- a/plugins/module_utils/template.py +++ b/plugins/module_utils/template.py @@ -218,3 +218,37 @@ def get_interface_policy_group_uuid(self, interface_policy_group): kv_list = [KVPair("name", interface_policy_group)] match = self.get_object_by_key_value_pairs("Interface Policy Groups", existing_policy_groups, kv_list, fail_module=True) return match.details.get("uuid") + + def get_l3out_object(self, uuid=None, name=None, fail_module=False): + """ + Get the L3Out by uuid or name. + :param uuid: UUID of the L3Out to search for -> Str + :param name: Name of the L3Out to search for -> Str + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + existing_l3outs = self.template.get("l3outTemplate", {}).get("l3outs", []) + if uuid or name: # Query a specific object + return self.get_object_by_key_value_pairs("L3Out", existing_l3outs, [KVPair("uuid", uuid) if uuid else KVPair("name", name)], fail_module) + return existing_l3outs # Query all objects + + def get_l3out_node_group(self, name, l3out_object, fail_module=False): + """ + Get the L3Out Node/Interface Group Policy by name. + :param name: Name of the L3Out Node/Interface Group Policy to search for -> Str + :param l3out_object: L3Out object to search Node/Interface Group Policy -> Dict + :param fail_module: When match is not found fail the ansible module -> Bool + :return: Dict | None | List[Dict] | List[]: The processed result which could be: + When the UUID | Name is existing in the search list -> Dict + When the UUID | Name is not existing in the search list -> None + When both UUID and Name are None, and the search list is not empty -> List[Dict] + When both UUID and Name are None, and the search list is empty -> List[] + """ + existing_l3out_node_groups = l3out_object.get("nodeGroups", []) + if name: # Query a specific object + return self.get_object_by_key_value_pairs("L3Out Node/Interface Group Policy", existing_l3out_node_groups, [KVPair("name", name)], fail_module) + return existing_l3out_node_groups # Query all objects diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py new file mode 100644 index 00000000..bf4d878e --- /dev/null +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -0,0 +1,316 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2024, Sabari Jaganathan (@sajagana) + +# GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = {"metadata_version": "1.1", "status": ["preview"], "supported_by": "community"} + +DOCUMENTATION = r""" +--- +module: ndo_l3out_node_group_policy +short_description: Manage L3Out Node/Interface Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). +description: +- Manage L3Out Node/Interface Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). +- This module is only supported on ND v3.1 (NDO v4.3) and later. +author: +- Sabari Jaganathan (@sajagana) +options: + template: + description: + - The name of the template. + - The template must be a L3Out template. + type: str + required: true + l3out: + description: + - The name of the L3Out. + type: str + required: true + name: + description: + - The name of the L3Out Node/Interface Group Policy. + type: str + description: + description: + - The description of the L3Out Node/Interface Group Policy. + type: str + node_routing_policy: + description: + - The name of the L3Out Node Routing Policy. + type: str + bfd_multi_hop_authentication: + description: + - The bidirectional forwarding detection (BFD) multi-hop authentication of the L3Out Node/Interface Group Policy. + - To enable the O(bfd_multi_hop_authentication) BGP routing protocol must be configured on the L3Out. + type: str + choices: [ enabled, disabled ] + bfd_multi_hop_key_id: + description: + - The BFD multi-hop key ID of the L3Out Node/Interface Group Policy. + type: int + bfd_multi_hop_key: + description: + - The BFD multi-hop key of the L3Out Node/Interface Group Policy. + type: str + target_dscp: + description: + - The DSCP Level of the L3Out Node/Interface Group Policy. + type: str + choices: + - af11 + - af12 + - af13 + - af21 + - af22 + - af23 + - af31 + - af32 + - af33 + - af41 + - af42 + - af43 + - cs0 + - cs1 + - cs2 + - cs3 + - cs4 + - cs5 + - cs6 + - cs7 + - expedited_forwarding + - unspecified + - voice_admit + state: + description: + - Use C(absent) for removing. + - Use C(query) for listing an object or multiple objects. + - Use C(present) for creating or updating. + type: str + choices: [ absent, query, present ] + default: query +notes: +- The O(template) must exist before using this module in your playbook. + Use M(cisco.mso.ndo_template) to create the L3Out template. +- The O(l3out) must exist before using this module in your playbook. + Use M(cisco.mso.ndo_l3out_template) to create the L3Out object under the L3Out template. +- The O(node_routing_policy) must exist before using this module in your playbook. + Use M(cisco.mso.ndo_l3out_node_routing_policy) to create the L3Out Node Routing Policy. +extends_documentation_fragment: cisco.mso.modules +""" + +EXAMPLES = r""" +- name: Create a new L3Out node group policy + cisco.mso.ndo_l3out_node_group_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: l3out_template + l3out: l3out + name: "node_group_policy_1" + state: present + +- name: Update an existing L3Out node group policy + cisco.mso.ndo_l3out_node_group_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: l3out_template + l3out: l3out + name: "node_group_policy_1" + description: "Updated description" + node_routing_policy: ans_node_policy_group_1 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key_id: 1 + bfd_multi_hop_key: TestKey + target_dscp: af11 + state: present + +- name: Query a L3Out node group policy + cisco.mso.ndo_l3out_node_group_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: l3out_template + l3out: l3out + name: "node_group_policy_1" + state: query + register: query_with_name + +- name: Delete an existing L3Out node group policy with name + cisco.mso.ndo_l3out_node_group_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: l3out_template + l3out: l3out + name: "node_group_policy_1" + state: absent +""" + +RETURN = r""" +""" + + +import copy +from ansible.module_utils.basic import AnsibleModule +from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec +from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair +from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP +from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint + + +def main(): + argument_spec = mso_argument_spec() + argument_spec.update( + template=dict(type="str", required=True), # L3Out template name + l3out=dict(type="str", required=True), # L3Out name + name=dict(type="str"), # L3Out Node/Interface Group Policy name + description=dict(type="str"), + node_routing_policy=dict(type="str"), + bfd_multi_hop_authentication=dict(type="str", choices=["enabled", "disabled"]), + bfd_multi_hop_key_id=dict(type="int"), + bfd_multi_hop_key=dict(type="str", no_log=False), + target_dscp=dict(type="str", choices=list(TARGET_DSCP_MAP)), + state=dict(type="str", default="query", choices=["absent", "query", "present"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "absent", ["name"]], + ["state", "present", ["name"]], + ["bfd_multi_hop_authentication", "enabled", ["bfd_multi_hop_key_id", "bfd_multi_hop_key"]], + ], + ) + + mso = MSOModule(module) + + template = module.params.get("template") + l3out = module.params.get("l3out") + name = module.params.get("name") + description = module.params.get("description") + node_routing_policy = module.params.get("node_routing_policy") + bfd_multi_hop_authentication = module.params.get("bfd_multi_hop_authentication") + bfd_multi_hop_key_id = module.params.get("bfd_multi_hop_key_id") + bfd_multi_hop_key = module.params.get("bfd_multi_hop_key") + target_dscp = TARGET_DSCP_MAP.get(module.params.get("target_dscp")) + state = module.params.get("state") + + mso_template = MSOTemplate(mso, "l3out", template) + mso_template.validate_template("l3out") + + l3out_object = mso_template.get_l3out_object(name=l3out, fail_module=True) + l3out_node_group = mso_template.get_l3out_node_group(name, l3out_object.details) + + if name: + if l3out_node_group: + mso.existing = mso.previous = copy.deepcopy(l3out_node_group.details) # Query a specific object + elif l3out_node_group: + mso.existing = l3out_node_group # Query all objects + + if state != "query": + node_group_policy_path = "/l3outTemplate/l3outs/{0}/nodeGroups/{1}".format(l3out_object.index, l3out_node_group.index if l3out_node_group else "-") + + ops = [] + + if state == "present": + l3out_node_routing_policy_object = None + if node_routing_policy: + l3out_node_routing_policy_objects = mso.query_objs( + generate_api_endpoint( + "templates/objects", **{"type": "l3OutNodePolGroup", "tenant-id": mso_template.template_summary.get("tenantId"), "include-common": "true"} + ) + ) + l3out_node_routing_policy_object = mso_template.get_object_by_key_value_pairs( + "L3Out Node Routing Policy", l3out_node_routing_policy_objects, [KVPair("name", node_routing_policy)], True + ) + + if mso.existing: + proposed_payload = copy.deepcopy(mso.existing) + + if description is not None and mso.existing.get("description") != description: + ops.append(dict(op="replace", path=node_group_policy_path + "/description", value=description)) + proposed_payload["description"] = description + + if ( + node_routing_policy is not None + and l3out_node_routing_policy_object + and mso.existing.get("nodeRoutingPolicyRef") != l3out_node_routing_policy_object.details.get("uuid") + ): + ops.append( + dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=l3out_node_routing_policy_object.details.get("uuid")) + ) + proposed_payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") + elif node_routing_policy == "" and mso.existing.get("nodeRoutingPolicyRef"): + ops.append(dict(op="remove", path=node_group_policy_path + "/nodeRoutingPolicyRef")) + proposed_payload.pop("nodeRoutingPolicyRef", None) + + if bfd_multi_hop_authentication == "enabled": + if not mso.existing.get("bfdMultiHop"): + proposed_payload["bfdMultiHop"] = dict() + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) + + if mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) + proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id + + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/value", value=bfd_multi_hop_key)) + proposed_payload["bfdMultiHop"]["value"] = bfd_multi_hop_key + + elif bfd_multi_hop_authentication == "disabled" and mso.existing.get("bfdMultiHop"): + proposed_payload.pop("bfdMultiHop", None) + ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) + + if target_dscp is not None and mso.existing.get("targetDscp") != target_dscp: + ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) + proposed_payload["targetDscp"] = target_dscp + + mso.sanitize(proposed_payload, collate=True) + + else: + payload = dict(name=name) + + if description: + payload["description"] = description + + if node_routing_policy and l3out_node_routing_policy_object: + payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") + + if bfd_multi_hop_authentication == "enabled": + payload["bfdMultiHop"] = dict(authEnabled=True, keyID=bfd_multi_hop_key_id, key=dict(value=bfd_multi_hop_key)) + + if target_dscp: + payload["targetDscp"] = target_dscp + + mso.sanitize(payload) + ops.append(dict(op="add", path=node_group_policy_path, value=payload)) + + mso.existing = mso.proposed + + elif state == "absent": + if mso.existing: + ops.append(dict(op="remove", path=node_group_policy_path)) + + if not module.check_mode and ops: + mso_template.template = mso.request(mso_template.template_path, method="PATCH", data=ops) + l3out_object = mso_template.get_l3out_object(name=l3out, fail_module=True) + l3out_node_group = mso_template.get_l3out_node_group(name, l3out_object.details) + if l3out_node_group: + mso.existing = l3out_node_group.details # When the state is present + else: + mso.existing = {} # When the state is absent + elif module.check_mode and state != "query": # When the state is present/absent with check mode + mso.existing = mso.proposed if state == "present" else {} + + mso.exit_json() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/aliases b/tests/integration/targets/ndo_l3out_node_group_policy/aliases new file mode 100644 index 00000000..5042c9c0 --- /dev/null +++ b/tests/integration/targets/ndo_l3out_node_group_policy/aliases @@ -0,0 +1,2 @@ +# No ACI MultiSite infrastructure, so not enabled +# unsupported diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml new file mode 100644 index 00000000..6b7ac110 --- /dev/null +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -0,0 +1,591 @@ +# Test code for the MSO modules +# Copyright: (c) 2024, Sabari Jaganathan (@sajagana) + +# 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 MultiSite host, username and password + ansible.builtin.fail: + msg: "Please define the following variables: mso_hostname, mso_username and mso_password." + when: mso_hostname is not defined or mso_username is not defined or mso_password is not defined + +# CLEAN ENVIRONMENT +- name: Set vars + ansible.builtin.set_fact: + mso_info: &mso_info + host: "{{ mso_hostname }}" + username: "{{ mso_username }}" + password: "{{ mso_password }}" + validate_certs: "{{ mso_validate_certs | default(false) }}" + use_ssl: "{{ mso_use_ssl | default(true) }}" + use_proxy: "{{ mso_use_proxy | default(true) }}" + output_level: '{{ mso_output_level | default("info") }}' + +# QUERY VERSION +- name: Query MSO version + cisco.mso.mso_version: + <<: *mso_info + state: query + register: version + +- name: Execute tasks only for NDO version > 4.2 + when: version.current.version is version('4.2', '>') + block: + # Setup Part + - name: Ensure l3out template not exist + cisco.mso.ndo_template: &ndo_l3out_template_absent + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + template_type: l3out + tenant: '{{ ansible_tenant | default("ansible_test") }}' + sites: + - name: '{{ mso_site | default("ansible_test") }}' + state: absent + + - name: Ensure ansible_test_policy tenant policy template not exists + cisco.mso.ndo_template: &tenant_pol_template_absent + <<: *mso_info + name: ansible_test_policy + template_type: tenant + tenant: '{{ ansible_tenant | default("ansible_test") }}' + state: absent + + - name: Ensure common tenant policy template not exists + cisco.mso.ndo_template: &common_ansible_test_policy + <<: *tenant_pol_template_absent + name: common_ansible_test_policy + tenant: common + state: absent + + - name: Ensure ansible_test schema template not exist + cisco.mso.mso_schema_template: &mso_schema_template_absent + <<: *mso_info + schema: '{{ ansible_schema | default("ansible_test") }}' + tenant: '{{ ansible_tenant | default("ansible_test") }}' + template: "Template1" + state: absent + + - name: Ensure ansible_test site exist + cisco.mso.mso_site: + <<: *mso_info + site: '{{ mso_site | default("ansible_test") }}' + state: query + register: ansible_test_site + + - name: Ensure ansible_test tenant exist + cisco.mso.mso_tenant: + <<: *mso_info + tenant: '{{ ansible_tenant | default("ansible_test") }}' + users: + - "{{ mso_username }}" + sites: + - '{{ mso_site | default("ansible_test") }}' + state: present + register: ansible_test_tenant + when: ansible_test_site.current.common.name == 'ansible_test' + + - name: Ensure common tenant exist + cisco.mso.mso_tenant: + <<: *mso_info + tenant: common + users: + - "{{ mso_username }}" + sites: + - '{{ mso_site | default("ansible_test") }}' + state: present + register: ansible_test_tenant + when: ansible_test_site.current.common.name == 'ansible_test' + + # Schema Template Setup for the VRF + - name: Add an ansible_test schema template + cisco.mso.mso_schema_template: + <<: *mso_schema_template_absent + state: present + + - name: Add a new VRF1 + cisco.mso.mso_schema_template_vrf: + <<: *mso_info + schema: '{{ ansible_schema | default("ansible_test") }}' + template: "Template1" + vrf: VRF1 + layer3_multicast: true + state: present + + # Tenant Policy Template Setup for the L3Out Node Routing Policy + - name: Ensure ansible_test_policy tenant policy template exists + cisco.mso.ndo_template: + <<: *tenant_pol_template_absent + state: present + register: ansible_test_policy + + - name: Ensure common tenant policy template exists + cisco.mso.ndo_template: + <<: *common_ansible_test_policy + state: present + register: common_ansible_test_policy + + - name: Add a new L3Out Node Routing Policy + cisco.mso.ndo_l3out_node_routing_policy: + <<: *mso_info + template: ansible_test_policy + name: "{{ item }}" + bfd_multi_hop_settings: + state: enabled + bgp_node_settings: + state: enabled + as_path_multipath_relax: enabled + state: present + loop: + - ans_node_policy_group_1 + - ans_node_policy_group_2 + + - name: Add a new L3Out Node Routing Policy to the common template + cisco.mso.ndo_l3out_node_routing_policy: + <<: *mso_info + template: common_ansible_test_policy + name: ans_node_policy_group_common + bfd_multi_hop_settings: + state: enabled + bgp_node_settings: + state: enabled + as_path_multipath_relax: enabled + state: present + + # L3Out Template Setup + - name: Create a new l3out template + cisco.mso.ndo_template: + <<: *ndo_l3out_template_absent + state: present + register: create_new_l3out_policy_template + + - name: Create l3out_1 object without routing protocols + cisco.mso.ndo_l3out_template: &l3out_1_present + <<: *mso_info + l3out_template: '{{ ansible_l3out_template | default("ansible_test") }}' + name: "l3out_1" + vrf: + name: "VRF1" + schema: '{{ ansible_schema | default("ansible_test") }}' + template: "Template1" + state: "present" + + - name: Create l3out_2 object with bgp enabled + cisco.mso.ndo_l3out_template: + <<: *l3out_1_present + name: "l3out_2" + bgp: + state: enabled + + # Test Part + - name: Query all L3Out node group policy objects when the L3Out is empty + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + state: query + register: query_all_node_groups_1 + + - name: Assertion check for query all L3Out node group policy objects when the L3Out is empty + ansible.builtin.assert: + that: + - query_all_node_groups_1 is not changed + - query_all_node_groups_1.current == {} + + - name: Query node_group_policy_1 L3Out node group policy object when the L3Out is empty + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + state: query + register: query_node_group_policy_1 + + - name: Assertion check for query node_group_policy_1 L3Out node group policy object when the L3Out is empty + ansible.builtin.assert: + that: + - query_node_group_policy_1 is not changed + - query_node_group_policy_1.current == {} + + - name: Create L3Out node group policy object with default values - check mode + cisco.mso.ndo_l3out_node_group_policy: &cm_node_group_policy_1_present + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + state: present + check_mode: true + register: cm_node_group_policy_1_present + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object with default values - check mode + ansible.builtin.assert: + that: + - cm_node_group_policy_1_present is changed + - cm_node_group_policy_1_present.current.name == "node_group_policy_1" + - cm_node_group_policy_1_present.previous == {} + + - name: Create L3Out node group policy object with default values - normal mode + cisco.mso.ndo_l3out_node_group_policy: &nm_node_group_policy_1_present + <<: *cm_node_group_policy_1_present + register: nm_node_group_policy_1_present + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object with default values - normal mode + ansible.builtin.assert: + that: + - nm_node_group_policy_1_present is changed + - nm_node_group_policy_1_present.current.name == "node_group_policy_1" + - nm_node_group_policy_1_present.current.nodeRoutingPolicyRef == "" + - nm_node_group_policy_1_present.current.targetDscp == "unspecified" + - nm_node_group_policy_1_present.previous == {} + + - name: Create L3Out node group policy object with default values - normal mode again + cisco.mso.ndo_l3out_node_group_policy: + <<: *nm_node_group_policy_1_present + register: nm_node_group_policy_1_present_again + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object with default values - normal mode again + ansible.builtin.assert: + that: + - nm_node_group_policy_1_present_again is not changed + - nm_node_group_policy_1_present_again.current.name == "node_group_policy_1" + - nm_node_group_policy_1_present_again.current.nodeRoutingPolicyRef == "" + - nm_node_group_policy_1_present_again.current.targetDscp == "unspecified" + - nm_node_group_policy_1_present_again.previous.name == "node_group_policy_1" + - nm_node_group_policy_1_present_again.previous.nodeRoutingPolicyRef == "" + - nm_node_group_policy_1_present_again.previous.targetDscp == "unspecified" + + - name: Update L3Out node group policy object with check mode + cisco.mso.ndo_l3out_node_group_policy: &cm_update_node_group_policy_1 + <<: *nm_node_group_policy_1_present + description: "Test description" + node_routing_policy: ans_node_policy_group_1 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key_id: 1 + bfd_multi_hop_key: TestKey + target_dscp: af11 + state: present + check_mode: true + register: cm_update_node_group_policy_1 + ignore_errors: true + + - name: Assertion check for update L3Out node group policy object with check mode + ansible.builtin.assert: + that: + - cm_update_node_group_policy_1 is changed + - cm_update_node_group_policy_1.current.bfdMultiHop.keyID == 1 + - cm_update_node_group_policy_1.current.bfdMultiHop.value == "TestKey" + - cm_update_node_group_policy_1.current.description == "Test description" + - cm_update_node_group_policy_1.current.name == "node_group_policy_1" + - cm_update_node_group_policy_1.current.nodeRoutingPolicyRef != "" + - cm_update_node_group_policy_1.current.targetDscp == "af11" + - cm_update_node_group_policy_1.previous.name == "node_group_policy_1" + - cm_update_node_group_policy_1.previous.nodeRoutingPolicyRef == "" + - cm_update_node_group_policy_1.previous.targetDscp == "unspecified" + + - name: Update L3Out node group policy object with normal mode + cisco.mso.ndo_l3out_node_group_policy: &nm_update_node_group_policy_1 + <<: *cm_update_node_group_policy_1 + register: nm_update_node_group_policy_1 + ignore_errors: true + + - name: Assertion check for update L3Out node group policy object with normal mode + ansible.builtin.assert: + that: + - nm_update_node_group_policy_1 is changed + - nm_update_node_group_policy_1.current.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1.current.bfdMultiHop.keyID == 1 + - nm_update_node_group_policy_1.current.description == "Test description" + - nm_update_node_group_policy_1.current.name == "node_group_policy_1" + - nm_update_node_group_policy_1.current.nodeRoutingPolicyRef != "" + - nm_update_node_group_policy_1.current.targetDscp == "af11" + - nm_update_node_group_policy_1.previous.name == "node_group_policy_1" + - nm_update_node_group_policy_1.previous.nodeRoutingPolicyRef == "" + - nm_update_node_group_policy_1.previous.targetDscp == "unspecified" + + - name: Update L3Out node group policy object with normal mode again + cisco.mso.ndo_l3out_node_group_policy: + <<: *nm_update_node_group_policy_1 + register: nm_update_node_group_policy_1_again + ignore_errors: true + + - name: Assertion check for update L3Out node group policy object with normal mode again + ansible.builtin.assert: + that: + - nm_update_node_group_policy_1_again is not changed + - nm_update_node_group_policy_1_again.current.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1_again.current.bfdMultiHop.keyID == 1 + - nm_update_node_group_policy_1_again.current.description == "Test description" + - nm_update_node_group_policy_1_again.current.name == "node_group_policy_1" + - nm_update_node_group_policy_1_again.current.nodeRoutingPolicyRef != "" + - nm_update_node_group_policy_1_again.current.targetDscp == "af11" + - nm_update_node_group_policy_1_again.previous.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1_again.previous.bfdMultiHop.keyID == 1 + - nm_update_node_group_policy_1_again.previous.description == "Test description" + - nm_update_node_group_policy_1_again.previous.name == "node_group_policy_1" + - nm_update_node_group_policy_1_again.previous.nodeRoutingPolicyRef != "" + - nm_update_node_group_policy_1_again.previous.targetDscp == "af11" + + - name: Update node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + description: "Test description updated" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key_id: 2 + bfd_multi_hop_key: TestKeyUpdated + target_dscp: af12 + state: present + register: update_node_group_policy_attrs + ignore_errors: true + + - name: Assertion check for update node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values + ansible.builtin.assert: + that: + - update_node_group_policy_attrs is changed + - update_node_group_policy_attrs.current.bfdMultiHop.authEnabled == false + - update_node_group_policy_attrs.current.bfdMultiHop.keyID == 2 + - update_node_group_policy_attrs.current.description == "Test description updated" + - update_node_group_policy_attrs.current.name == "node_group_policy_1" + - update_node_group_policy_attrs.current.nodeRoutingPolicyRef != "" + - update_node_group_policy_attrs.current.targetDscp == "af12" + - update_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == false + - update_node_group_policy_attrs.previous.bfdMultiHop.keyID == 1 + - update_node_group_policy_attrs.previous.description == "Test description" + - update_node_group_policy_attrs.previous.name == "node_group_policy_1" + - update_node_group_policy_attrs.previous.nodeRoutingPolicyRef != "" + - update_node_group_policy_attrs.previous.targetDscp == "af11" + + - name: Clear node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + description: "" + node_routing_policy: "" + bfd_multi_hop_authentication: disabled + target_dscp: "unspecified" + state: present + register: clear_node_group_policy_attrs + ignore_errors: true + + - name: Assertion check for clear node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values + ansible.builtin.assert: + that: + - clear_node_group_policy_attrs is changed + - clear_node_group_policy_attrs.current.name == "node_group_policy_1" + - clear_node_group_policy_attrs.current.nodeRoutingPolicyRef == "" + - clear_node_group_policy_attrs.current.targetDscp == "unspecified" + - clear_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == false + - clear_node_group_policy_attrs.previous.bfdMultiHop.keyID == 2 + - clear_node_group_policy_attrs.previous.description == "Test description updated" + - clear_node_group_policy_attrs.previous.name == "node_group_policy_1" + - clear_node_group_policy_attrs.previous.nodeRoutingPolicyRef != "" + - clear_node_group_policy_attrs.previous.targetDscp == "af12" + + - name: Query node_group_policy_1 + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + state: query + register: query_node_group_policy_1 + ignore_errors: true + + - name: Assertion check for query node_group_policy_1 + ansible.builtin.assert: + that: + - query_node_group_policy_1 is not changed + - query_node_group_policy_1.current.name == "node_group_policy_1" + - query_node_group_policy_1.current.nodeRoutingPolicyRef == "" + - query_node_group_policy_1.current.targetDscp == "unspecified" + + - name: Add node_group_policy_2 with common tenant node_routing_policy object + cisco.mso.ndo_l3out_node_group_policy: &add_node_group_policy_2 + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_2" + description: "Create test description" + target_dscp: cs7 + node_routing_policy: "ans_node_policy_group_common" + state: present + register: add_node_group_policy_2 + ignore_errors: true + + - name: Assertion check for add node_group_policy_2 with common tenant node_routing_policy object + ansible.builtin.assert: + that: + - add_node_group_policy_2 is changed + - add_node_group_policy_2.current.description == "Create test description" + - add_node_group_policy_2.current.name == "node_group_policy_2" + - add_node_group_policy_2.current.nodeRoutingPolicyRef != "" + - add_node_group_policy_2.current.targetDscp == "cs7" + - add_node_group_policy_2.previous == {} + + - name: Query node_group_policy_2 + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_2" + state: query + register: query_node_group_policy_2 + ignore_errors: true + + - name: Assertion check for query node_group_policy_2 + ansible.builtin.assert: + that: + - query_node_group_policy_2 is not changed + - query_node_group_policy_2.current.description == "Create test description" + - query_node_group_policy_2.current.name == "node_group_policy_2" + - query_node_group_policy_2.current.nodeRoutingPolicyRef != "" + - query_node_group_policy_2.current.targetDscp == "cs7" + + - name: Query all node_group_policies + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + state: query + register: query_all_node_group_policies + ignore_errors: true + + - name: Assertion check for query all node_group_policies + ansible.builtin.assert: + that: + - query_all_node_group_policies is not changed + - query_all_node_group_policies.current | length == 2 + + - name: Remove node_group_policy_2 with check mode + cisco.mso.ndo_l3out_node_group_policy: &cm_rm_node_group_policy_2 + <<: *add_node_group_policy_2 + state: absent + check_mode: true + register: cm_rm_node_group_policy_2 + + - name: Assertion check for remove node_group_policy_2 with check mode + ansible.builtin.assert: + that: + - cm_rm_node_group_policy_2 is changed + - cm_rm_node_group_policy_2.current == {} + - cm_rm_node_group_policy_2.previous.description == "Create test description" + - cm_rm_node_group_policy_2.previous.name == "node_group_policy_2" + - cm_rm_node_group_policy_2.previous.nodeRoutingPolicyRef != "" + - cm_rm_node_group_policy_2.previous.targetDscp == "cs7" + + - name: Remove node_group_policy_2 with normal mode + cisco.mso.ndo_l3out_node_group_policy: + <<: *cm_rm_node_group_policy_2 + register: nm_rm_node_group_policy_2 + + - name: Assertion check for remove node_group_policy_2 with normal mode + ansible.builtin.assert: + that: + - nm_rm_node_group_policy_2 is changed + - nm_rm_node_group_policy_2.current == {} + - nm_rm_node_group_policy_2.previous.description == "Create test description" + - nm_rm_node_group_policy_2.previous.name == "node_group_policy_2" + - nm_rm_node_group_policy_2.previous.nodeRoutingPolicyRef != "" + - nm_rm_node_group_policy_2.previous.targetDscp == "cs7" + + - name: Remove node_group_policy_2 with normal mode + cisco.mso.ndo_l3out_node_group_policy: + <<: *cm_rm_node_group_policy_2 + register: nm_rm_node_group_policy_2_again + + - name: Assertion check for remove node_group_policy_2 with normal mode + ansible.builtin.assert: + that: + - nm_rm_node_group_policy_2_again is not changed + - nm_rm_node_group_policy_2_again.current == {} + - nm_rm_node_group_policy_2_again.previous == {} + + # Negative test part begins + - name: Create L3Out node group policy object with invalid l3out name + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_nt" + name: "node_group_policy_nt" + state: present + register: node_group_policy_nt + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object with invalid l3out name + ansible.builtin.assert: + that: + - node_group_policy_nt is not changed + - node_group_policy_nt.current == {} + - node_group_policy_nt.msg == "Provided L3Out with '[KVPair(key='name', value='l3out_nt')]' not matching existing object(s){{':'}} l3out_1, l3out_2" + - node_group_policy_nt.previous == {} + + - name: Create L3Out node group policy object with l3out_1 template + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_1" + name: "node_group_policy_nt" + node_routing_policy: ans_node_policy_group_1 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key_id: 12 + bfd_multi_hop_key: "test" + state: present + register: node_group_policy_nt_with_l3out_1 + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object with l3out_1 template + ansible.builtin.assert: + that: + - node_group_policy_nt_with_l3out_1 is changed + - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.authEnabled == true + - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.key.value == "test" + - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.keyID == 12 + - node_group_policy_nt_with_l3out_1.current.name == "node_group_policy_nt" + - node_group_policy_nt_with_l3out_1.current.nodeRoutingPolicyRef != "" + - node_group_policy_nt_with_l3out_1.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_1'{{':'}} node group 'node_group_policy_nt'{{':'}} BFD Multihop is not supported with non-BGP routing protocols. Current protocol{{':'}} none" + - node_group_policy_nt_with_l3out_1.previous == {} + + - name: Create L3Out node group policy object without key and id when bfd_multi_hop_authentication is enabled + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_1" + name: "node_group_policy_nt" + bfd_multi_hop_authentication: enabled + state: present + register: node_group_policy_nt_without_key + ignore_errors: true + + - name: Assertion check for create L3Out node group policy object without key and id when bfd_multi_hop_authentication is enabled + ansible.builtin.assert: + that: + - node_group_policy_nt_without_key is not changed + - node_group_policy_nt_without_key.msg == "bfd_multi_hop_authentication is enabled but all of the following are missing{{':'}} bfd_multi_hop_key_id, bfd_multi_hop_key" + # Negative test part ends + + # Cleanup Part + - name: Remove l3out tenant template + cisco.mso.ndo_template: + <<: *ndo_l3out_template_absent + + - name: Remove tenant policy template + cisco.mso.ndo_template: + <<: *tenant_pol_template_absent + + - name: Remove ansible_test schema template not exist + cisco.mso.mso_schema_template: + <<: *mso_schema_template_absent + + - name: Ensure ansible_test_policy tenant policy template not exists - cleanup + cisco.mso.ndo_template: + <<: *tenant_pol_template_absent + + - name: Ensure common tenant policy template not exists - cleanup + cisco.mso.ndo_template: + <<: *common_ansible_test_policy From 818ad62c4376f63ff89c95132de4537e704260cd Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 24 Oct 2024 00:05:46 +0530 Subject: [PATCH 02/12] [minor_change] Fixed the bfd_multi_hop_authentication attribute value set logic in the ndo_l3out_node_group_policy module --- .../modules/ndo_l3out_node_group_policy.py | 95 +++-- .../tasks/main.yml | 334 ++++++++++++++---- 2 files changed, 314 insertions(+), 115 deletions(-) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index bf4d878e..9f2627f8 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -14,9 +14,9 @@ DOCUMENTATION = r""" --- module: ndo_l3out_node_group_policy -short_description: Manage L3Out Node/Interface Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). +short_description: Manage L3Out Node Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). description: -- Manage L3Out Node/Interface Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). +- Manage L3Out Node Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). - This module is only supported on ND v3.1 (NDO v4.3) and later. author: - Sabari Jaganathan (@sajagana) @@ -26,19 +26,22 @@ - The name of the template. - The template must be a L3Out template. type: str + aliases: [ l3out_template ] required: true l3out: description: - The name of the L3Out. type: str + aliases: [ l3out_name ] required: true name: description: - - The name of the L3Out Node/Interface Group Policy. + - The name of the L3Out Node Group Policy. type: str + aliases: [ l3out_node_group_policy ] description: description: - - The description of the L3Out Node/Interface Group Policy. + - The description of the L3Out Node Group Policy. type: str node_routing_policy: description: @@ -46,21 +49,21 @@ type: str bfd_multi_hop_authentication: description: - - The bidirectional forwarding detection (BFD) multi-hop authentication of the L3Out Node/Interface Group Policy. + - The bidirectional forwarding detection (BFD) multi-hop authentication of the L3Out Node Group Policy. - To enable the O(bfd_multi_hop_authentication) BGP routing protocol must be configured on the L3Out. type: str choices: [ enabled, disabled ] bfd_multi_hop_key_id: description: - - The BFD multi-hop key ID of the L3Out Node/Interface Group Policy. + - The BFD multi-hop key ID of the L3Out Node Group Policy. type: int bfd_multi_hop_key: description: - - The BFD multi-hop key of the L3Out Node/Interface Group Policy. + - The BFD multi-hop key of the L3Out Node Group Policy. type: str target_dscp: description: - - The DSCP Level of the L3Out Node/Interface Group Policy. + - The DSCP Level of the L3Out Node Group Policy. type: str choices: - af11 @@ -112,7 +115,7 @@ password: SomeSecretPassword template: l3out_template l3out: l3out - name: "node_group_policy_1" + name: node_group_policy_1 state: present - name: Update an existing L3Out node group policy @@ -122,7 +125,7 @@ password: SomeSecretPassword template: l3out_template l3out: l3out - name: "node_group_policy_1" + name: node_group_policy_1 description: "Updated description" node_routing_policy: ans_node_policy_group_1 bfd_multi_hop_authentication: enabled @@ -138,7 +141,7 @@ password: SomeSecretPassword template: l3out_template l3out: l3out - name: "node_group_policy_1" + name: node_group_policy_1 state: query register: query_with_name @@ -149,7 +152,7 @@ password: SomeSecretPassword template: l3out_template l3out: l3out - name: "node_group_policy_1" + name: node_group_policy_1 state: absent """ @@ -168,9 +171,9 @@ def main(): argument_spec = mso_argument_spec() argument_spec.update( - template=dict(type="str", required=True), # L3Out template name - l3out=dict(type="str", required=True), # L3Out name - name=dict(type="str"), # L3Out Node/Interface Group Policy name + template=dict(type="str", required=True, aliases=["l3out_template"]), + l3out=dict(type="str", required=True, aliases=["l3out_name"]), + name=dict(type="str", aliases=["l3out_node_group_policy"]), description=dict(type="str"), node_routing_policy=dict(type="str"), bfd_multi_hop_authentication=dict(type="str", choices=["enabled", "disabled"]), @@ -186,7 +189,6 @@ def main(): required_if=[ ["state", "absent", ["name"]], ["state", "present", ["name"]], - ["bfd_multi_hop_authentication", "enabled", ["bfd_multi_hop_key_id", "bfd_multi_hop_key"]], ], ) @@ -209,9 +211,8 @@ def main(): l3out_object = mso_template.get_l3out_object(name=l3out, fail_module=True) l3out_node_group = mso_template.get_l3out_node_group(name, l3out_object.details) - if name: - if l3out_node_group: - mso.existing = mso.previous = copy.deepcopy(l3out_node_group.details) # Query a specific object + if name and l3out_node_group: + mso.existing = mso.previous = copy.deepcopy(l3out_node_group.details) # Query a specific object elif l3out_node_group: mso.existing = l3out_node_group # Query all objects @@ -239,11 +240,7 @@ def main(): ops.append(dict(op="replace", path=node_group_policy_path + "/description", value=description)) proposed_payload["description"] = description - if ( - node_routing_policy is not None - and l3out_node_routing_policy_object - and mso.existing.get("nodeRoutingPolicyRef") != l3out_node_routing_policy_object.details.get("uuid") - ): + if l3out_node_routing_policy_object and mso.existing.get("nodeRoutingPolicyRef") != l3out_node_routing_policy_object.details.get("uuid"): ops.append( dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=l3out_node_routing_policy_object.details.get("uuid")) ) @@ -252,21 +249,30 @@ def main(): ops.append(dict(op="remove", path=node_group_policy_path + "/nodeRoutingPolicyRef")) proposed_payload.pop("nodeRoutingPolicyRef", None) - if bfd_multi_hop_authentication == "enabled": - if not mso.existing.get("bfdMultiHop"): - proposed_payload["bfdMultiHop"] = dict() - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) + if (bfd_multi_hop_authentication or bfd_multi_hop_key or bfd_multi_hop_key_id) and not mso.existing.get("bfdMultiHop"): + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) + proposed_payload["bfdMultiHop"] = dict() - if mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) - proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id + if bfd_multi_hop_authentication is not None and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not ( + True if bfd_multi_hop_authentication == "enabled" else False + ): + ops.append( + dict( + op="replace", + path=node_group_policy_path + "/bfdMultiHop/authEnabled", + value=True if bfd_multi_hop_authentication == "enabled" else False, + ) + ) + proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/value", value=bfd_multi_hop_key)) - proposed_payload["bfdMultiHop"]["value"] = bfd_multi_hop_key + if bfd_multi_hop_key_id is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) + proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id - elif bfd_multi_hop_authentication == "disabled" and mso.existing.get("bfdMultiHop"): - proposed_payload.pop("bfdMultiHop", None) - ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) + if bfd_multi_hop_key is not None: + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd_multi_hop_key)) + proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd_multi_hop_key) if target_dscp is not None and mso.existing.get("targetDscp") != target_dscp: ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) @@ -280,11 +286,22 @@ def main(): if description: payload["description"] = description - if node_routing_policy and l3out_node_routing_policy_object: + if l3out_node_routing_policy_object: payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") - if bfd_multi_hop_authentication == "enabled": - payload["bfdMultiHop"] = dict(authEnabled=True, keyID=bfd_multi_hop_key_id, key=dict(value=bfd_multi_hop_key)) + bfd_multi_hop = dict() + + if bfd_multi_hop_authentication is not None: + bfd_multi_hop["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False + + if bfd_multi_hop_key_id: + bfd_multi_hop["keyID"] = bfd_multi_hop_key_id + + if bfd_multi_hop_key: + bfd_multi_hop["key"] = dict(value=bfd_multi_hop_key) + + if bfd_multi_hop: + payload["bfdMultiHop"] = bfd_multi_hop if target_dscp: payload["targetDscp"] = target_dscp diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index 6b7ac110..eae463ab 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -31,6 +31,37 @@ when: version.current.version is version('4.2', '>') block: # Setup Part + - name: Ensure ansible_test site exist + cisco.mso.mso_site: + <<: *mso_info + site: '{{ mso_site | default("ansible_test") }}' + state: query + register: ansible_test_site + + - name: Ensure ansible_test tenant exist + cisco.mso.mso_tenant: + <<: *mso_info + tenant: '{{ ansible_tenant | default("ansible_test") }}' + users: + - "{{ mso_username }}" + sites: + - '{{ mso_site | default("ansible_test") }}' + state: present + register: ansible_test_tenant + when: ansible_test_site.current.common.name == 'ansible_test' + + - name: Ensure common tenant exist + cisco.mso.mso_tenant: + <<: *mso_info + tenant: common + users: + - "{{ mso_username }}" + sites: + - '{{ mso_site | default("ansible_test") }}' + state: present + register: ansible_test_tenant + when: ansible_test_site.current.common.name == 'ansible_test' + - name: Ensure l3out template not exist cisco.mso.ndo_template: &ndo_l3out_template_absent <<: *mso_info @@ -64,37 +95,6 @@ template: "Template1" state: absent - - name: Ensure ansible_test site exist - cisco.mso.mso_site: - <<: *mso_info - site: '{{ mso_site | default("ansible_test") }}' - state: query - register: ansible_test_site - - - name: Ensure ansible_test tenant exist - cisco.mso.mso_tenant: - <<: *mso_info - tenant: '{{ ansible_tenant | default("ansible_test") }}' - users: - - "{{ mso_username }}" - sites: - - '{{ mso_site | default("ansible_test") }}' - state: present - register: ansible_test_tenant - when: ansible_test_site.current.common.name == 'ansible_test' - - - name: Ensure common tenant exist - cisco.mso.mso_tenant: - <<: *mso_info - tenant: common - users: - - "{{ mso_username }}" - sites: - - '{{ mso_site | default("ansible_test") }}' - state: present - register: ansible_test_tenant - when: ansible_test_site.current.common.name == 'ansible_test' - # Schema Template Setup for the VRF - name: Add an ansible_test schema template cisco.mso.mso_schema_template: @@ -214,7 +214,6 @@ state: present check_mode: true register: cm_node_group_policy_1_present - ignore_errors: true - name: Assertion check for create L3Out node group policy object with default values - check mode ansible.builtin.assert: @@ -227,7 +226,6 @@ cisco.mso.ndo_l3out_node_group_policy: &nm_node_group_policy_1_present <<: *cm_node_group_policy_1_present register: nm_node_group_policy_1_present - ignore_errors: true - name: Assertion check for create L3Out node group policy object with default values - normal mode ansible.builtin.assert: @@ -242,7 +240,6 @@ cisco.mso.ndo_l3out_node_group_policy: <<: *nm_node_group_policy_1_present register: nm_node_group_policy_1_present_again - ignore_errors: true - name: Assertion check for create L3Out node group policy object with default values - normal mode again ansible.builtin.assert: @@ -267,14 +264,13 @@ state: present check_mode: true register: cm_update_node_group_policy_1 - ignore_errors: true - name: Assertion check for update L3Out node group policy object with check mode ansible.builtin.assert: that: - cm_update_node_group_policy_1 is changed - cm_update_node_group_policy_1.current.bfdMultiHop.keyID == 1 - - cm_update_node_group_policy_1.current.bfdMultiHop.value == "TestKey" + - cm_update_node_group_policy_1.current.bfdMultiHop.key.value == "TestKey" - cm_update_node_group_policy_1.current.description == "Test description" - cm_update_node_group_policy_1.current.name == "node_group_policy_1" - cm_update_node_group_policy_1.current.nodeRoutingPolicyRef != "" @@ -287,13 +283,12 @@ cisco.mso.ndo_l3out_node_group_policy: &nm_update_node_group_policy_1 <<: *cm_update_node_group_policy_1 register: nm_update_node_group_policy_1 - ignore_errors: true - name: Assertion check for update L3Out node group policy object with normal mode ansible.builtin.assert: that: - nm_update_node_group_policy_1 is changed - - nm_update_node_group_policy_1.current.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1.current.bfdMultiHop.authEnabled == true - nm_update_node_group_policy_1.current.bfdMultiHop.keyID == 1 - nm_update_node_group_policy_1.current.description == "Test description" - nm_update_node_group_policy_1.current.name == "node_group_policy_1" @@ -303,23 +298,23 @@ - nm_update_node_group_policy_1.previous.nodeRoutingPolicyRef == "" - nm_update_node_group_policy_1.previous.targetDscp == "unspecified" - - name: Update L3Out node group policy object with normal mode again + - name: Update L3Out node group policy object with normal mode again - task status should be changed because of the auth key ref change cisco.mso.ndo_l3out_node_group_policy: <<: *nm_update_node_group_policy_1 register: nm_update_node_group_policy_1_again - ignore_errors: true - name: Assertion check for update L3Out node group policy object with normal mode again ansible.builtin.assert: that: - - nm_update_node_group_policy_1_again is not changed - - nm_update_node_group_policy_1_again.current.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1_again is changed + - nm_update_node_group_policy_1_again.current.bfdMultiHop.authEnabled == true - nm_update_node_group_policy_1_again.current.bfdMultiHop.keyID == 1 + - nm_update_node_group_policy_1_again.current.bfdMultiHop.key.ref != nm_update_node_group_policy_1_again.previous.bfdMultiHop.key.ref - nm_update_node_group_policy_1_again.current.description == "Test description" - nm_update_node_group_policy_1_again.current.name == "node_group_policy_1" - nm_update_node_group_policy_1_again.current.nodeRoutingPolicyRef != "" - nm_update_node_group_policy_1_again.current.targetDscp == "af11" - - nm_update_node_group_policy_1_again.previous.bfdMultiHop.authEnabled == false + - nm_update_node_group_policy_1_again.previous.bfdMultiHop.authEnabled == true - nm_update_node_group_policy_1_again.previous.bfdMultiHop.keyID == 1 - nm_update_node_group_policy_1_again.previous.description == "Test description" - nm_update_node_group_policy_1_again.previous.name == "node_group_policy_1" @@ -340,19 +335,18 @@ target_dscp: af12 state: present register: update_node_group_policy_attrs - ignore_errors: true - name: Assertion check for update node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values ansible.builtin.assert: that: - update_node_group_policy_attrs is changed - - update_node_group_policy_attrs.current.bfdMultiHop.authEnabled == false + - update_node_group_policy_attrs.current.bfdMultiHop.authEnabled == true - update_node_group_policy_attrs.current.bfdMultiHop.keyID == 2 - update_node_group_policy_attrs.current.description == "Test description updated" - update_node_group_policy_attrs.current.name == "node_group_policy_1" - update_node_group_policy_attrs.current.nodeRoutingPolicyRef != "" - update_node_group_policy_attrs.current.targetDscp == "af12" - - update_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == false + - update_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == true - update_node_group_policy_attrs.previous.bfdMultiHop.keyID == 1 - update_node_group_policy_attrs.previous.description == "Test description" - update_node_group_policy_attrs.previous.name == "node_group_policy_1" @@ -370,8 +364,8 @@ bfd_multi_hop_authentication: disabled target_dscp: "unspecified" state: present + output_level: debug register: clear_node_group_policy_attrs - ignore_errors: true - name: Assertion check for clear node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values ansible.builtin.assert: @@ -379,8 +373,9 @@ - clear_node_group_policy_attrs is changed - clear_node_group_policy_attrs.current.name == "node_group_policy_1" - clear_node_group_policy_attrs.current.nodeRoutingPolicyRef == "" + - clear_node_group_policy_attrs.current.bfdMultiHop.authEnabled == false - clear_node_group_policy_attrs.current.targetDscp == "unspecified" - - clear_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == false + - clear_node_group_policy_attrs.previous.bfdMultiHop.authEnabled == true - clear_node_group_policy_attrs.previous.bfdMultiHop.keyID == 2 - clear_node_group_policy_attrs.previous.description == "Test description updated" - clear_node_group_policy_attrs.previous.name == "node_group_policy_1" @@ -395,7 +390,6 @@ name: "node_group_policy_1" state: query register: query_node_group_policy_1 - ignore_errors: true - name: Assertion check for query node_group_policy_1 ansible.builtin.assert: @@ -404,6 +398,7 @@ - query_node_group_policy_1.current.name == "node_group_policy_1" - query_node_group_policy_1.current.nodeRoutingPolicyRef == "" - query_node_group_policy_1.current.targetDscp == "unspecified" + - query_node_group_policy_1.current.bfdMultiHop.authEnabled == false - name: Add node_group_policy_2 with common tenant node_routing_policy object cisco.mso.ndo_l3out_node_group_policy: &add_node_group_policy_2 @@ -416,7 +411,6 @@ node_routing_policy: "ans_node_policy_group_common" state: present register: add_node_group_policy_2 - ignore_errors: true - name: Assertion check for add node_group_policy_2 with common tenant node_routing_policy object ansible.builtin.assert: @@ -436,7 +430,6 @@ name: "node_group_policy_2" state: query register: query_node_group_policy_2 - ignore_errors: true - name: Assertion check for query node_group_policy_2 ansible.builtin.assert: @@ -454,7 +447,6 @@ l3out: "l3out_2" state: query register: query_all_node_group_policies - ignore_errors: true - name: Assertion check for query all node_group_policies ansible.builtin.assert: @@ -462,6 +454,220 @@ - query_all_node_group_policies is not changed - query_all_node_group_policies.current | length == 2 + - name: Create node_group_policy_30 with bfd_multi_hop_authentication enabled, key id and value + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_30" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key_id: 2 + bfd_multi_hop_key: TestKeyUpdated + target_dscp: af12 + state: present + register: add_ngp_3_auth_disabled + + - name: Assertion check for create node_group_policy_30 with bfd_multi_hop_authentication enabled, key id and value + ansible.builtin.assert: + that: + - add_ngp_3_auth_disabled is changed + - add_ngp_3_auth_disabled.current.bfdMultiHop.authEnabled == true + - add_ngp_3_auth_disabled.current.bfdMultiHop.key.ref is defined + - add_ngp_3_auth_disabled.current.bfdMultiHop.keyID == 2 + - add_ngp_3_auth_disabled.current.name == "node_group_policy_30" + - add_ngp_3_auth_disabled.current.nodeRoutingPolicyRef != "" + - add_ngp_3_auth_disabled.current.targetDscp == "af12" + - add_ngp_3_auth_disabled.previous == {} + + - name: Create node_group_policy_3 with bfd_multi_hop_authentication disabled, key id and value + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: disabled + bfd_multi_hop_key_id: 2 + bfd_multi_hop_key: TestKeyUpdated + target_dscp: af12 + state: present + register: add_ngp_3_auth_disabled + + - name: Assertion check for create node_group_policy_3 with bfd_multi_hop_authentication disabled, key id and value + ansible.builtin.assert: + that: + - add_ngp_3_auth_disabled is changed + - add_ngp_3_auth_disabled.current.bfdMultiHop.authEnabled == false + - add_ngp_3_auth_disabled.current.bfdMultiHop.keyID == 2 + - add_ngp_3_auth_disabled.current.bfdMultiHop.key.ref is not defined + - add_ngp_3_auth_disabled.current.name == "node_group_policy_3" + - add_ngp_3_auth_disabled.current.nodeRoutingPolicyRef != "" + - add_ngp_3_auth_disabled.current.targetDscp == "af12" + - add_ngp_3_auth_disabled.previous == {} + + - name: Update node_group_policy_3 with only bfd_multi_hop_key_id + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + bfd_multi_hop_key_id: 3 + state: present + register: update_ngp_3_with_key_id + + - name: Assertion check for update node_group_policy_3 with only bfd_multi_hop_key_id + ansible.builtin.assert: + that: + - update_ngp_3_with_key_id is changed + - update_ngp_3_with_key_id.current.bfdMultiHop.authEnabled == false + - update_ngp_3_with_key_id.current.bfdMultiHop.keyID == 3 + - update_ngp_3_with_key_id.current.name == "node_group_policy_3" + - update_ngp_3_with_key_id.current.nodeRoutingPolicyRef != "" + - update_ngp_3_with_key_id.current.targetDscp == "af12" + - update_ngp_3_with_key_id.previous.bfdMultiHop.authEnabled == false + - update_ngp_3_with_key_id.previous.bfdMultiHop.keyID == 2 + - update_ngp_3_with_key_id.previous.name == "node_group_policy_3" + - update_ngp_3_with_key_id.previous.nodeRoutingPolicyRef != "" + - update_ngp_3_with_key_id.previous.targetDscp == "af12" + + - name: Update node_group_policy_3 with only bfd_multi_hop_key - task flag changed should be false wth authentication is disabled + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + bfd_multi_hop_key: TestKeyUpdated1 + state: present + register: update_ngp_3_with_key + + - name: Assertion check for update node_group_policy_3 with only bfd_multi_hop_key - task flag changed should be false wth authentication is disabled + ansible.builtin.assert: + that: + - update_ngp_3_with_key is not changed + - update_ngp_3_with_key.current.bfdMultiHop.authEnabled == false + - update_ngp_3_with_key.current.bfdMultiHop.keyID == 3 + - update_ngp_3_with_key.current.name == "node_group_policy_3" + - update_ngp_3_with_key.current.nodeRoutingPolicyRef != "" + - update_ngp_3_with_key.current.targetDscp == "af12" + - update_ngp_3_with_key.previous.bfdMultiHop.authEnabled == false + - update_ngp_3_with_key.previous.bfdMultiHop.keyID == 3 + - update_ngp_3_with_key.previous.name == "node_group_policy_3" + - update_ngp_3_with_key.previous.nodeRoutingPolicyRef != "" + - update_ngp_3_with_key.previous.targetDscp == "af12" + + - name: Create node_group_policy_4 with bfd_multi_hop_authentication disabled without bfd_multi_hop_key_id and bfd_multi_hop_key + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: disabled + target_dscp: af12 + state: present + register: add_ngp_4_auth_disabled + + - name: Assertion check for create node_group_policy_4 with bfd_multi_hop_authentication disabled without bfd_multi_hop_key_id and bfd_multi_hop_key + ansible.builtin.assert: + that: + - add_ngp_4_auth_disabled is changed + - add_ngp_4_auth_disabled.current.bfdMultiHop.authEnabled == false + - add_ngp_4_auth_disabled.current.name == "node_group_policy_4" + - add_ngp_4_auth_disabled.current.nodeRoutingPolicyRef != "" + - add_ngp_4_auth_disabled.current.targetDscp == "af12" + - add_ngp_4_auth_disabled.previous == {} + + - name: Create node_group_policy_5 without bfd config + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + state: present + register: add_ngp_5 + + - name: Assertion check for create node_group_policy_5 without bfd config + ansible.builtin.assert: + that: + - add_ngp_5 is changed + - add_ngp_5.current.name == "node_group_policy_5" + - add_ngp_5.current.nodeRoutingPolicyRef != "" + - add_ngp_5.current.targetDscp == "unspecified" + - add_ngp_5.previous == {} + + - name: Update node_group_policy_5 with only bfd_multi_hop_key_id and bfd_multi_hop_key + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_key_id: 3 + bfd_multi_hop_key: TestKeyUpdated1 + state: present + register: update_ngp_5_only_id_value + + - name: Assertion check for update node_group_policy_5 with only bfd_multi_hop_key_id and bfd_multi_hop_key + ansible.builtin.assert: + that: + - update_ngp_5_only_id_value is changed + - update_ngp_5_only_id_value.current.bfdMultiHop.authEnabled == false + - update_ngp_5_only_id_value.current.bfdMultiHop.keyID == 3 + - update_ngp_5_only_id_value.current.name == "node_group_policy_5" + - update_ngp_5_only_id_value.current.nodeRoutingPolicyRef != "" + - update_ngp_5_only_id_value.current.targetDscp == "unspecified" + - update_ngp_5_only_id_value.previous.name == "node_group_policy_5" + - update_ngp_5_only_id_value.previous.nodeRoutingPolicyRef != "" + - update_ngp_5_only_id_value.previous.targetDscp == "unspecified" + + - name: Enable bfd_multi_hop_authentication without bfd_multi_hop_key on node_group_policy_5 + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: enabled + state: present + register: enable_ngp_5_auth_without_key + ignore_errors: true + + - name: Assertion check for enable bfd_multi_hop_authentication without bfd_multi_hop_key on node_group_policy_5 + ansible.builtin.assert: + that: + - enable_ngp_5_auth_without_key is changed + - enable_ngp_5_auth_without_key.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_2'{{':'}} node group 'node_group_policy_5'{{':'}} bfdMultiHop Key must be specified when auth is enabled" + + - name: Update node_group_policy_5 with bfd config + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd_multi_hop_authentication: enabled + bfd_multi_hop_key: TestKeyUpdated4 + state: present + register: update_ngp_5_bfd_config + + - name: Assertion check for update node_group_policy_5 with bfd config + ansible.builtin.assert: + that: + - update_ngp_5_bfd_config is changed + - update_ngp_5_bfd_config.current.bfdMultiHop.authEnabled == true + - update_ngp_5_bfd_config.current.bfdMultiHop.key.ref is defined + - update_ngp_5_bfd_config.current.bfdMultiHop.keyID == 3 + - update_ngp_5_bfd_config.current.name == "node_group_policy_5" + - update_ngp_5_bfd_config.current.nodeRoutingPolicyRef != "" + - update_ngp_5_bfd_config.current.targetDscp == "unspecified" + - update_ngp_5_bfd_config.previous.bfdMultiHop.authEnabled == false + - update_ngp_5_bfd_config.previous.bfdMultiHop.keyID == 3 + - update_ngp_5_bfd_config.previous.name == "node_group_policy_5" + - update_ngp_5_bfd_config.previous.nodeRoutingPolicyRef != "" + - update_ngp_5_bfd_config.previous.targetDscp == "unspecified" + - name: Remove node_group_policy_2 with check mode cisco.mso.ndo_l3out_node_group_policy: &cm_rm_node_group_policy_2 <<: *add_node_group_policy_2 @@ -543,31 +749,7 @@ ansible.builtin.assert: that: - node_group_policy_nt_with_l3out_1 is changed - - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.authEnabled == true - - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.key.value == "test" - - node_group_policy_nt_with_l3out_1.current.bfdMultiHop.keyID == 12 - - node_group_policy_nt_with_l3out_1.current.name == "node_group_policy_nt" - - node_group_policy_nt_with_l3out_1.current.nodeRoutingPolicyRef != "" - node_group_policy_nt_with_l3out_1.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_1'{{':'}} node group 'node_group_policy_nt'{{':'}} BFD Multihop is not supported with non-BGP routing protocols. Current protocol{{':'}} none" - - node_group_policy_nt_with_l3out_1.previous == {} - - - name: Create L3Out node group policy object without key and id when bfd_multi_hop_authentication is enabled - cisco.mso.ndo_l3out_node_group_policy: - <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' - l3out: "l3out_1" - name: "node_group_policy_nt" - bfd_multi_hop_authentication: enabled - state: present - register: node_group_policy_nt_without_key - ignore_errors: true - - - name: Assertion check for create L3Out node group policy object without key and id when bfd_multi_hop_authentication is enabled - ansible.builtin.assert: - that: - - node_group_policy_nt_without_key is not changed - - node_group_policy_nt_without_key.msg == "bfd_multi_hop_authentication is enabled but all of the following are missing{{':'}} bfd_multi_hop_key_id, bfd_multi_hop_key" - # Negative test part ends # Cleanup Part - name: Remove l3out tenant template From bd850a299b1336afc77665d47eeabb32c05141d4 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 24 Oct 2024 10:30:42 +0530 Subject: [PATCH 03/12] [minor_change] Fixed ndo_l3out_node_group_policy module doc --- plugins/modules/ndo_l3out_node_group_policy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 9f2627f8..419e70c0 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -24,7 +24,7 @@ template: description: - The name of the template. - - The template must be a L3Out template. + - The template must be an L3Out template. type: str aliases: [ l3out_template ] required: true @@ -49,7 +49,7 @@ type: str bfd_multi_hop_authentication: description: - - The bidirectional forwarding detection (BFD) multi-hop authentication of the L3Out Node Group Policy. + - The Bidirectional Forwarding Detection (BFD) multi-hop authentication of the L3Out Node Group Policy. - To enable the O(bfd_multi_hop_authentication) BGP routing protocol must be configured on the L3Out. type: str choices: [ enabled, disabled ] From 3b3a5bdca794c3fbd923b151ad8aa69560781b29 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 24 Oct 2024 18:38:04 +0530 Subject: [PATCH 04/12] [ignore] Fixed the update logic to clear bfd config on ndo_l3out_node_group_policy module --- plugins/module_utils/template.py | 8 +- .../modules/ndo_l3out_node_group_policy.py | 75 ++++++++++------ .../tasks/main.yml | 90 +++++++++++++++++-- 3 files changed, 133 insertions(+), 40 deletions(-) diff --git a/plugins/module_utils/template.py b/plugins/module_utils/template.py index 62bd0593..249c215c 100644 --- a/plugins/module_utils/template.py +++ b/plugins/module_utils/template.py @@ -238,9 +238,9 @@ def get_l3out_object(self, uuid=None, name=None, fail_module=False): def get_l3out_node_group(self, name, l3out_object, fail_module=False): """ - Get the L3Out Node/Interface Group Policy by name. - :param name: Name of the L3Out Node/Interface Group Policy to search for -> Str - :param l3out_object: L3Out object to search Node/Interface Group Policy -> Dict + Get the L3Out Node Group Policy by name. + :param name: Name of the L3Out Node Group Policy to search for -> Str + :param l3out_object: L3Out object to search Node Group Policy -> Dict :param fail_module: When match is not found fail the ansible module -> Bool :return: Dict | None | List[Dict] | List[]: The processed result which could be: When the UUID | Name is existing in the search list -> Dict @@ -250,5 +250,5 @@ def get_l3out_node_group(self, name, l3out_object, fail_module=False): """ existing_l3out_node_groups = l3out_object.get("nodeGroups", []) if name: # Query a specific object - return self.get_object_by_key_value_pairs("L3Out Node/Interface Group Policy", existing_l3out_node_groups, [KVPair("name", name)], fail_module) + return self.get_object_by_key_value_pairs("L3Out Node Group Policy", existing_l3out_node_groups, [KVPair("name", name)], fail_module) return existing_l3out_node_groups # Query all objects diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 419e70c0..7afec1ee 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -46,16 +46,19 @@ node_routing_policy: description: - The name of the L3Out Node Routing Policy. + - Providing an empty string will remove the O(node_routing_policy="") from L3Out Node Group Policy. type: str bfd_multi_hop_authentication: description: - The Bidirectional Forwarding Detection (BFD) multi-hop authentication of the L3Out Node Group Policy. - To enable the O(bfd_multi_hop_authentication) BGP routing protocol must be configured on the L3Out. + - To clear the BFD auth configuration, provide the values O(bfd_multi_hop_authentication=""), O(bfd_multi_hop_key=""), and O(bfd_multi_hop_key_id=0). type: str - choices: [ enabled, disabled ] + choices: [ enabled, disabled, "" ] bfd_multi_hop_key_id: description: - The BFD multi-hop key ID of the L3Out Node Group Policy. + - Providing 0 will remove the O(bfd_multi_hop_key_id=0) from L3Out Node Group Policy. type: int bfd_multi_hop_key: description: @@ -176,9 +179,9 @@ def main(): name=dict(type="str", aliases=["l3out_node_group_policy"]), description=dict(type="str"), node_routing_policy=dict(type="str"), - bfd_multi_hop_authentication=dict(type="str", choices=["enabled", "disabled"]), + bfd_multi_hop_authentication=dict(type="str", choices=["enabled", "disabled", ""]), bfd_multi_hop_key_id=dict(type="int"), - bfd_multi_hop_key=dict(type="str", no_log=False), + bfd_multi_hop_key=dict(type="str", no_log=True), target_dscp=dict(type="str", choices=list(TARGET_DSCP_MAP)), state=dict(type="str", default="query", choices=["absent", "query", "present"]), ) @@ -235,6 +238,9 @@ def main(): if mso.existing: proposed_payload = copy.deepcopy(mso.existing) + if proposed_payload.get("bfdMultiHop", {}).get("key", {}).get("ref"): + proposed_payload["bfdMultiHop"]["key"].pop("ref", None) + mso.existing["bfdMultiHop"]["key"].pop("ref", None) if description is not None and mso.existing.get("description") != description: ops.append(dict(op="replace", path=node_group_policy_path + "/description", value=description)) @@ -245,41 +251,50 @@ def main(): dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=l3out_node_routing_policy_object.details.get("uuid")) ) proposed_payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") - elif node_routing_policy == "" and mso.existing.get("nodeRoutingPolicyRef"): - ops.append(dict(op="remove", path=node_group_policy_path + "/nodeRoutingPolicyRef")) - proposed_payload.pop("nodeRoutingPolicyRef", None) - if (bfd_multi_hop_authentication or bfd_multi_hop_key or bfd_multi_hop_key_id) and not mso.existing.get("bfdMultiHop"): - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) - proposed_payload["bfdMultiHop"] = dict() - - if bfd_multi_hop_authentication is not None and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not ( - True if bfd_multi_hop_authentication == "enabled" else False - ): - ops.append( - dict( - op="replace", - path=node_group_policy_path + "/bfdMultiHop/authEnabled", - value=True if bfd_multi_hop_authentication == "enabled" else False, + elif node_routing_policy == "" and mso.existing.get( + "nodeRoutingPolicyRef" + ): # Clear the node routing policy when node_routing_policy is empty string + ops.append(dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=node_routing_policy)) + proposed_payload["nodeRoutingPolicyRef"] = node_routing_policy + + if bfd_multi_hop_authentication or bfd_multi_hop_key or bfd_multi_hop_key_id: + if not mso.existing.get("bfdMultiHop"): + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) + proposed_payload["bfdMultiHop"] = dict() + + # Ignore when bfd_multi_hop_authentication is None or empty string + if bfd_multi_hop_authentication and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not ( + True if bfd_multi_hop_authentication == "enabled" else False + ): + ops.append( + dict( + op="replace", + path=node_group_policy_path + "/bfdMultiHop/authEnabled", + value=True if bfd_multi_hop_authentication == "enabled" else False, + ) ) - ) - proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False + proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False - if bfd_multi_hop_key_id is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) - proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id + if bfd_multi_hop_key_id is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) + proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id - if bfd_multi_hop_key is not None: - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd_multi_hop_key)) - proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd_multi_hop_key) + if bfd_multi_hop_key is not None: + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd_multi_hop_key)) + proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd_multi_hop_key) + + # Clear the complete BFD multi-hop configuration when all parameters are empty + elif bfd_multi_hop_authentication == "" and bfd_multi_hop_key == "" and bfd_multi_hop_key_id == 0 and mso.existing.get("bfdMultiHop"): + ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) + proposed_payload.pop("bfdMultiHop") if target_dscp is not None and mso.existing.get("targetDscp") != target_dscp: ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) proposed_payload["targetDscp"] = target_dscp mso.sanitize(proposed_payload, collate=True) - else: payload = dict(name=name) @@ -291,7 +306,7 @@ def main(): bfd_multi_hop = dict() - if bfd_multi_hop_authentication is not None: + if bfd_multi_hop_authentication: bfd_multi_hop["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False if bfd_multi_hop_key_id: @@ -321,6 +336,8 @@ def main(): l3out_node_group = mso_template.get_l3out_node_group(name, l3out_object.details) if l3out_node_group: mso.existing = l3out_node_group.details # When the state is present + if mso.existing.get("bfdMultiHop", {}).get("key", {}).get("ref"): + mso.existing["bfdMultiHop"]["key"].pop("ref") else: mso.existing = {} # When the state is absent elif module.check_mode and state != "query": # When the state is present/absent with check mode diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index eae463ab..fdecf7cd 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -270,7 +270,7 @@ that: - cm_update_node_group_policy_1 is changed - cm_update_node_group_policy_1.current.bfdMultiHop.keyID == 1 - - cm_update_node_group_policy_1.current.bfdMultiHop.key.value == "TestKey" + - cm_update_node_group_policy_1.current.bfdMultiHop.key.value is defined - cm_update_node_group_policy_1.current.description == "Test description" - cm_update_node_group_policy_1.current.name == "node_group_policy_1" - cm_update_node_group_policy_1.current.nodeRoutingPolicyRef != "" @@ -298,7 +298,7 @@ - nm_update_node_group_policy_1.previous.nodeRoutingPolicyRef == "" - nm_update_node_group_policy_1.previous.targetDscp == "unspecified" - - name: Update L3Out node group policy object with normal mode again - task status should be changed because of the auth key ref change + - name: Update L3Out node group policy object with normal mode again cisco.mso.ndo_l3out_node_group_policy: <<: *nm_update_node_group_policy_1 register: nm_update_node_group_policy_1_again @@ -306,10 +306,9 @@ - name: Assertion check for update L3Out node group policy object with normal mode again ansible.builtin.assert: that: - - nm_update_node_group_policy_1_again is changed + - nm_update_node_group_policy_1_again is not changed - nm_update_node_group_policy_1_again.current.bfdMultiHop.authEnabled == true - nm_update_node_group_policy_1_again.current.bfdMultiHop.keyID == 1 - - nm_update_node_group_policy_1_again.current.bfdMultiHop.key.ref != nm_update_node_group_policy_1_again.previous.bfdMultiHop.key.ref - nm_update_node_group_policy_1_again.current.description == "Test description" - nm_update_node_group_policy_1_again.current.name == "node_group_policy_1" - nm_update_node_group_policy_1_again.current.nodeRoutingPolicyRef != "" @@ -473,7 +472,6 @@ that: - add_ngp_3_auth_disabled is changed - add_ngp_3_auth_disabled.current.bfdMultiHop.authEnabled == true - - add_ngp_3_auth_disabled.current.bfdMultiHop.key.ref is defined - add_ngp_3_auth_disabled.current.bfdMultiHop.keyID == 2 - add_ngp_3_auth_disabled.current.name == "node_group_policy_30" - add_ngp_3_auth_disabled.current.nodeRoutingPolicyRef != "" @@ -500,7 +498,6 @@ - add_ngp_3_auth_disabled is changed - add_ngp_3_auth_disabled.current.bfdMultiHop.authEnabled == false - add_ngp_3_auth_disabled.current.bfdMultiHop.keyID == 2 - - add_ngp_3_auth_disabled.current.bfdMultiHop.key.ref is not defined - add_ngp_3_auth_disabled.current.name == "node_group_policy_3" - add_ngp_3_auth_disabled.current.nodeRoutingPolicyRef != "" - add_ngp_3_auth_disabled.current.targetDscp == "af12" @@ -578,6 +575,61 @@ - add_ngp_4_auth_disabled.current.targetDscp == "af12" - add_ngp_4_auth_disabled.previous == {} + - name: Add bfd_multi_hop_key_id to node_group_policy_4 when bfd_multi_hop_authentication is disabled + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + bfd_multi_hop_key_id: 10 + state: present + register: add_key_id_ngp_4_auth_disabled + + - name: Assertion check for add bfd_multi_hop_key_id to node_group_policy_4 when bfd_multi_hop_authentication is disabled + ansible.builtin.assert: + that: + - add_key_id_ngp_4_auth_disabled is changed + - add_key_id_ngp_4_auth_disabled.current.bfdMultiHop.authEnabled == false + - add_key_id_ngp_4_auth_disabled.current.bfdMultiHop.keyID == 10 + - add_key_id_ngp_4_auth_disabled.current.name == "node_group_policy_4" + - add_key_id_ngp_4_auth_disabled.current.nodeRoutingPolicyRef != "" + - add_key_id_ngp_4_auth_disabled.current.targetDscp == "af12" + - add_key_id_ngp_4_auth_disabled.previous.bfdMultiHop.authEnabled == false + - add_key_id_ngp_4_auth_disabled.previous.name == "node_group_policy_4" + - add_key_id_ngp_4_auth_disabled.previous.nodeRoutingPolicyRef != "" + - add_key_id_ngp_4_auth_disabled.previous.bfdMultiHop.keyID is not defined + - add_key_id_ngp_4_auth_disabled.previous.targetDscp == "af12" + + - name: Remove bfd_multi_hop_key_id from node_group_policy_4 when bfd_multi_hop_authentication is disabled + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + bfd_multi_hop_authentication: disabled + bfd_multi_hop_key_id: 0 + state: present + output_level: debug + register: clear_key_id_ngp_4_auth_disabled + + - name: Assertion check for remove bfd_multi_hop_key_id from node_group_policy_4 when bfd_multi_hop_authentication is disabled + ansible.builtin.assert: + that: + - clear_key_id_ngp_4_auth_disabled is changed + - clear_key_id_ngp_4_auth_disabled.current.bfdMultiHop.keyID is not defined + - clear_key_id_ngp_4_auth_disabled.current.bfdMultiHop.authEnabled == false + - clear_key_id_ngp_4_auth_disabled.current.name == "node_group_policy_4" + - clear_key_id_ngp_4_auth_disabled.current.nodeRoutingPolicyRef != "" + - clear_key_id_ngp_4_auth_disabled.current.targetDscp == "af12" + - clear_key_id_ngp_4_auth_disabled.previous.bfdMultiHop.authEnabled == false + - clear_key_id_ngp_4_auth_disabled.previous.bfdMultiHop.keyID == 10 + - clear_key_id_ngp_4_auth_disabled.previous.name == "node_group_policy_4" + - clear_key_id_ngp_4_auth_disabled.previous.nodeRoutingPolicyRef != "" + - clear_key_id_ngp_4_auth_disabled.previous.targetDscp == "af12" + - clear_key_id_ngp_4_auth_disabled.proposed.bfdMultiHop.authEnabled == false + - clear_key_id_ngp_4_auth_disabled.proposed.bfdMultiHop.keyID == 0 + - clear_key_id_ngp_4_auth_disabled.proposed.name == "node_group_policy_4" + - name: Create node_group_policy_5 without bfd config cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info @@ -657,7 +709,6 @@ that: - update_ngp_5_bfd_config is changed - update_ngp_5_bfd_config.current.bfdMultiHop.authEnabled == true - - update_ngp_5_bfd_config.current.bfdMultiHop.key.ref is defined - update_ngp_5_bfd_config.current.bfdMultiHop.keyID == 3 - update_ngp_5_bfd_config.current.name == "node_group_policy_5" - update_ngp_5_bfd_config.current.nodeRoutingPolicyRef != "" @@ -668,6 +719,31 @@ - update_ngp_5_bfd_config.previous.nodeRoutingPolicyRef != "" - update_ngp_5_bfd_config.previous.targetDscp == "unspecified" + - name: Clear complete bfd and node_routing_policy config from node_group_policy_5 + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: "" + bfd_multi_hop_authentication: "" + bfd_multi_hop_key_id: 0 + bfd_multi_hop_key: "" + state: present + register: clear_ngp_5_bfd_config + + - name: Assertion check for clear complete bfd and node_routing_policy config from node_group_policy_5 + ansible.builtin.assert: + that: + - clear_ngp_5_bfd_config is changed + - clear_ngp_5_bfd_config.current.name == "node_group_policy_5" + - clear_ngp_5_bfd_config.current.nodeRoutingPolicyRef == "" + - clear_ngp_5_bfd_config.current.targetDscp == "unspecified" + - clear_ngp_5_bfd_config.previous.name == "node_group_policy_5" + - clear_ngp_5_bfd_config.previous.nodeRoutingPolicyRef != "" + - clear_ngp_5_bfd_config.previous.targetDscp == "unspecified" + - clear_ngp_5_bfd_config.previous.bfdMultiHop is defined + - name: Remove node_group_policy_2 with check mode cisco.mso.ndo_l3out_node_group_policy: &cm_rm_node_group_policy_2 <<: *add_node_group_policy_2 From 5affc77f9357b3c6f43714911cda06fd454dfd0e Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:31:53 +0530 Subject: [PATCH 05/12] [ignore] Changed the bfd multi-hop attribute structure in ndo_l3out_node_group_policy module --- .../modules/ndo_l3out_node_group_policy.py | 147 ++++++++++-------- .../tasks/main.yml | 91 +++++++---- 2 files changed, 147 insertions(+), 91 deletions(-) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 7afec1ee..9a1cd819 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -48,22 +48,32 @@ - The name of the L3Out Node Routing Policy. - Providing an empty string will remove the O(node_routing_policy="") from L3Out Node Group Policy. type: str - bfd_multi_hop_authentication: + bfd: description: - - The Bidirectional Forwarding Detection (BFD) multi-hop authentication of the L3Out Node Group Policy. - - To enable the O(bfd_multi_hop_authentication) BGP routing protocol must be configured on the L3Out. - - To clear the BFD auth configuration, provide the values O(bfd_multi_hop_authentication=""), O(bfd_multi_hop_key=""), and O(bfd_multi_hop_key_id=0). - type: str - choices: [ enabled, disabled, "" ] - bfd_multi_hop_key_id: - description: - - The BFD multi-hop key ID of the L3Out Node Group Policy. - - Providing 0 will remove the O(bfd_multi_hop_key_id=0) from L3Out Node Group Policy. - type: int - bfd_multi_hop_key: - description: - - The BFD multi-hop key of the L3Out Node Group Policy. - type: str + - The Bidirectional Forwarding Detection (BFD) multi-hop configuration of the L3Out Node Group Policy. + type: dict + suboptions: + state: + description: + - Use C(enabled) to configure the BFD multi-hop. + - Use C(disabled) to remove the BFD multi-hop. + type: str + choices: [ enabled, disabled ] + auth: + description: + - The BFD multi-hop authentication of the L3Out Node Group Policy. + type: str + choices: [ enabled, disabled ] + aliases: [ bfd_multi_hop_authentication ] + key_id: + description: + - The BFD multi-hop key ID of the L3Out Node Group Policy. + type: int + key: + description: + - The BFD multi-hop key of the L3Out Node Group Policy. + type: str + aliases: [ bfd_multi_hop ] target_dscp: description: - The DSCP Level of the L3Out Node Group Policy. @@ -131,13 +141,14 @@ name: node_group_policy_1 description: "Updated description" node_routing_policy: ans_node_policy_group_1 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key_id: 1 - bfd_multi_hop_key: TestKey + bfd: + auth: enabled + key_id: 1 + key: TestKey target_dscp: af11 state: present -- name: Query a L3Out node group policy +- name: Query an existing L3Out node group policy with name cisco.mso.ndo_l3out_node_group_policy: host: mso_host username: admin @@ -148,6 +159,16 @@ state: query register: query_with_name +- name: Query all L3Out node group policy + cisco.mso.ndo_l3out_node_group_policy: + host: mso_host + username: admin + password: SomeSecretPassword + template: l3out_template + l3out: l3out + state: query + register: query_all + - name: Delete an existing L3Out node group policy with name cisco.mso.ndo_l3out_node_group_policy: host: mso_host @@ -179,9 +200,16 @@ def main(): name=dict(type="str", aliases=["l3out_node_group_policy"]), description=dict(type="str"), node_routing_policy=dict(type="str"), - bfd_multi_hop_authentication=dict(type="str", choices=["enabled", "disabled", ""]), - bfd_multi_hop_key_id=dict(type="int"), - bfd_multi_hop_key=dict(type="str", no_log=True), + bfd=dict( + type="dict", + options=dict( + state=dict(type="str", choices=["enabled", "disabled"]), + auth=dict(type="str", choices=["enabled", "disabled"], aliases=["bfd_multi_hop_authentication"]), + key_id=dict(type="int"), + key=dict(type="str", no_log=True), + ), + aliases=["bfd_multi_hop"], + ), target_dscp=dict(type="str", choices=list(TARGET_DSCP_MAP)), state=dict(type="str", default="query", choices=["absent", "query", "present"]), ) @@ -202,9 +230,7 @@ def main(): name = module.params.get("name") description = module.params.get("description") node_routing_policy = module.params.get("node_routing_policy") - bfd_multi_hop_authentication = module.params.get("bfd_multi_hop_authentication") - bfd_multi_hop_key_id = module.params.get("bfd_multi_hop_key_id") - bfd_multi_hop_key = module.params.get("bfd_multi_hop_key") + bfd = module.params.get("bfd") target_dscp = TARGET_DSCP_MAP.get(module.params.get("target_dscp")) state = module.params.get("state") @@ -258,37 +284,35 @@ def main(): ops.append(dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=node_routing_policy)) proposed_payload["nodeRoutingPolicyRef"] = node_routing_policy - if bfd_multi_hop_authentication or bfd_multi_hop_key or bfd_multi_hop_key_id: - if not mso.existing.get("bfdMultiHop"): - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) - proposed_payload["bfdMultiHop"] = dict() - - # Ignore when bfd_multi_hop_authentication is None or empty string - if bfd_multi_hop_authentication and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not ( - True if bfd_multi_hop_authentication == "enabled" else False - ): - ops.append( - dict( - op="replace", - path=node_group_policy_path + "/bfdMultiHop/authEnabled", - value=True if bfd_multi_hop_authentication == "enabled" else False, + if bfd: + if bfd.get("state") == "disabled" and proposed_payload.get("bfdMultiHop"): + proposed_payload.pop("bfdMultiHop") + ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) + else: + if not proposed_payload.get("bfdMultiHop"): + proposed_payload["bfdMultiHop"] = dict() + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) + + if bfd.get("auth") and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not (True if bfd.get("auth") == "enabled" else False): + ops.append( + dict( + op="replace", + path=node_group_policy_path + "/bfdMultiHop/authEnabled", + value=True if bfd.get("auth") == "enabled" else False, + ) ) - ) - proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False + proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd.get("auth") == "enabled" else False - if bfd_multi_hop_key_id is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd_multi_hop_key_id: - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd_multi_hop_key_id)) - proposed_payload["bfdMultiHop"]["keyID"] = bfd_multi_hop_key_id + if bfd.get("key_id") is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd.get("key_id"): + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd.get("key_id"))) + proposed_payload["bfdMultiHop"]["keyID"] = bfd.get("key_id") - if bfd_multi_hop_key is not None: - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd_multi_hop_key)) - proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd_multi_hop_key) + if bfd.get("key") is not None: + if not isinstance(proposed_payload["bfdMultiHop"].get("key"), dict): + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) - # Clear the complete BFD multi-hop configuration when all parameters are empty - elif bfd_multi_hop_authentication == "" and bfd_multi_hop_key == "" and bfd_multi_hop_key_id == 0 and mso.existing.get("bfdMultiHop"): - ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) - proposed_payload.pop("bfdMultiHop") + ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd.get("key"))) + proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd.get("key")) if target_dscp is not None and mso.existing.get("targetDscp") != target_dscp: ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) @@ -304,19 +328,20 @@ def main(): if l3out_node_routing_policy_object: payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") - bfd_multi_hop = dict() + if bfd: + bfd_multi_hop = dict() - if bfd_multi_hop_authentication: - bfd_multi_hop["authEnabled"] = True if bfd_multi_hop_authentication == "enabled" else False + if bfd.get("auth"): + bfd_multi_hop["authEnabled"] = True if bfd.get("auth") == "enabled" else False - if bfd_multi_hop_key_id: - bfd_multi_hop["keyID"] = bfd_multi_hop_key_id + if bfd.get("key_id"): + bfd_multi_hop["keyID"] = bfd.get("key_id") - if bfd_multi_hop_key: - bfd_multi_hop["key"] = dict(value=bfd_multi_hop_key) + if bfd.get("key"): + bfd_multi_hop["key"] = dict(value=bfd.get("key")) - if bfd_multi_hop: - payload["bfdMultiHop"] = bfd_multi_hop + if bfd_multi_hop: + payload["bfdMultiHop"] = bfd_multi_hop if target_dscp: payload["targetDscp"] = target_dscp diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index fdecf7cd..1d640e23 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -257,9 +257,10 @@ <<: *nm_node_group_policy_1_present description: "Test description" node_routing_policy: ans_node_policy_group_1 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key_id: 1 - bfd_multi_hop_key: TestKey + bfd: + auth: enabled + key_id: 1 + key: TestKey target_dscp: af11 state: present check_mode: true @@ -328,9 +329,10 @@ name: "node_group_policy_1" description: "Test description updated" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key_id: 2 - bfd_multi_hop_key: TestKeyUpdated + bfd: + auth: enabled + key_id: 2 + key: TestKeyUpdated target_dscp: af12 state: present register: update_node_group_policy_attrs @@ -360,7 +362,8 @@ name: "node_group_policy_1" description: "" node_routing_policy: "" - bfd_multi_hop_authentication: disabled + bfd: + auth: disabled target_dscp: "unspecified" state: present output_level: debug @@ -460,9 +463,10 @@ l3out: "l3out_2" name: "node_group_policy_30" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key_id: 2 - bfd_multi_hop_key: TestKeyUpdated + bfd: + auth: enabled + key_id: 2 + key: TestKeyUpdated target_dscp: af12 state: present register: add_ngp_3_auth_disabled @@ -485,9 +489,10 @@ l3out: "l3out_2" name: "node_group_policy_3" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: disabled - bfd_multi_hop_key_id: 2 - bfd_multi_hop_key: TestKeyUpdated + bfd: + auth: disabled + key_id: 2 + key: TestKeyUpdated target_dscp: af12 state: present register: add_ngp_3_auth_disabled @@ -509,7 +514,8 @@ template: '{{ ansible_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_3" - bfd_multi_hop_key_id: 3 + bfd: + key_id: 3 state: present register: update_ngp_3_with_key_id @@ -534,7 +540,8 @@ template: '{{ ansible_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_3" - bfd_multi_hop_key: TestKeyUpdated1 + bfd: + key: TestKeyUpdated1 state: present register: update_ngp_3_with_key @@ -560,7 +567,8 @@ l3out: "l3out_2" name: "node_group_policy_4" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: disabled + bfd: + auth: disabled target_dscp: af12 state: present register: add_ngp_4_auth_disabled @@ -581,7 +589,8 @@ template: '{{ ansible_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_4" - bfd_multi_hop_key_id: 10 + bfd: + key_id: 10 state: present register: add_key_id_ngp_4_auth_disabled @@ -606,8 +615,9 @@ template: '{{ ansible_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_4" - bfd_multi_hop_authentication: disabled - bfd_multi_hop_key_id: 0 + bfd: + auth: disabled + key_id: 0 state: present output_level: debug register: clear_key_id_ngp_4_auth_disabled @@ -656,8 +666,9 @@ l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_key_id: 3 - bfd_multi_hop_key: TestKeyUpdated1 + bfd: + key_id: 3 + key: TestKeyUpdated1 state: present register: update_ngp_5_only_id_value @@ -681,7 +692,8 @@ l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: enabled + bfd: + auth: enabled state: present register: enable_ngp_5_auth_without_key ignore_errors: true @@ -699,8 +711,9 @@ l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key: TestKeyUpdated4 + bfd: + auth: enabled + key: TestKeyUpdated4 state: present register: update_ngp_5_bfd_config @@ -726,9 +739,8 @@ l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: "" - bfd_multi_hop_authentication: "" - bfd_multi_hop_key_id: 0 - bfd_multi_hop_key: "" + bfd: + state: disabled state: present register: clear_ngp_5_bfd_config @@ -814,9 +826,10 @@ l3out: "l3out_1" name: "node_group_policy_nt" node_routing_policy: ans_node_policy_group_1 - bfd_multi_hop_authentication: enabled - bfd_multi_hop_key_id: 12 - bfd_multi_hop_key: "test" + bfd: + auth: enabled + key_id: 12 + key: "test" state: present register: node_group_policy_nt_with_l3out_1 ignore_errors: true @@ -827,6 +840,24 @@ - node_group_policy_nt_with_l3out_1 is changed - node_group_policy_nt_with_l3out_1.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_1'{{':'}} node group 'node_group_policy_nt'{{':'}} BFD Multihop is not supported with non-BGP routing protocols. Current protocol{{':'}} none" + - name: Create ngp1 with bfd state disabled + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out: "l3out_1" + name: "ngp1" + bfd: + state: disabled + state: present + register: create_ngp1_bfd_disabled + + - name: Assertion check for create ngp1 with bfd state disabled + ansible.builtin.assert: + that: + - create_ngp1_bfd_disabled is changed + - create_ngp1_bfd_disabled.current.name == "ngp1" + - create_ngp1_bfd_disabled.current.bfdMultiHop is not defined + # Cleanup Part - name: Remove l3out tenant template cisco.mso.ndo_template: From d89dff2d278c3376a4bcc9f69451180f1b333c80 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:55:00 +0530 Subject: [PATCH 06/12] [ignore] Removed state from ndo_l3out_node_group_policy module attribute --- plugins/module_utils/utils.py | 9 -------- .../modules/ndo_l3out_node_group_policy.py | 23 ++++++------------- .../tasks/main.yml | 10 ++++---- 3 files changed, 11 insertions(+), 31 deletions(-) diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 1f037a56..0cded945 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -18,15 +18,6 @@ def generate_api_endpoint(path, **kwargs): :param kwargs: Keyword arguments representing query parameters. -> Dict :return: A string representing the full API endpoint with query parameters. -> Str """ - # if not kwargs: - # return path - - # query_strings = ["{0}={1}".format(key, value) for key, value in kwargs.items()] - # query_string = "&".join(query_strings) - # full_url = "{0}?{1}".format(path, query_string) - - # return full_url - return path if not kwargs else "{0}?{1}".format(path, "&".join(["{0}={1}".format(key, value) for key, value in kwargs.items()])) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 9a1cd819..2ad57bf0 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -51,14 +51,9 @@ bfd: description: - The Bidirectional Forwarding Detection (BFD) multi-hop configuration of the L3Out Node Group Policy. + - Providing an empty dictionary will remove the O(bfd={}) from the L3Out Node Group Policy. type: dict suboptions: - state: - description: - - Use C(enabled) to configure the BFD multi-hop. - - Use C(disabled) to remove the BFD multi-hop. - type: str - choices: [ enabled, disabled ] auth: description: - The BFD multi-hop authentication of the L3Out Node Group Policy. @@ -189,7 +184,7 @@ from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP -from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint +from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint, check_if_all_elements_are_none def main(): @@ -203,7 +198,6 @@ def main(): bfd=dict( type="dict", options=dict( - state=dict(type="str", choices=["enabled", "disabled"]), auth=dict(type="str", choices=["enabled", "disabled"], aliases=["bfd_multi_hop_authentication"]), key_id=dict(type="int"), key=dict(type="str", no_log=True), @@ -285,10 +279,10 @@ def main(): proposed_payload["nodeRoutingPolicyRef"] = node_routing_policy if bfd: - if bfd.get("state") == "disabled" and proposed_payload.get("bfdMultiHop"): + if check_if_all_elements_are_none(list(bfd.values())) and proposed_payload.get("bfdMultiHop"): proposed_payload.pop("bfdMultiHop") ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) - else: + elif not check_if_all_elements_are_none(list(bfd.values())): if not proposed_payload.get("bfdMultiHop"): proposed_payload["bfdMultiHop"] = dict() ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) @@ -314,16 +308,14 @@ def main(): ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd.get("key"))) proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd.get("key")) - if target_dscp is not None and mso.existing.get("targetDscp") != target_dscp: + if target_dscp and mso.existing.get("targetDscp") != target_dscp: ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) proposed_payload["targetDscp"] = target_dscp mso.sanitize(proposed_payload, collate=True) else: payload = dict(name=name) - - if description: - payload["description"] = description + payload["description"] = description if l3out_node_routing_policy_object: payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") @@ -343,8 +335,7 @@ def main(): if bfd_multi_hop: payload["bfdMultiHop"] = bfd_multi_hop - if target_dscp: - payload["targetDscp"] = target_dscp + payload["targetDscp"] = target_dscp mso.sanitize(payload) ops.append(dict(op="add", path=node_group_policy_path, value=payload)) diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index 1d640e23..92cfb77d 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -739,8 +739,7 @@ l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: "" - bfd: - state: disabled + bfd: {} state: present register: clear_ngp_5_bfd_config @@ -840,18 +839,17 @@ - node_group_policy_nt_with_l3out_1 is changed - node_group_policy_nt_with_l3out_1.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_1'{{':'}} node group 'node_group_policy_nt'{{':'}} BFD Multihop is not supported with non-BGP routing protocols. Current protocol{{':'}} none" - - name: Create ngp1 with bfd state disabled + - name: Create ngp1 with bfd is an empty dict cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info template: '{{ ansible_l3out_template | default("ansible_test") }}' l3out: "l3out_1" name: "ngp1" - bfd: - state: disabled + bfd: {} state: present register: create_ngp1_bfd_disabled - - name: Assertion check for create ngp1 with bfd state disabled + - name: Assertion check for create ngp1 with bfd is an empty dict ansible.builtin.assert: that: - create_ngp1_bfd_disabled is changed From 6a303177dc273d1a0e5fb53ee81e3a406a1da2b5 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Fri, 8 Nov 2024 19:26:01 +0530 Subject: [PATCH 07/12] [ignore] Added name check to the query all assertion task --- .../targets/ndo_l3out_node_group_policy/tasks/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index 92cfb77d..4a8ec2ff 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -455,6 +455,8 @@ that: - query_all_node_group_policies is not changed - query_all_node_group_policies.current | length == 2 + - "'node_group_policy_2' in query_all_node_group_policies.current | map(attribute='name') | list" + - "'node_group_policy_1' in query_all_node_group_policies.current | map(attribute='name') | list" - name: Create node_group_policy_30 with bfd_multi_hop_authentication enabled, key id and value cisco.mso.ndo_l3out_node_group_policy: From fe8e1d380fe85cced4530e7140de64c31f0d0223 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:30:28 +0530 Subject: [PATCH 08/12] [ignore] Rebased with latest master to include append_update_ops_data for the ndo_l3out_node_group_policy module --- plugins/module_utils/constants.py | 2 + plugins/module_utils/utils.py | 10 +++ .../modules/ndo_l3out_node_group_policy.py | 60 ++++++----------- .../tasks/main.yml | 66 +++++++++---------- 4 files changed, 64 insertions(+), 74 deletions(-) diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index 489cd55e..1fd80330 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -211,3 +211,5 @@ ORIGINATE_DEFAULT_ROUTE = {"only": "only", "in_addition": "inAddition", "": ""} L3OUT_ROUTING_PROTOCOLS = {"bgp": ["bgp"], "ospf": ["ospf"], "bgpOspf": ["bgp", "ospf"], None: [None], "": None, "bgpospf": "bgpOspf", "ospfbgp": "bgpOspf"} + +ENABLED_DISABLED_BOOLEAN_MAP = {"enabled": True, "disabled": False, True: "enabled", False: "disabled"} diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py index 0cded945..6fa0c58c 100644 --- a/plugins/module_utils/utils.py +++ b/plugins/module_utils/utils.py @@ -136,3 +136,13 @@ def recursive_delete(data, path, keys): for key in remove_data: recursive_delete(existing_data, update_path, key if isinstance(key, tuple) else (key,)) + + +def check_if_all_elements_are_none(values): + """ + Checks if all the elements in the provided list are None. + + :param values: List of values to check. -> List + :return: True if all elements are None, False otherwise. -> boo + """ + return all(value is None for value in values) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 2ad57bf0..0cb7e0b8 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -183,8 +183,8 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair -from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP -from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint, check_if_all_elements_are_none +from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP, ENABLED_DISABLED_BOOLEAN_MAP +from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint, check_if_all_elements_are_none, append_update_ops_data def main(): @@ -258,60 +258,38 @@ def main(): if mso.existing: proposed_payload = copy.deepcopy(mso.existing) + replace_data = dict() + remove_data = list() + if proposed_payload.get("bfdMultiHop", {}).get("key", {}).get("ref"): proposed_payload["bfdMultiHop"]["key"].pop("ref", None) mso.existing["bfdMultiHop"]["key"].pop("ref", None) - if description is not None and mso.existing.get("description") != description: - ops.append(dict(op="replace", path=node_group_policy_path + "/description", value=description)) - proposed_payload["description"] = description - - if l3out_node_routing_policy_object and mso.existing.get("nodeRoutingPolicyRef") != l3out_node_routing_policy_object.details.get("uuid"): - ops.append( - dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=l3out_node_routing_policy_object.details.get("uuid")) - ) - proposed_payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") + replace_data["description"] = description - elif node_routing_policy == "" and mso.existing.get( + if node_routing_policy == "" and mso.existing.get( "nodeRoutingPolicyRef" ): # Clear the node routing policy when node_routing_policy is empty string - ops.append(dict(op="replace", path=node_group_policy_path + "/nodeRoutingPolicyRef", value=node_routing_policy)) - proposed_payload["nodeRoutingPolicyRef"] = node_routing_policy + remove_data.append("nodeRoutingPolicyRef") + else: + replace_data["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if l3out_node_routing_policy_object else None if bfd: if check_if_all_elements_are_none(list(bfd.values())) and proposed_payload.get("bfdMultiHop"): - proposed_payload.pop("bfdMultiHop") - ops.append(dict(op="remove", path=node_group_policy_path + "/bfdMultiHop")) + remove_data.append("bfdMultiHop") elif not check_if_all_elements_are_none(list(bfd.values())): if not proposed_payload.get("bfdMultiHop"): - proposed_payload["bfdMultiHop"] = dict() - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop", value=dict())) - - if bfd.get("auth") and mso.existing.get("bfdMultiHop", {}).get("authEnabled") is not (True if bfd.get("auth") == "enabled" else False): - ops.append( - dict( - op="replace", - path=node_group_policy_path + "/bfdMultiHop/authEnabled", - value=True if bfd.get("auth") == "enabled" else False, - ) - ) - proposed_payload["bfdMultiHop"]["authEnabled"] = True if bfd.get("auth") == "enabled" else False - - if bfd.get("key_id") is not None and mso.existing.get("bfdMultiHop", {}).get("keyID") != bfd.get("key_id"): - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/keyID", value=bfd.get("key_id"))) - proposed_payload["bfdMultiHop"]["keyID"] = bfd.get("key_id") + replace_data["bfdMultiHop"] = dict() - if bfd.get("key") is not None: - if not isinstance(proposed_payload["bfdMultiHop"].get("key"), dict): - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key", value=dict())) + replace_data[("bfdMultiHop", "authEnabled")] = ENABLED_DISABLED_BOOLEAN_MAP.get(bfd.get("auth")) + replace_data[("bfdMultiHop", "keyID")] = bfd.get("key_id") - ops.append(dict(op="replace", path=node_group_policy_path + "/bfdMultiHop/key/value", value=bfd.get("key"))) - proposed_payload["bfdMultiHop"]["key"] = dict(value=bfd.get("key")) + if bfd.get("key") is not None: + replace_data[("bfdMultiHop", "key")] = dict(value=bfd.get("key")) - if target_dscp and mso.existing.get("targetDscp") != target_dscp: - ops.append(dict(op="replace", path=node_group_policy_path + "/targetDscp", value=target_dscp)) - proposed_payload["targetDscp"] = target_dscp + replace_data["targetDscp"] = target_dscp + append_update_ops_data(ops, proposed_payload, node_group_policy_path, replace_data, remove_data) mso.sanitize(proposed_payload, collate=True) else: payload = dict(name=name) @@ -324,7 +302,7 @@ def main(): bfd_multi_hop = dict() if bfd.get("auth"): - bfd_multi_hop["authEnabled"] = True if bfd.get("auth") == "enabled" else False + bfd_multi_hop["authEnabled"] = ENABLED_DISABLED_BOOLEAN_MAP.get(bfd.get("auth")) if bfd.get("key_id"): bfd_multi_hop["keyID"] = bfd.get("key_id") diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index 4a8ec2ff..165d40a8 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -41,7 +41,7 @@ - name: Ensure ansible_test tenant exist cisco.mso.mso_tenant: <<: *mso_info - tenant: '{{ ansible_tenant | default("ansible_test") }}' + tenant: '{{ mso_tenant | default("ansible_test") }}' users: - "{{ mso_username }}" sites: @@ -65,9 +65,9 @@ - name: Ensure l3out template not exist cisco.mso.ndo_template: &ndo_l3out_template_absent <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' template_type: l3out - tenant: '{{ ansible_tenant | default("ansible_test") }}' + tenant: '{{ mso_tenant | default("ansible_test") }}' sites: - name: '{{ mso_site | default("ansible_test") }}' state: absent @@ -77,7 +77,7 @@ <<: *mso_info name: ansible_test_policy template_type: tenant - tenant: '{{ ansible_tenant | default("ansible_test") }}' + tenant: '{{ mso_tenant | default("ansible_test") }}' state: absent - name: Ensure common tenant policy template not exists @@ -90,8 +90,8 @@ - name: Ensure ansible_test schema template not exist cisco.mso.mso_schema_template: &mso_schema_template_absent <<: *mso_info - schema: '{{ ansible_schema | default("ansible_test") }}' - tenant: '{{ ansible_tenant | default("ansible_test") }}' + schema: '{{ mso_schema | default("ansible_test") }}' + tenant: '{{ mso_tenant | default("ansible_test") }}' template: "Template1" state: absent @@ -104,7 +104,7 @@ - name: Add a new VRF1 cisco.mso.mso_schema_template_vrf: <<: *mso_info - schema: '{{ ansible_schema | default("ansible_test") }}' + schema: '{{ mso_schema | default("ansible_test") }}' template: "Template1" vrf: VRF1 layer3_multicast: true @@ -160,11 +160,11 @@ - name: Create l3out_1 object without routing protocols cisco.mso.ndo_l3out_template: &l3out_1_present <<: *mso_info - l3out_template: '{{ ansible_l3out_template | default("ansible_test") }}' + l3out_template: '{{ mso_l3out_template | default("ansible_test") }}' name: "l3out_1" vrf: name: "VRF1" - schema: '{{ ansible_schema | default("ansible_test") }}' + schema: '{{ mso_schema | default("ansible_test") }}' template: "Template1" state: "present" @@ -179,7 +179,7 @@ - name: Query all L3Out node group policy objects when the L3Out is empty cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" state: query register: query_all_node_groups_1 @@ -193,7 +193,7 @@ - name: Query node_group_policy_1 L3Out node group policy object when the L3Out is empty cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_1" state: query @@ -208,7 +208,7 @@ - name: Create L3Out node group policy object with default values - check mode cisco.mso.ndo_l3out_node_group_policy: &cm_node_group_policy_1_present <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_1" state: present @@ -324,7 +324,7 @@ - name: Update node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_1" description: "Test description updated" @@ -357,7 +357,7 @@ - name: Clear node_group_policy_1 - bfd_multi_hop_key id, value, target_dscp and node_routing_policy values cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_1" description: "" @@ -387,7 +387,7 @@ - name: Query node_group_policy_1 cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_1" state: query @@ -405,7 +405,7 @@ - name: Add node_group_policy_2 with common tenant node_routing_policy object cisco.mso.ndo_l3out_node_group_policy: &add_node_group_policy_2 <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_2" description: "Create test description" @@ -427,7 +427,7 @@ - name: Query node_group_policy_2 cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_2" state: query @@ -445,7 +445,7 @@ - name: Query all node_group_policies cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" state: query register: query_all_node_group_policies @@ -461,7 +461,7 @@ - name: Create node_group_policy_30 with bfd_multi_hop_authentication enabled, key id and value cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_30" node_routing_policy: ans_node_policy_group_2 @@ -487,7 +487,7 @@ - name: Create node_group_policy_3 with bfd_multi_hop_authentication disabled, key id and value cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_3" node_routing_policy: ans_node_policy_group_2 @@ -513,7 +513,7 @@ - name: Update node_group_policy_3 with only bfd_multi_hop_key_id cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_3" bfd: @@ -539,7 +539,7 @@ - name: Update node_group_policy_3 with only bfd_multi_hop_key - task flag changed should be false wth authentication is disabled cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_3" bfd: @@ -565,7 +565,7 @@ - name: Create node_group_policy_4 with bfd_multi_hop_authentication disabled without bfd_multi_hop_key_id and bfd_multi_hop_key cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_4" node_routing_policy: ans_node_policy_group_2 @@ -588,7 +588,7 @@ - name: Add bfd_multi_hop_key_id to node_group_policy_4 when bfd_multi_hop_authentication is disabled cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_4" bfd: @@ -614,7 +614,7 @@ - name: Remove bfd_multi_hop_key_id from node_group_policy_4 when bfd_multi_hop_authentication is disabled cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_4" bfd: @@ -645,7 +645,7 @@ - name: Create node_group_policy_5 without bfd config cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 @@ -664,7 +664,7 @@ - name: Update node_group_policy_5 with only bfd_multi_hop_key_id and bfd_multi_hop_key cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 @@ -690,7 +690,7 @@ - name: Enable bfd_multi_hop_authentication without bfd_multi_hop_key on node_group_policy_5 cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 @@ -709,7 +709,7 @@ - name: Update node_group_policy_5 with bfd config cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: ans_node_policy_group_2 @@ -737,7 +737,7 @@ - name: Clear complete bfd and node_routing_policy config from node_group_policy_5 cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_2" name: "node_group_policy_5" node_routing_policy: "" @@ -805,7 +805,7 @@ - name: Create L3Out node group policy object with invalid l3out name cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_nt" name: "node_group_policy_nt" state: present @@ -823,7 +823,7 @@ - name: Create L3Out node group policy object with l3out_1 template cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_1" name: "node_group_policy_nt" node_routing_policy: ans_node_policy_group_1 @@ -844,7 +844,7 @@ - name: Create ngp1 with bfd is an empty dict cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info - template: '{{ ansible_l3out_template | default("ansible_test") }}' + template: '{{ mso_l3out_template | default("ansible_test") }}' l3out: "l3out_1" name: "ngp1" bfd: {} From 41e7e98d7dd64a4a5c69ab68317fc9eed9f74c18 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Tue, 10 Dec 2024 17:56:17 +0530 Subject: [PATCH 09/12] [ignore] Removed ENABLED_DISABLED_BOOLEAN_MAP from constants.py file --- plugins/module_utils/constants.py | 2 - .../modules/ndo_l3out_node_group_policy.py | 42 +++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/plugins/module_utils/constants.py b/plugins/module_utils/constants.py index 1fd80330..489cd55e 100644 --- a/plugins/module_utils/constants.py +++ b/plugins/module_utils/constants.py @@ -211,5 +211,3 @@ ORIGINATE_DEFAULT_ROUTE = {"only": "only", "in_addition": "inAddition", "": ""} L3OUT_ROUTING_PROTOCOLS = {"bgp": ["bgp"], "ospf": ["ospf"], "bgpOspf": ["bgp", "ospf"], None: [None], "": None, "bgpospf": "bgpOspf", "ospfbgp": "bgpOspf"} - -ENABLED_DISABLED_BOOLEAN_MAP = {"enabled": True, "disabled": False, True: "enabled", False: "disabled"} diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 0cb7e0b8..f3006f49 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -183,7 +183,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.mso.plugins.module_utils.mso import MSOModule, mso_argument_spec from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair -from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP, ENABLED_DISABLED_BOOLEAN_MAP +from ansible_collections.cisco.mso.plugins.module_utils.constants import TARGET_DSCP_MAP, ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint, check_if_all_elements_are_none, append_update_ops_data @@ -258,51 +258,51 @@ def main(): if mso.existing: proposed_payload = copy.deepcopy(mso.existing) - replace_data = dict() - remove_data = list() + mso_values = dict() + mso_values_remove = list() if proposed_payload.get("bfdMultiHop", {}).get("key", {}).get("ref"): proposed_payload["bfdMultiHop"]["key"].pop("ref", None) mso.existing["bfdMultiHop"]["key"].pop("ref", None) - replace_data["description"] = description + mso_values["description"] = description if node_routing_policy == "" and mso.existing.get( "nodeRoutingPolicyRef" ): # Clear the node routing policy when node_routing_policy is empty string - remove_data.append("nodeRoutingPolicyRef") + mso_values_remove.append("nodeRoutingPolicyRef") else: - replace_data["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if l3out_node_routing_policy_object else None + mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if l3out_node_routing_policy_object else None if bfd: if check_if_all_elements_are_none(list(bfd.values())) and proposed_payload.get("bfdMultiHop"): - remove_data.append("bfdMultiHop") + mso_values_remove.append("bfdMultiHop") elif not check_if_all_elements_are_none(list(bfd.values())): if not proposed_payload.get("bfdMultiHop"): - replace_data["bfdMultiHop"] = dict() + mso_values["bfdMultiHop"] = dict() - replace_data[("bfdMultiHop", "authEnabled")] = ENABLED_DISABLED_BOOLEAN_MAP.get(bfd.get("auth")) - replace_data[("bfdMultiHop", "keyID")] = bfd.get("key_id") + mso_values[("bfdMultiHop", "authEnabled")] = ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP.get(bfd.get("auth")) + mso_values[("bfdMultiHop", "keyID")] = bfd.get("key_id") if bfd.get("key") is not None: - replace_data[("bfdMultiHop", "key")] = dict(value=bfd.get("key")) + mso_values[("bfdMultiHop", "key")] = dict(value=bfd.get("key")) - replace_data["targetDscp"] = target_dscp + mso_values["targetDscp"] = target_dscp - append_update_ops_data(ops, proposed_payload, node_group_policy_path, replace_data, remove_data) + append_update_ops_data(ops, proposed_payload, node_group_policy_path, mso_values, mso_values_remove) mso.sanitize(proposed_payload, collate=True) else: - payload = dict(name=name) - payload["description"] = description + mso_values = dict(name=name) + mso_values["description"] = description if l3out_node_routing_policy_object: - payload["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") + mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if bfd: bfd_multi_hop = dict() if bfd.get("auth"): - bfd_multi_hop["authEnabled"] = ENABLED_DISABLED_BOOLEAN_MAP.get(bfd.get("auth")) + bfd_multi_hop["authEnabled"] = ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP.get(bfd.get("auth")) if bfd.get("key_id"): bfd_multi_hop["keyID"] = bfd.get("key_id") @@ -311,12 +311,12 @@ def main(): bfd_multi_hop["key"] = dict(value=bfd.get("key")) if bfd_multi_hop: - payload["bfdMultiHop"] = bfd_multi_hop + mso_values["bfdMultiHop"] = bfd_multi_hop - payload["targetDscp"] = target_dscp + mso_values["targetDscp"] = target_dscp - mso.sanitize(payload) - ops.append(dict(op="add", path=node_group_policy_path, value=payload)) + mso.sanitize(mso_values) + ops.append(dict(op="add", path=node_group_policy_path, value=mso_values)) mso.existing = mso.proposed From 93a5fdbf511a544d2b7b33b8f6cdd8d11f9fa6cb Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:28:53 +0530 Subject: [PATCH 10/12] [ignore] Removed UUID from get_l3out_node_group function doc string from the mso_utils template.py --- plugins/module_utils/template.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/template.py b/plugins/module_utils/template.py index 249c215c..aaaab21d 100644 --- a/plugins/module_utils/template.py +++ b/plugins/module_utils/template.py @@ -243,10 +243,10 @@ def get_l3out_node_group(self, name, l3out_object, fail_module=False): :param l3out_object: L3Out object to search Node Group Policy -> Dict :param fail_module: When match is not found fail the ansible module -> Bool :return: Dict | None | List[Dict] | List[]: The processed result which could be: - When the UUID | Name is existing in the search list -> Dict - When the UUID | Name is not existing in the search list -> None - When both UUID and Name are None, and the search list is not empty -> List[Dict] - When both UUID and Name are None, and the search list is empty -> List[] + When the Name is existing in the search list -> Dict + When the Name is not existing in the search list -> None + When the Name is None, and the search list is not empty -> List[Dict] + When the Name is None, and the search list is empty -> List[] """ existing_l3out_node_groups = l3out_object.get("nodeGroups", []) if name: # Query a specific object From 71e9808717292eb16907dde11c17c14877d50fab Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Fri, 13 Dec 2024 17:51:41 +0530 Subject: [PATCH 11/12] [ignore] Changed the BFD Multi Hop create and update logic --- .../modules/ndo_l3out_node_group_policy.py | 56 ++++++++++--------- .../tasks/main.yml | 4 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index f3006f49..9c9cf485 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -187,6 +187,16 @@ from ansible_collections.cisco.mso.plugins.module_utils.utils import generate_api_endpoint, check_if_all_elements_are_none, append_update_ops_data +def bfd_multi_hop_mso_values(bfd): + return dict( + authEnabled=ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP.get(bfd.get("auth")), + keyID=bfd.get("key_id"), + key=dict( + value=bfd.get("key"), + ), + ) + + def main(): argument_spec = mso_argument_spec() argument_spec.update( @@ -235,7 +245,8 @@ def main(): l3out_node_group = mso_template.get_l3out_node_group(name, l3out_object.details) if name and l3out_node_group: - mso.existing = mso.previous = copy.deepcopy(l3out_node_group.details) # Query a specific object + mso.existing = copy.deepcopy(l3out_node_group.details) + mso.previous = copy.deepcopy(l3out_node_group.details) # Query a specific object elif l3out_node_group: mso.existing = l3out_node_group # Query all objects @@ -245,6 +256,10 @@ def main(): ops = [] if state == "present": + if bfd: + # True if all elements are None, False otherwise. + bfd_is_empty = check_if_all_elements_are_none(list(bfd.values())) + l3out_node_routing_policy_object = None if node_routing_policy: l3out_node_routing_policy_objects = mso.query_objs( @@ -257,13 +272,12 @@ def main(): ) if mso.existing: - proposed_payload = copy.deepcopy(mso.existing) mso_values = dict() mso_values_remove = list() - if proposed_payload.get("bfdMultiHop", {}).get("key", {}).get("ref"): - proposed_payload["bfdMultiHop"]["key"].pop("ref", None) + if mso.existing.get("bfdMultiHop", {}).get("key", {}).get("ref"): mso.existing["bfdMultiHop"]["key"].pop("ref", None) + mso.previous["bfdMultiHop"]["key"].pop("ref", None) mso_values["description"] = description @@ -275,22 +289,26 @@ def main(): mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if l3out_node_routing_policy_object else None if bfd: - if check_if_all_elements_are_none(list(bfd.values())) and proposed_payload.get("bfdMultiHop"): + if bfd_is_empty and mso.existing.get("bfdMultiHop"): mso_values_remove.append("bfdMultiHop") - elif not check_if_all_elements_are_none(list(bfd.values())): - if not proposed_payload.get("bfdMultiHop"): - mso_values["bfdMultiHop"] = dict() + elif not bfd_is_empty and not mso.existing.get("bfdMultiHop"): + mso_values["bfdMultiHop"] = bfd_multi_hop_mso_values(bfd) + + elif not bfd_is_empty and mso.existing.get("bfdMultiHop"): mso_values[("bfdMultiHop", "authEnabled")] = ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP.get(bfd.get("auth")) mso_values[("bfdMultiHop", "keyID")] = bfd.get("key_id") if bfd.get("key") is not None: - mso_values[("bfdMultiHop", "key")] = dict(value=bfd.get("key")) + if mso.existing.get("bfdMultiHop", {}).get("key") is not None: + mso_values[("bfdMultiHop", "key", "value")] = bfd.get("key") + else: + mso_values[("bfdMultiHop", "key")] = dict(value=bfd.get("key")) mso_values["targetDscp"] = target_dscp - append_update_ops_data(ops, proposed_payload, node_group_policy_path, mso_values, mso_values_remove) - mso.sanitize(proposed_payload, collate=True) + append_update_ops_data(ops, mso.existing, node_group_policy_path, mso_values, mso_values_remove) + mso.sanitize(mso.existing, collate=True) else: mso_values = dict(name=name) mso_values["description"] = description @@ -298,20 +316,8 @@ def main(): if l3out_node_routing_policy_object: mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") - if bfd: - bfd_multi_hop = dict() - - if bfd.get("auth"): - bfd_multi_hop["authEnabled"] = ENABLED_OR_DISABLED_TO_BOOL_STRING_MAP.get(bfd.get("auth")) - - if bfd.get("key_id"): - bfd_multi_hop["keyID"] = bfd.get("key_id") - - if bfd.get("key"): - bfd_multi_hop["key"] = dict(value=bfd.get("key")) - - if bfd_multi_hop: - mso_values["bfdMultiHop"] = bfd_multi_hop + if bfd and not bfd_is_empty: + mso_values["bfdMultiHop"] = bfd_multi_hop_mso_values(bfd) mso_values["targetDscp"] = target_dscp diff --git a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml index 165d40a8..3d8fb0e5 100644 --- a/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -841,7 +841,7 @@ - node_group_policy_nt_with_l3out_1 is changed - node_group_policy_nt_with_l3out_1.msg == "MSO Error 400{{':'}} Invalid configuration in L3Out 'l3out_1'{{':'}} node group 'node_group_policy_nt'{{':'}} BFD Multihop is not supported with non-BGP routing protocols. Current protocol{{':'}} none" - - name: Create ngp1 with bfd is an empty dict + - name: Create ngp1 with an empty bfd configuration cisco.mso.ndo_l3out_node_group_policy: <<: *mso_info template: '{{ mso_l3out_template | default("ansible_test") }}' @@ -851,7 +851,7 @@ state: present register: create_ngp1_bfd_disabled - - name: Assertion check for create ngp1 with bfd is an empty dict + - name: Assertion check for create ngp1 with an empty bfd configuration ansible.builtin.assert: that: - create_ngp1_bfd_disabled is changed From e1eecfdffa699152fe582e549162ef618ad392a6 Mon Sep 17 00:00:00 2001 From: Sabari Jaganathan <93724860+sajagana@users.noreply.github.com> Date: Tue, 17 Dec 2024 12:11:14 +0530 Subject: [PATCH 12/12] [ignore] Added seealso section to the ndo_l3out_node_group_policy module --- plugins/modules/ndo_l3out_node_group_policy.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/modules/ndo_l3out_node_group_policy.py b/plugins/modules/ndo_l3out_node_group_policy.py index 9c9cf485..67619874 100644 --- a/plugins/modules/ndo_l3out_node_group_policy.py +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -112,6 +112,10 @@ Use M(cisco.mso.ndo_l3out_template) to create the L3Out object under the L3Out template. - The O(node_routing_policy) must exist before using this module in your playbook. Use M(cisco.mso.ndo_l3out_node_routing_policy) to create the L3Out Node Routing Policy. +seealso: +- module: cisco.mso.ndo_template +- module: cisco.mso.ndo_l3out_template +- module: cisco.mso.ndo_l3out_node_routing_policy extends_documentation_fragment: cisco.mso.modules """