diff --git a/plugins/module_utils/template.py b/plugins/module_utils/template.py index 011e5e7d..aaaab21d 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 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 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 + 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/module_utils/utils.py b/plugins/module_utils/utils.py index 1f037a56..6fa0c58c 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()])) @@ -145,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 new file mode 100644 index 00000000..67619874 --- /dev/null +++ b/plugins/modules/ndo_l3out_node_group_policy.py @@ -0,0 +1,354 @@ +#!/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 Group Policy on Cisco Nexus Dashboard Orchestrator (NDO). +description: +- 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) +options: + template: + description: + - The name of the template. + - The template must be an 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 Group Policy. + type: str + aliases: [ l3out_node_group_policy ] + description: + description: + - The description of the L3Out Node Group Policy. + type: str + 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: + 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: + 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. + 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. +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 +""" + +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: + auth: enabled + key_id: 1 + key: TestKey + target_dscp: af11 + state: present + +- name: Query 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: 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 + 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, 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 + + +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( + 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=dict( + type="dict", + options=dict( + 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"]), + ) + + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[ + ["state", "absent", ["name"]], + ["state", "present", ["name"]], + ], + ) + + 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 = module.params.get("bfd") + 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 and l3out_node_group: + 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 + + 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": + 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( + 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: + mso_values = dict() + mso_values_remove = list() + + 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 + + if node_routing_policy == "" and mso.existing.get( + "nodeRoutingPolicyRef" + ): # Clear the node routing policy when node_routing_policy is empty string + mso_values_remove.append("nodeRoutingPolicyRef") + else: + mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") if l3out_node_routing_policy_object else None + + if bfd: + if bfd_is_empty and mso.existing.get("bfdMultiHop"): + mso_values_remove.append("bfdMultiHop") + + 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: + 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, 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 + + if l3out_node_routing_policy_object: + mso_values["nodeRoutingPolicyRef"] = l3out_node_routing_policy_object.details.get("uuid") + + if bfd and not bfd_is_empty: + mso_values["bfdMultiHop"] = bfd_multi_hop_mso_values(bfd) + + mso_values["targetDscp"] = target_dscp + + mso.sanitize(mso_values) + ops.append(dict(op="add", path=node_group_policy_path, value=mso_values)) + + 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 + 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 + 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..3d8fb0e5 --- /dev/null +++ b/tests/integration/targets/ndo_l3out_node_group_policy/tasks/main.yml @@ -0,0 +1,880 @@ +# 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 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: '{{ mso_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 + template: '{{ mso_l3out_template | default("ansible_test") }}' + template_type: l3out + tenant: '{{ mso_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: '{{ mso_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: '{{ mso_schema | default("ansible_test") }}' + tenant: '{{ mso_tenant | default("ansible_test") }}' + template: "Template1" + state: absent + + # 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: '{{ mso_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: '{{ mso_l3out_template | default("ansible_test") }}' + name: "l3out_1" + vrf: + name: "VRF1" + schema: '{{ mso_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: '{{ mso_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: '{{ mso_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: '{{ mso_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 + + - 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 + + - 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 + + - 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: + auth: enabled + key_id: 1 + key: TestKey + target_dscp: af11 + state: present + check_mode: true + register: cm_update_node_group_policy_1 + + - 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.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 != "" + - 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 + + - 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 == 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" + - 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 + + - 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 == true + - 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 == 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" + - 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: '{{ mso_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: + auth: enabled + key_id: 2 + key: TestKeyUpdated + target_dscp: af12 + state: present + register: update_node_group_policy_attrs + + - 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 == 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 == 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" + - 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_1" + description: "" + node_routing_policy: "" + bfd: + auth: disabled + target_dscp: "unspecified" + state: present + output_level: debug + register: clear_node_group_policy_attrs + + - 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.bfdMultiHop.authEnabled == false + - clear_node_group_policy_attrs.current.targetDscp == "unspecified" + - 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" + - 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: '{{ mso_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 + 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" + - 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 + <<: *mso_info + template: '{{ mso_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 + + - 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_2" + state: query + register: query_node_group_policy_2 + + - 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + state: query + register: query_all_node_group_policies + + - 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 + - "'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: + <<: *mso_info + template: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_30" + node_routing_policy: ans_node_policy_group_2 + bfd: + auth: enabled + key_id: 2 + 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.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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + node_routing_policy: ans_node_policy_group_2 + bfd: + auth: disabled + key_id: 2 + 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.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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + bfd: + 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_3" + bfd: + 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + node_routing_policy: ans_node_policy_group_2 + bfd: + auth: 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: 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + bfd: + 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_4" + bfd: + auth: disabled + 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 + template: '{{ mso_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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd: + key_id: 3 + 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd: + auth: 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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: ans_node_policy_group_2 + bfd: + auth: enabled + 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.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: Clear complete bfd and node_routing_policy config from node_group_policy_5 + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_2" + name: "node_group_policy_5" + node_routing_policy: "" + bfd: {} + 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 + 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: '{{ mso_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: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_1" + name: "node_group_policy_nt" + node_routing_policy: ans_node_policy_group_1 + bfd: + auth: enabled + key_id: 12 + 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.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 an empty bfd configuration + cisco.mso.ndo_l3out_node_group_policy: + <<: *mso_info + template: '{{ mso_l3out_template | default("ansible_test") }}' + l3out: "l3out_1" + name: "ngp1" + bfd: {} + state: present + register: create_ngp1_bfd_disabled + + - name: Assertion check for create ngp1 with an empty bfd configuration + 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: + <<: *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