diff --git a/plugins/module_utils/mso.py b/plugins/module_utils/mso.py index f66d4cbb..ccfe3dfb 100644 --- a/plugins/module_utils/mso.py +++ b/plugins/module_utils/mso.py @@ -318,6 +318,19 @@ def write_file(module, url, dest, content, resp, tmpsrc=None): os.remove(tmpsrc) +def format_interface_descriptions(interface_descriptions, node=None): + formated_interface_descriptions = [ + { + "nodeID": node if node is not None else interface_description.get("node"), + "interfaceID": interface_description.get("interface_id", interface_description.get("interfaceID")), + "description": interface_description.get("description"), + } + for interface_description in interface_descriptions + ] + + return formated_interface_descriptions + + class MSOModule(object): def __init__(self, module): self.module = module diff --git a/plugins/module_utils/template.py b/plugins/module_utils/template.py index 4392ce92..50f2013a 100644 --- a/plugins/module_utils/template.py +++ b/plugins/module_utils/template.py @@ -102,6 +102,8 @@ def get_object_by_key_value_pairs(self, object_description, search_list, kv_list :param fail_module: When match is not found fail the ansible module. -> Bool :return: The object. -> Dict | None """ + if search_list is None or kv_list is None: + return None match, existing = self.get_object_from_list(search_list, kv_list) if not match and fail_module: msg = "Provided {0} with '{1}' not matching existing object(s): {2}".format(object_description, kv_list, ", ".join(existing)) @@ -214,7 +216,7 @@ def get_interface_policy_group_uuid(self, interface_policy_group): :param interface_policy_group: Name of the Interface Policy Group to search for -> Str :return: UUID of the Interface Policy Group. -> Str """ - existing_policies = self.template.get("fabricPolicyTemplate", {}).get("template", {}).get("interfacePolicyGroups", []) + existing_policy_groups = self.template.get("fabricPolicyTemplate", {}).get("template", {}).get("interfacePolicyGroups", []) kv_list = [KVPair("name", interface_policy_group)] - match = self.get_object_by_key_value_pairs("Interface Policy Groups", existing_policies, kv_list, fail_module=True) + match = self.get_object_by_key_value_pairs("Interface Policy Groups", existing_policy_groups, kv_list, fail_module=True) return match.details.get("uuid") diff --git a/plugins/modules/ndo_physical_interface.py b/plugins/modules/ndo_physical_interface.py index b2ee2bfb..c9bd2ee7 100644 --- a/plugins/modules/ndo_physical_interface.py +++ b/plugins/modules/ndo_physical_interface.py @@ -14,10 +14,10 @@ DOCUMENTATION = r""" --- module: ndo_physical_interface -short_description: Manage physical interface on Cisco Nexus Dashboard Orchestrator (NDO). +short_description: Manage Physical Interfaces on Cisco Nexus Dashboard Orchestrator (NDO). description: -- Manage physical interface on Cisco Nexus Dashboard Orchestrator (NDO). -- This module is only supported on ND v3.1 (NDO v4.3) and later. +- Manage Physical Interfaces on Cisco Nexus Dashboard Orchestrator (NDO). +- This module is only supported on ND v3.2 (NDO v4.4) and later. author: - Anvitha Jain (@anvjain) options: @@ -27,24 +27,24 @@ - The template must be a fabric resource policy template. type: str required: true - physical_interface: + name: description: - - The name of the physical interface. + - The name of the Physical Interface. type: str - aliases: [ name ] - physical_interface_uuid: + aliases: [ physical_interface ] + uuid: description: - - The UUID of the physical interface. - - This parameter is required when the O(physical_interface) needs to be updated. + - The UUID of the Physical Interface. + - This parameter is required when the O(name) needs to be updated. type: str - aliases: [ uuid ] + aliases: [ physical_interface_uuid ] description: description: - - The description of the physical interface. + - The description of the Physical Interface. type: str nodes: description: - - The node IDs where the physical interface policy will be deployed. + - The node IDs where the Physical Interface policy will be deployed. type: list elements: int interfaces: @@ -61,7 +61,7 @@ physical_policy_uuid: description: - The UUID of the Interface Setting Policy. - - This is only required when creating a new Port Channel Interface. + - This is only required when creating a new Interface Setting Policy. - This parameter is required when O(physical_interface_type) is C(physical). - This parameter can be used instead of O(physical_policy). type: str @@ -75,23 +75,23 @@ suboptions: name: description: - - The name of the Port Channel Interface Setting Policy. + - The name of the Interface Setting Policy. type: str template: description: - - The name of the template in which is referred the Port Channel Interface Policy Group. + - The name of the template in which is referred the Interface Setting Policy. type: str aliases: [ policy, interface_policy, interface_policy_group, interface_setting ] breakout_mode: description: - - The breakout mode enabled splitting of the ethernet ports. + - Breakout mode enables breaking down an ethernet port into multiple low-speed ports. - This parameter is available only when O(physical_interface_type) is C(breakout). - The default value is C(4x10G). type: str choices: [ 4x10G, 4x25G, 4x100G ] interface_descriptions: description: - - The interface settings defined in the interface settings policy will be applied to the interfaces on the nodes you provided. + - The interface settings defined in the interface settings policy will be applied to the interfaces on the node IDs configured in C(nodes). type: list elements: dict suboptions: @@ -124,83 +124,83 @@ """ EXAMPLES = r""" -- name: Create an physical interface physical_interface_type physical +- name: Create a Physical Interface with physical_interface_type set to physical cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface: ansible_test_physical_interface_physical - description: "physical interface for Ansible Test" - nodes: [101] - interfaces: "1/1" - physical_interface_type: physical - physical_policy: ansible_test_interface_setting_policy_uuid - state: present - -- name: Create an physical interface physical_interface_type breakout + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + name: ansible_test_physical_interface_physical + description: "Physical Interface for Ansible Test" + nodes: [101] + interfaces: "1/1" + physical_interface_type: physical + physical_policy: ansible_test_interface_setting_policy_uuid + state: present + +- name: Create a Physical Interface with physical_interface_type set to breakout cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface: ansible_test_physical_interface_breakout - description: "breakout interface for Ansible Test" - nodes: [101] - interfaces: "1/1" - physical_interface_type: breakout - breakout_mode: 4x25G - interface_descriptions: - - interface_id: "1/1" - description: "Interface description for 1/1" - state: present + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + name: ansible_test_physical_interface_breakout + description: "breakout interface for Ansible Test" + nodes: [101] + interfaces: "1/1" + physical_interface_type: breakout + breakout_mode: 4x25G + interface_descriptions: + - interface_id: "1/1" + description: "Interface description for 1/1" + state: present - name: Query all physical interfaces cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - state: query + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + state: query register: query_all -- name: Query a specific physical interface with name +- name: Query a specific Physical Interface with name cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface: ansible_test_physical_interface_physical - state: query + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + name: ansible_test_physical_interface_physical + state: query register: query_one_name -- name: Query a specific physical interface with UUID +- name: Query a specific Physical Interface with UUID cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface_uuid: ansible_test_physical_interface_uuid - state: query + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + uuid: "{{ query_one_uuid.current.uuid }}" + state: query register: query_one_uuid -- name: Delete an physical interface with name +- name: Delete a Physical Interface with name cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface: ansible_test_physical_interface_physical - state: absent - -- name: Delete an physical interface with UUID + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + name: ansible_test_physical_interface_physical + state: absent + +- name: Delete a Physical Interface with UUID cisco.mso.ndo_physical_interface: - host: mso_host - username: admin - password: SomeSecretPassword - template: ansible_test_template - physical_interface_uuid: ansible_test_physical_interface_uuid - state: absent + host: mso_host + username: admin + password: SomeSecretPassword + template: ansible_test_template + uuid: "{{ query_one_uuid.current.uuid }}" + state: absent """ RETURN = r""" @@ -211,6 +211,7 @@ from ansible_collections.cisco.mso.plugins.module_utils.mso import ( MSOModule, mso_argument_spec, + format_interface_descriptions, ) from ansible_collections.cisco.mso.plugins.module_utils.template import MSOTemplate, KVPair import copy @@ -221,8 +222,8 @@ def main(): argument_spec.update( dict( template=dict(type="str", required=True), - physical_interface=dict(type="str", aliases=["name"]), - physical_interface_uuid=dict(type="str", aliases=["uuid"]), + name=dict(type="str", aliases=["physical_interface"]), + uuid=dict(type="str", aliases=["physical_interface_uuid"]), description=dict(type="str"), nodes=dict(type="list", elements="int"), interfaces=dict(type="list", elements="str"), @@ -253,8 +254,8 @@ def main(): argument_spec=argument_spec, supports_check_mode=True, required_if=[ - ["state", "present", ["physical_interface", "physical_interface_uuid"], True], - ["state", "absent", ["physical_interface", "physical_interface_uuid"], True], + ["state", "present", ["name", "uuid"], True], + ["state", "absent", ["name", "uuid"], True], ], mutually_exclusive=[("physical_policy", "breakout_mode"), ("physical_policy", "physical_policy_uuid")], ) @@ -262,8 +263,8 @@ def main(): mso = MSOModule(module) template = module.params.get("template") - physical_interface = module.params.get("physical_interface") - physical_interface_uuid = module.params.get("physical_interface_uuid") + name = module.params.get("name") + uuid = module.params.get("uuid") description = module.params.get("description") nodes = module.params.get("nodes") if nodes: @@ -284,83 +285,80 @@ def main(): mso_template = MSOTemplate(mso, "fabric_resource", template) mso_template.validate_template("fabricResource") - path = "/fabricResourceTemplate/template/interfaceProfiles" object_description = "Physical Interface Profile" - existing_interface_policies = mso_template.template.get("fabricResourceTemplate", {}).get("template", {}) - if existing_interface_policies.get("interfaceProfiles") is not None: - existing_interface_policies = existing_interface_policies.get("interfaceProfiles") - else: - existing_interface_policies = [] + existing_physical_interfaces = mso_template.template.get("fabricResourceTemplate", {}).get("template", {}).get("interfaceProfiles", []) - if physical_interface or physical_interface_uuid: + if state in ["query", "absent"] and not existing_physical_interfaces: + mso.exit_json() + elif state == "query" and not (name or uuid): + mso.existing = existing_physical_interfaces + elif existing_physical_interfaces and (name or uuid): match = mso_template.get_object_by_key_value_pairs( - object_description, - existing_interface_policies, - [KVPair("uuid", physical_interface_uuid) if physical_interface_uuid else KVPair("name", physical_interface)], + object_description, existing_physical_interfaces, [KVPair("uuid", uuid) if uuid else KVPair("name", name)] ) if match: + physical_policy_path = "/fabricResourceTemplate/template/interfaceProfiles/{0}".format(match.index) mso.existing = mso.previous = copy.deepcopy(match.details) - else: - mso.existing = mso.previous = existing_interface_policies if state == "present": + if uuid and not mso.existing: + mso.fail_json(msg="{0} with the UUID: '{1}' not found".format(object_description, uuid)) if physical_policy and not physical_policy_uuid: # check this part and see if this is required or use mutually_exclusive fabric_policy_template = MSOTemplate(mso, "fabric_policy", physical_policy.get("template")) fabric_policy_template.validate_template("fabricPolicy") physical_policy_uuid = fabric_policy_template.get_interface_policy_group_uuid(physical_policy.get("name")) - if match: + if mso.existing: + proposed_payload = copy.deepcopy(match.details) if physical_interface_type and match.details.get("policyGroupType") != physical_interface_type: mso.fail_json(msg="ERROR: Physical Interface type cannot be changed.") - if physical_interface and match.details.get("name") != physical_interface: - ops.append(dict(op="replace", path="{0}/{1}/name".format(path, match.index), value=physical_interface)) - match.details["name"] = physical_interface + if name and match.details.get("name") != name: + ops.append(dict(op="replace", path=physical_policy_path + "/name", value=name)) + proposed_payload["name"] = name if description is not None and match.details.get("description") != description: - ops.append(dict(op="replace", path="{0}/{1}/description".format(path, match.index), value=description)) - match.details["description"] = description + ops.append(dict(op="replace", path=physical_policy_path + "/description", value=description)) + proposed_payload["description"] = description if nodes and match.details.get("nodes") != nodes: - ops.append(dict(op="replace", path="{0}/{1}/nodes".format(path, match.index), value=nodes)) - match.details["nodes"] = nodes + ops.append(dict(op="replace", path=physical_policy_path + "/nodes", value=nodes)) + proposed_payload["nodes"] = nodes if physical_policy_uuid and match.details.get("policy") != physical_policy_uuid: - ops.append(dict(op="replace", path="{0}/{1}/policy".format(path, match.index), value=physical_policy_uuid)) - match.details["policy"] = physical_policy_uuid + ops.append(dict(op="replace", path=physical_policy_path + "/policy", value=physical_policy_uuid)) + proposed_payload["policy"] = physical_policy_uuid if breakout_mode and match.details.get("breakoutMode") != breakout_mode: - ops.append(dict(op="replace", path="{0}/{1}/breakoutMode".format(path, match.index), value=breakout_mode)) - match.details["breakoutMode"] = breakout_mode + ops.append(dict(op="replace", path=physical_policy_path + "/breakoutMode", value=breakout_mode)) + proposed_payload["breakoutMode"] = breakout_mode if interfaces and interfaces != match.details.get("interfaces"): - ops.append(dict(op="replace", path="{0}/{1}/interfaces".format(path, match.index), value=interfaces)) - match.details["interfaces"] = interfaces + ops.append(dict(op="replace", path=physical_policy_path + "/interfaces", value=interfaces)) + proposed_payload["interfaces"] = interfaces # Node changes are not reflected on UI if interface_descriptions and match.details.get("interfaceDescriptions") != interface_descriptions: - updated_interface_descriptions = validate_interface_description(interface_descriptions) - ops.append(dict(op="replace", path="{0}/{1}/interfaceDescriptions".format(path, match.index), value=updated_interface_descriptions)) - match.details["interfaceDescriptions"] = updated_interface_descriptions + updated_interface_descriptions = format_interface_descriptions(interface_descriptions, "") + ops.append(dict(op="replace", path=physical_policy_path + "/interfaceDescriptions", value=updated_interface_descriptions)) + proposed_payload["interfaceDescriptions"] = updated_interface_descriptions elif interface_descriptions == [] and match.details.get("interfaceDescriptions"): - ops.append(dict(op="remove", path="{0}/{1}/interfaceDescriptions".format(path, match.index))) + ops.append(dict(op="remove", path=physical_policy_path + "/interfaceDescriptions")) - mso.sanitize(match.details) + mso.sanitize(proposed_payload, collate=True) else: if not nodes: mso.fail_json(msg=("ERROR: Missing 'nodes' for creating a Physical Interface.")) if not physical_interface_type: - mso.fail_json(msg=("ERROR: Missing physical interface type for creating a Physical Interface.")) + mso.fail_json(msg=("ERROR: Missing Physical Interface type for creating a Physical Interface.")) payload = { - "name": physical_interface, - "templateId": mso_template.template.get("templateId"), - "schemaId": mso_template.template.get("schemaId"), + "name": name, "nodes": nodes, "interfaces": interfaces, "policyGroupType": physical_interface_type, @@ -376,47 +374,28 @@ def main(): payload["breakoutMode"] = breakout_mode if interface_descriptions: - payload["interfaceDescriptions"] = validate_interface_description(interface_descriptions) - - ops.append(dict(op="add", path="{0}/-".format(path), value=copy.deepcopy(payload))) + payload["interfaceDescriptions"] = format_interface_descriptions(interface_descriptions, "") mso.sanitize(payload) - - mso.existing = mso.proposed + ops.append(dict(op="add", path="/fabricResourceTemplate/template/interfaceProfiles/-", value=mso.sent)) elif state == "absent": if match: - ops.append(dict(op="remove", path="{0}/{1}".format(path, match.index))) + ops.append(dict(op="remove", path=physical_policy_path)) if not module.check_mode and ops: response = mso.request(mso_template.template_path, method="PATCH", data=ops) - interface_policies = response.get("fabricResourceTemplate", {}).get("template", {}).get("interfaceProfiles", []) - match = mso_template.get_object_by_key_value_pairs( - object_description, - interface_policies, - [KVPair("uuid", physical_interface_uuid) if physical_interface_uuid else KVPair("name", physical_interface)], - ) + physical_interfaces = response.get("fabricResourceTemplate", {}).get("template", {}).get("interfaceProfiles", []) + match = mso_template.get_object_by_key_value_pairs(object_description, physical_interfaces, [KVPair("uuid", uuid) if uuid else KVPair("name", name)]) if match: - mso.existing = match.details + mso.existing = match.details # When the state is present else: - mso.existing = {} - elif module.check_mode and state != "query": + 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() -def validate_interface_description(interface_descriptions): - interface_descriptions = [ - { - "interfaceID": interface_description.get("interface_id"), - "description": interface_description.get("description"), - } - for interface_description in interface_descriptions - ] - - return interface_descriptions - - if __name__ == "__main__": main() diff --git a/tests/integration/targets/ndo_physical_interface/tasks/main.yml b/tests/integration/targets/ndo_physical_interface/tasks/main.yml index 49dfe1db..b99bf5d3 100644 --- a/tests/integration/targets/ndo_physical_interface/tasks/main.yml +++ b/tests/integration/targets/ndo_physical_interface/tasks/main.yml @@ -55,49 +55,48 @@ <<: *template_absent state: present - - name: Create interface policy group (physical policy) - cisco.mso.ndo_interface_setting: &add_interface_policy_group - <<: *mso_info - template: ansible_fabric_policy_template - interface_policy_group: ansible_interface_policy_group - interface_type: physical - state: present - register: add_interface_policy_group - - - name: Create another interface policy group - cisco.mso.ndo_interface_setting: - <<: *add_interface_policy_group - interface_policy_group: ansible_interface_policy_group_2 - register: add_interface_policy_group_2 + # - name: Create interface policy group (physical policy) + # cisco.mso.ndo_interface_setting: &add_interface_policy_group + # <<: *mso_info + # template: ansible_fabric_policy_template + # name: ansible_interface_policy_group + # interface_type: physical + # state: present + # register: add_interface_policy_group + + # - name: Create another interface policy group + # cisco.mso.ndo_interface_setting: + # <<: *add_interface_policy_group + # name: ansible_interface_policy_group_2 + # register: add_interface_policy_group_2 # CREATE - # Create physical interface of type physical with physical policy UUID - - name: Create physical interface of type 'physical' (check mode) + # Create Physical Interface of type physical with physical policy UUID + - name: Create Physical Interface of type 'physical' (check mode) cisco.mso.ndo_physical_interface: &add_physical_interface <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface + name: ansible_physical_interface nodes: 103 interfaces: ['1/3'] physical_interface_type: physical - # physical_policy_uuid: "164e7885-f4b8-419d-9a8f-aa77a0368c44" - physical_policy_uuid: {{ add_interface_policy_group.current.uuid }} + physical_policy_uuid: "8a5b5701-5cfc-4b27-9c73-4c42504b1999" # '{{ add_interface_policy_group.current.uuid }}' state: present check_mode: true register: cm_physical_interface - - name: Create physical interface of type 'physical' + - name: Create Physical Interface of type 'physical' cisco.mso.ndo_physical_interface: <<: *add_physical_interface register: nm_physical_interface - - name: Create physical interface of type 'physical' again + - name: Create Physical Interface of type 'physical' again cisco.mso.ndo_physical_interface: <<: *add_physical_interface register: nm_physical_interface_again - - name: Assert physical interface of type 'physical' is created + - name: Assert Physical Interface of type 'physical' is created ansible.builtin.assert: that: - cm_physical_interface is changed @@ -120,39 +119,39 @@ - nm_physical_interface_again.previous.uuid == nm_physical_interface.current.uuid - nm_physical_interface_again.current.uuid is defined - - name: Create physical interface of type 'physical' with physical policy - cisco.mso.ndo_physical_interface: - <<: *mso_info - template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface_with_policy - nodes: 109 - interfaces: ['1/9'] - physical_interface_type: physical - physical_policy: - template: ansible_fabric_policy_template - name: ansible_interface_policy_group - state: present - register: add_physical_interface_with_policy - - - name: Assert physical interface of type 'physical' is created with policy - ansible.builtin.assert: - that: - - add_physical_interface_with_policy is changed - - add_physical_interface_with_policy.previous == {} - - add_physical_interface_with_policy.current.name == "ansible_physical_interface_with_policy" - - add_physical_interface_with_policy.current.policyGroupType == "physical" - - add_physical_interface_with_policy.current.nodes | length == 1 - - add_physical_interface_with_policy.current.nodes[0] == "109" - - add_physical_interface_with_policy.current.interfaces == "1/9" - - add_physical_interface_with_policy.current.policy is defined - - add_physical_interface_with_policy.current.uuid is defined - - - name: Create physical interface of type 'breakout' (check mode) + # - name: Create Physical Interface of type 'physical' with physical policy + # cisco.mso.ndo_physical_interface: &add_physical_interface3 + # <<: *mso_info + # template: ansible_fabric_resource_policy_template + # name: ansible_physical_interface_with_policy + # nodes: 109 + # interfaces: ['1/9'] + # physical_interface_type: physical + # physical_policy: + # template: ansible_fabric_policy_template + # name: ansible_interface_policy_group + # state: present + # register: add_physical_interface_with_policy + + # - name: Assert Physical Interface of type 'physical' is created with policy + # ansible.builtin.assert: + # that: + # - add_physical_interface_with_policy is changed + # - add_physical_interface_with_policy.previous == {} + # - add_physical_interface_with_policy.current.name == "ansible_physical_interface_with_policy" + # - add_physical_interface_with_policy.current.policyGroupType == "physical" + # - add_physical_interface_with_policy.current.nodes | length == 1 + # - add_physical_interface_with_policy.current.nodes[0] == "109" + # - add_physical_interface_with_policy.current.interfaces == "1/9" + # - add_physical_interface_with_policy.current.policy is defined + # - add_physical_interface_with_policy.current.uuid is defined + + - name: Create Physical Interface of type 'breakout' (check mode) cisco.mso.ndo_physical_interface: &add_physical_interface_breakout <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface_2 - description: "Breakout type physical interface" + name: ansible_physical_interface_2 + description: "Breakout type Physical Interface" nodes: [101, 102] interfaces: - 1/1 @@ -166,19 +165,19 @@ check_mode: true register: cm_physical_interface_2 - - name: Create physical interface of type 'breakout' + - name: Create Physical Interface of type 'breakout' cisco.mso.ndo_physical_interface: <<: *add_physical_interface_breakout register: nm_physical_interface_2 - - name: Assert physical interface of type 'breakout' is created + - name: Assert Physical Interface of type 'breakout' is created ansible.builtin.assert: that: - cm_physical_interface_2 is changed - nm_physical_interface_2 is changed - cm_physical_interface_2.previous == nm_physical_interface_2.previous == {} - cm_physical_interface_2.current.name == nm_physical_interface_2.current.name == "ansible_physical_interface_2" - - cm_physical_interface_2.current.description == nm_physical_interface_2.current.description == "Breakout type physical interface" + - cm_physical_interface_2.current.description == nm_physical_interface_2.current.description == "Breakout type Physical Interface" - cm_physical_interface_2.current.policyGroupType == nm_physical_interface_2.current.policyGroupType == "breakout" - cm_physical_interface_2.current.nodes | length == nm_physical_interface_2.current.nodes | length == 2 - cm_physical_interface_2.current.nodes[0] == nm_physical_interface_2.current.nodes[0] == "101" @@ -191,16 +190,15 @@ - nm_physical_interface_2.current.uuid is defined # UPDATE - - name: Update physical interface of type 'physical' (check mode) + - name: Update Physical Interface of type 'physical' (check mode) cisco.mso.ndo_physical_interface: &update_physical_interface <<: *add_physical_interface - description: "Updated physical interface" + description: "Updated Physical Interface" nodes: 105 interfaces: - 1/5 - 2/3-5 - # physical_policy_uuid: "7513267f-f239-40cd-8c6f-3954734972df" - physical_policy_uuid: {{ add_interface_policy_group_2.current.uuid }} + physical_policy_uuid: "7513267f-f239-40cd-8c6f-3954734972df" # '{{ add_interface_policy_group_2.current.uuid }}' interface_descriptions: - interface_id: "2/5" description: "Updated interface description" @@ -210,17 +208,17 @@ check_mode: true register: cm_physical_interface_update - - name: Update physical interface of type 'physical' + - name: Update Physical Interface of type 'physical' cisco.mso.ndo_physical_interface: <<: *update_physical_interface register: nm_physical_interface_update - - name: Update physical interface of type 'physical' again + - name: Update Physical Interface of type 'physical' again cisco.mso.ndo_physical_interface: <<: *update_physical_interface register: nm_physical_interface_update_again - - name: Assert physical interface of type 'physical' is updated + - name: Assert Physical Interface of type 'physical' is updated ansible.builtin.assert: that: - cm_physical_interface_update is changed @@ -229,7 +227,7 @@ - cm_physical_interface_update.previous.name == nm_physical_interface_update.previous.name == "ansible_physical_interface" - cm_physical_interface_update.current.name == nm_physical_interface_update.current.name == "ansible_physical_interface" - cm_physical_interface_update.previous.description == nm_physical_interface_update.previous.description == "" - - cm_physical_interface_update.current.description == nm_physical_interface_update.current.description == "Updated physical interface" + - cm_physical_interface_update.current.description == nm_physical_interface_update.current.description == "Updated Physical Interface" - cm_physical_interface_update.previous.policyGroupType == nm_physical_interface_update.previous.policyGroupType == "physical" - cm_physical_interface_update.current.policyGroupType == nm_physical_interface_update.current.policyGroupType == "physical" - cm_physical_interface_update.previous.nodes | length == nm_physical_interface_update.previous.nodes | length == 1 @@ -250,7 +248,7 @@ - cm_physical_interface_update.current.uuid is defined - nm_physical_interface_update_again is not changed - nm_physical_interface_update_again.previous.name == nm_physical_interface_update_again.current.name == "ansible_physical_interface" - - nm_physical_interface_update_again.previous.description == nm_physical_interface_update_again.current.description == "Updated physical interface" + - nm_physical_interface_update_again.previous.description == nm_physical_interface_update_again.current.description == "Updated Physical Interface" - nm_physical_interface_update_again.previous.policyGroupType == nm_physical_interface_update_again.current.policyGroupType == "physical" - nm_physical_interface_update_again.previous.nodes | length == nm_physical_interface_update_again.current.nodes | length == 1 - nm_physical_interface_update_again.previous.interfaces == nm_physical_interface_update_again.current.interfaces == "1/5,2/3-5" @@ -259,15 +257,15 @@ - nm_physical_interface_update_again.previous.uuid == nm_physical_interface_update.current.uuid - nm_physical_interface_update_again.current.uuid is defined - - name: Update name physical interface of type 'breakout' with UUID and change breakout mode + - name: Update name Physical Interface of type 'breakout' with UUID and change breakout mode cisco.mso.ndo_physical_interface: &update_physical_interface_uuid <<: *add_physical_interface_breakout - physical_interface: "ansible_physical_interface_changed" - physical_interface_uuid: "{{ nm_physical_interface_2.current.uuid }}" + name: "ansible_physical_interface_changed" + uuid: "{{ nm_physical_interface_2.current.uuid }}" breakout_mode: 4x25G register: update_physical_interface_name - - name: Assert physical interface of type 'breakout' is updated breakout_mode and name with UUID + - name: Assert Physical Interface of type 'breakout' is updated breakout_mode and name with UUID ansible.builtin.assert: that: - update_physical_interface_name is changed @@ -275,7 +273,7 @@ - update_physical_interface_name.current.name == "ansible_physical_interface_changed" - update_physical_interface_name.previous.breakoutMode == "4x10G" - update_physical_interface_name.current.breakoutMode == "4x25G" - - update_physical_interface_name.previous.description == update_physical_interface_name.current.description == "Breakout type physical interface" + - update_physical_interface_name.previous.description == update_physical_interface_name.current.description == "Breakout type Physical Interface" - update_physical_interface_name.previous.policyGroupType == update_physical_interface_name.current.policyGroupType == "breakout" - update_physical_interface_name.previous.nodes | length == update_physical_interface_name.current.nodes | length == 2 - update_physical_interface_name.previous.interfaces == update_physical_interface_name.current.interfaces == "1/1,1/2-4" @@ -283,37 +281,37 @@ - update_physical_interface_name.current.uuid is defined # QUERY - - name: Query one physical interface with name + - name: Query one Physical Interface with name cisco.mso.ndo_physical_interface: <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface + name: ansible_physical_interface state: query register: query_physical_interface_with_name - - name: Query one physical interface with UUID + - name: Query one Physical Interface with UUID cisco.mso.ndo_physical_interface: <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface_uuid: '{{update_physical_interface_name.current.uuid}}' + uuid: '{{update_physical_interface_name.current.uuid}}' state: query register: query_physical_interface_with_uuid - name: Query all physical interfaces in ansible_fabric_resource_policy_template - cisco.mso.ndo_physical_interface: + cisco.mso.ndo_physical_interface: &query_all_physical_interface <<: *mso_info template: ansible_fabric_resource_policy_template state: query register: query_all_physical_interfaces - - name: Assert physical interface of type 'physical' is queried + - name: Assert Physical Interface of type 'physical' is queried ansible.builtin.assert: that: - query_physical_interface_with_name is not changed - query_physical_interface_with_uuid is not changed - query_all_physical_interfaces is not changed - query_physical_interface_with_name.current.name == "ansible_physical_interface" - - query_physical_interface_with_name.current.description == "Updated physical interface" + - query_physical_interface_with_name.current.description == "Updated Physical Interface" - query_physical_interface_with_name.current.policyGroupType == "physical" - query_physical_interface_with_name.current.nodes | length == 1 - query_physical_interface_with_name.current.nodes[0] == "105" @@ -323,7 +321,7 @@ - query_physical_interface_with_name.current.interfaceDescriptions | length == 2 - query_physical_interface_with_uuid.current.name == "ansible_physical_interface_changed" - query_physical_interface_with_uuid.current.breakoutMode == "4x25G" - - query_physical_interface_with_uuid.current.description == "Breakout type physical interface" + - query_physical_interface_with_uuid.current.description == "Breakout type Physical Interface" - query_physical_interface_with_uuid.current.policyGroupType == "breakout" - query_physical_interface_with_uuid.current.nodes | length == 2 - query_physical_interface_with_uuid.current.nodes[0] == "101" @@ -333,16 +331,16 @@ - query_physical_interface_with_uuid.current.interfaceDescriptions[0].interfaceID == "1/1" - query_physical_interface_with_uuid.current.interfaceDescriptions[0].description == "First interface" - query_physical_interface_with_uuid.current.uuid is defined - - query_all_physical_interfaces.current | length == 3 + # - query_all_physical_interfaces.current | length == 3 # Remove interface descriptions - - name: Update name physical interface of type 'breakout' by removing interface interface_descriptions + - name: Update name Physical Interface of type 'breakout' by removing interface interface_descriptions cisco.mso.ndo_physical_interface: <<: *update_physical_interface_uuid interface_descriptions: [] register: rm_physical_interface_name_interface_descriptions - - name: Assert physical interface of type 'breakout' is updated by removing interface interface_descriptions + - name: Assert Physical Interface of type 'breakout' is updated by removing interface interface_descriptions ansible.builtin.assert: that: - rm_physical_interface_name_interface_descriptions is changed @@ -358,74 +356,74 @@ # Errors # Create errors - - name: Create physical interface without nodes + - name: Create Physical Interface without nodes cisco.mso.ndo_physical_interface: <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface_invalid + name: ansible_physical_interface_invalid interfaces: ['1/1'] state: present ignore_errors: true register: create_physical_interface_without_nodes - - name: Assert creating physical interface with invalid attributes + - name: Assert creating Physical Interface with invalid attributes ansible.builtin.assert: that: - create_physical_interface_without_nodes is failed - create_physical_interface_without_nodes.msg == "ERROR{{':'}} Missing 'nodes' for creating a Physical Interface." - - name: Create physical interface without_interface_type + - name: Create Physical Interface without_interface_type cisco.mso.ndo_physical_interface: <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface_invalid + name: ansible_physical_interface_invalid nodes: 103 interfaces: ['1/1'] state: present ignore_errors: true register: create_physical_interface_without_interface_type - - name: Assert creating physical interface with invalid attributes + - name: Assert creating Physical Interface with invalid attributes ansible.builtin.assert: that: - create_physical_interface_without_interface_type is failed - - create_physical_interface_without_interface_type.msg == "ERROR{{':'}} Missing physical interface type for creating a Physical Interface." + - create_physical_interface_without_interface_type.msg == "ERROR{{':'}} Missing Physical Interface type for creating a Physical Interface." # Update errors - - name: Update interfaces without updating the physical interface type + - name: Update interfaces without updating the Physical Interface type cisco.mso.ndo_physical_interface: <<: *update_physical_interface physical_interface_type: breakout ignore_errors: true register: create_physical_interface_invalid_type - - name: Assert updating interfaces without updating the physical interface type + - name: Assert updating interfaces without updating the Physical Interface type ansible.builtin.assert: that: - create_physical_interface_invalid_type is failed - create_physical_interface_invalid_type.msg == "ERROR{{':'}} Physical Interface type cannot be changed." # DELETE - - name: Delete physical interface of type 'physical' (check mode) + - name: Delete Physical Interface of type 'physical' (check mode) cisco.mso.ndo_physical_interface: &delete_physical_interface <<: *mso_info template: ansible_fabric_resource_policy_template - physical_interface: ansible_physical_interface + name: ansible_physical_interface state: absent check_mode: true register: cm_delete_physical_interface - - name: Delete physical interface of type 'physical' + - name: Delete Physical Interface of type 'physical' cisco.mso.ndo_physical_interface: <<: *delete_physical_interface register: nm_delete_physical_interface - - name: Delete physical interface of type 'physical' again + - name: Delete Physical Interface of type 'physical' again cisco.mso.ndo_physical_interface: <<: *delete_physical_interface register: nm_delete_physical_interface_again - - name: Assert physical interface of type 'physical' is deleted + - name: Assert Physical Interface of type 'physical' is deleted ansible.builtin.assert: that: - cm_delete_physical_interface is changed @@ -439,6 +437,60 @@ - nm_delete_physical_interface_again.previous == nm_delete_physical_interface_again.current == {} - nm_delete_physical_interface_again.current.uuid is not defined + - name: Query all tests + cisco.mso.ndo_physical_interface: + <<: *query_all_physical_interface + + - name: Delete Physical Interface of type 'breakout' with UUID + cisco.mso.ndo_physical_interface: + <<: *mso_info + template: ansible_fabric_resource_policy_template + uuid: "{{ rm_physical_interface_name_interface_descriptions.current.uuid }}" + state: absent + register: delete_physical_interface_uuid + + - name: Assert Physical Interface of type 'breakout' is deleted with UUID + ansible.builtin.assert: + that: + - delete_physical_interface_uuid is changed + - delete_physical_interface_uuid.previous.name == "ansible_physical_interface_changed" + - delete_physical_interface_uuid.current == {} + - delete_physical_interface_uuid.previous.policyGroupType == "breakout" + - delete_physical_interface_uuid.previous.uuid is defined + + # Errors and no policies found + # - name: Delete Physical Interface of type 'physical' when all are deleted + # cisco.mso.ndo_physical_interface: + # <<: *add_physical_interface3 + # state: absent + # register: nm_delete_last_physical_interface + + - name: Query all Physical Interface in the template when all are deleted + cisco.mso.ndo_physical_interface: + <<: *query_all_physical_interface + register: query_all_none + + - name: Update Physical Interface with non-existing UUID + cisco.mso.ndo_physical_interface: + <<: *mso_info + template: ansible_fabric_resource_policy_template + uuid: non-existing-uuid + state: present + ignore_errors: true + register: update_non_existing_uuid + + - name: Assert no Physical Interface found + assert: + that: + # - nm_delete_last_physical_interface is changed + # - nm_delete_last_physical_interface.previous.name == "ansible_physical_interface_with_policy" + # - nm_delete_last_physical_interface.previous.policyGroupType == "physical" + # - nm_delete_last_physical_interface.current == {} + - query_all_none is not changed + - query_all_none.current == {} + - update_non_existing_uuid is failed + - update_non_existing_uuid.msg == "Physical Interface Profile with the UUID{{":"}} 'non-existing-uuid' not found" + # CLEANUP TEMPLATE - name: Ensure fabric resource policy template do not exist