diff --git a/docs/cisco.dcnm.dcnm_interface_module.rst b/docs/cisco.dcnm.dcnm_interface_module.rst index 516375426..02282465f 100644 --- a/docs/cisco.dcnm.dcnm_interface_module.rst +++ b/docs/cisco.dcnm.dcnm_interface_module.rst @@ -804,7 +804,7 @@ Parameters Default:
""
-
IPV4 address of the interface.
+
IPv4 address of the interface.
@@ -822,7 +822,7 @@ Parameters Default:
""
-
IPV6 address of the interface.
+
IPv6 address of the interface.
@@ -840,10 +840,16 @@ Parameters -
Interface mode
+
There are several modes for loopback interfaces.
+
Mode 'lo' is used to create, modify and delete non fabric loopback interfaces using policy 'int_loopback'.
+
Mode 'fabric' is used to modify loopbacks created when the fabric is first created using policy 'int_fabric_loopback_11_1'
+
Mode 'mpls' is used to modify loopbacks created when the fabric is first created using policy 'int_mpls_loopback'
+
Mode 'fabric' and 'mpls' interfaces can be modified but not created or deleted.
@@ -864,6 +870,24 @@ Parameters
Route tag associated with the interface IP.
+ + + + +
+ secondary_ipv4_addr + +
+ string +
+ + + Default:
""
+ + +
Secondary IP address of the nve interface loopback
+ + @@ -2589,6 +2613,26 @@ Examples - no shutdown description: "loopback interface 100 configuration - replaced" + ## Loopback Interfaces Created During Fabric Creation + - name: Mange Fabric loopback interfaces + cisco.dcnm.dcnm_interface: + fabric: mmudigon-fabric + state: merged + config: + - name: lo1 # This is usually lo0 or lo1 created during fabric creation + type: lo + switch: + - "192.172.1.1" # provide the switch where to deploy the config + deploy: true # choose from [true, false] + profile: + admin_state: false # choose from [true, false] + mode: fabric # This must be set to 'fabric' for fabric loopback interfaces + secondary_ipv4_addr: 172.16.5.1 # secondary ipv4 address for loopback interface + route_tag: "100" # Routing Tag for the interface + cmds: # Freeform config + - no shutdown + description: "Fabric interface managed by Ansible" + # To delete or reset all interfaces on all switches in the fabric - name: Delete loopback interfaces cisco.dcnm.dcnm_interface: diff --git a/plugins/modules/dcnm_interface.py b/plugins/modules/dcnm_interface.py index 0ce3108fa..88bdca107 100644 --- a/plugins/modules/dcnm_interface.py +++ b/plugins/modules/dcnm_interface.py @@ -345,9 +345,16 @@ - Object profile which must be included for loopback interface configurations. suboptions: mode: + choices: ['lo', 'fabric', 'mpls'] description: - - Interface mode - choices: ['lo'] + - There are several modes for loopback interfaces. + - Mode 'lo' is used to create, modify and delete non fabric loopback + interfaces using policy 'int_loopback'. + - Mode 'fabric' is used to modify loopbacks created when the fabric is first + created using policy 'int_fabric_loopback_11_1' + - Mode 'mpls' is used to modify loopbacks created when the fabric is first + created using policy 'int_mpls_loopback' + - Mode 'fabric' and 'mpls' interfaces can be modified but not created or deleted. type: str required: true int_vrf: @@ -357,12 +364,17 @@ default: default ipv4_addr: description: - - IPV4 address of the interface. + - IPv4 address of the interface. + type: str + default: "" + secondary_ipv4_addr: + description: + - Secondary IP address of the nve interface loopback type: str default: "" ipv6_addr: description: - - IPV6 address of the interface. + - IPv6 address of the interface. type: str default: "" route_tag: @@ -848,6 +860,26 @@ - no shutdown description: "loopback interface 100 configuration - replaced" +## Loopback Interfaces Created During Fabric Creation +- name: Mange Fabric loopback interfaces + cisco.dcnm.dcnm_interface: + fabric: mmudigon-fabric + state: merged + config: + - name: lo1 # This is usually lo0 or lo1 created during fabric creation + type: lo + switch: + - "192.172.1.1" # provide the switch where to deploy the config + deploy: true # choose from [true, false] + profile: + admin_state: false # choose from [true, false] + mode: fabric # This must be set to 'fabric' for fabric loopback interfaces + secondary_ipv4_addr: 172.16.5.1 # secondary ipv4 address for loopback interface + route_tag: "100" # Routing Tag for the interface + cmds: # Freeform config + - no shutdown + description: "Fabric interface managed by Ansible" + # To delete or reset all interfaces on all switches in the fabric - name: Delete loopback interfaces cisco.dcnm.dcnm_interface: @@ -1682,6 +1714,7 @@ def __init__(self, module): "serialNumber": "sno", "fabricName": "fabric", "IP": "ipv4_addr", + "SECONDARY_IP": "secondary_ipv4_addr", "INTF_VRF": "int_vrf", "V6IP": "ipv6_addr", "IPv6": "ipv6_addr", @@ -1716,6 +1749,8 @@ def __init__(self, module): "PEER2_PO_CONF": "peer2_cmds", "PEER1_ACCESS_VLAN": "peer1_access_vlan", "PEER2_ACCESS_VLAN": "peer2_access_vlan", + "DCI_ROUTING_PROTO": "dci_routing_proto", + "DCI_ROUTING_TAG": "dci_routing_tag", } # New Interfaces @@ -1746,6 +1781,8 @@ def __init__(self, module): "pc_l3": "int_l3_port_channel", "sub_int_subint": "int_subif", "lo_lo": "int_loopback", + "lo_fabric": "int_fabric_loopback_11_1", + "lo_mpls": "int_mpls_loopback", "eth_trunk": "int_trunk_host", "eth_access": "int_access_host", "eth_routed": "int_routed_host", @@ -2124,6 +2161,7 @@ def dcnm_intf_validate_loopback_interface_input(self, cfg): lo_prof_spec = dict( mode=dict(required=True, type="str"), ipv4_addr=dict(required=True, type="ipv4"), + secondary_ipv4_addr=dict(type="ipv4", default=""), int_vrf=dict(type="str", default="default"), ipv6_addr=dict(type="ipv6", default=""), route_tag=dict(type="str", default=""), @@ -2395,17 +2433,17 @@ def dcnm_intf_validate_input(self): cfg.append(citem) if self.module.params["state"] == "deleted": - # config for delete state is different for all interafces. It may not have the profile + # config for delete state is different for all interfaces. It may not have the profile # construct. So validate deleted state differently self.dcnm_intf_validate_delete_state_input(cfg) elif self.module.params["state"] == "query": - # config for query state is different for all interafces. It may not have the profile + # config for query state is different for all interfaces. It may not have the profile # construct. So validate query state differently self.dcnm_intf_validate_query_state_input(cfg) elif (self.module.params["state"] == "overridden") and not ( any("profile" in key for key in item) ): - # config for overridden state is different for all interafces. It may not have the profile + # config for overridden state is different for all interfaces. It may not have the profile # construct. So validate overridden state differently self.dcnm_intf_validate_overridden_state_input(cfg) else: @@ -2719,25 +2757,15 @@ def dcnm_intf_get_sub_intf_payload(self, delem, intf, profile): def dcnm_intf_get_loopback_payload(self, delem, intf, profile): - # Extract port id from the given name, which is of the form 'po300' - + # Properties common for all loopback interface modes ifname, port_id = self.dcnm_intf_get_if_name( delem["name"], delem["type"] ) intf["interfaces"][0].update({"ifName": ifname}) - intf["interfaces"][0]["nvPairs"]["INTF_VRF"] = delem[profile][ - "int_vrf" - ] intf["interfaces"][0]["nvPairs"]["IP"] = str( delem[profile]["ipv4_addr"] ) - intf["interfaces"][0]["nvPairs"]["V6IP"] = str( - delem[profile]["ipv6_addr"] - ) - intf["interfaces"][0]["nvPairs"]["ROUTE_MAP_TAG"] = delem[profile][ - "route_tag" - ] intf["interfaces"][0]["nvPairs"]["INTF_NAME"] = ifname intf["interfaces"][0]["nvPairs"]["DESC"] = delem[profile][ "description" @@ -2752,6 +2780,42 @@ def dcnm_intf_get_loopback_payload(self, delem, intf, profile): delem[profile]["admin_state"] ).lower() + # Properties for mode 'lo' Loopback Interfaces + if delem[profile]["mode"] == "lo": + + intf["interfaces"][0]["nvPairs"]["INTF_VRF"] = delem[profile][ + "int_vrf" + ] + intf["interfaces"][0]["nvPairs"]["V6IP"] = str( + delem[profile]["ipv6_addr"] + ) + intf["interfaces"][0]["nvPairs"]["ROUTE_MAP_TAG"] = delem[profile][ + "route_tag" + ] + + # Properties for mode 'fabric' Loopback Interfaces + if delem[profile]["mode"] == "fabric": + + intf["interfaces"][0]["nvPairs"]["SECONDARY_IP"] = delem[profile][ + "secondary_ipv4_addr" + ] + intf["interfaces"][0]["nvPairs"]["V6IP"] = str( + delem[profile]["ipv6_addr"] + ) + intf["interfaces"][0]["nvPairs"]["ROUTE_MAP_TAG"] = delem[profile][ + "route_tag" + ] + + # Properties for mode 'mpls' Loopback Interfaces + if delem[profile]["mode"] == "mpls": + + # These properties are read_only properties and are not exposed as + # properties that can be modified. They will be updated from the + # self.have dictionary to reflect the actual values later in the + # code workflow that walks the want values and compares to have values. + intf["interfaces"][0]["nvPairs"]["DCI_ROUTING_PROTO"] = "PLACE_HOLDER" + intf["interfaces"][0]["nvPairs"]["DCI_ROUTING_TAG"] = "PLACE_HOLDER" + def dcnm_intf_get_eth_payload(self, delem, intf, profile): # Extract port id from the given name, which is of the form 'po300' @@ -3366,6 +3430,11 @@ def dcnm_intf_compare_elements( if t_e1 != t_e2: if (state == "replaced") or (state == "overridden"): + # Special handling is required for mode 'mpls' loopback interfaces. + # They will contain either of the following two read_only properties. + if k in ['DCI_ROUTING_PROTO', 'DCI_ROUTING_TAG']: + return "copy_and_add" + return "add" elif state == "merged": # If the key is included in config, then use the value from want. @@ -3469,8 +3538,8 @@ def dcnm_intf_compare_want_and_have(self, state): # First check if the policies are same for want and have. If they are different, we cannot compare # the profiles because each profile will have different elements. As per PRD, if policies are different - # we should not merge the information. For now we will assume we will oerwrite the same. Don't compare - # rest of the structure. Overwrite with waht ever is in want + # we should not merge the information. For now we will assume we will overwrite the same. Don't compare + # rest of the structure. Overwrite with whatever is in want if want["policy"] != d["policy"]: action = "update" diff --git a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_fabric.yaml b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_fabric.yaml new file mode 100644 index 000000000..f66c9a8f7 --- /dev/null +++ b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_fabric.yaml @@ -0,0 +1,219 @@ +############################################## +## SETUP ## +############################################## + +# This test file specfically validates fabric loopback +# interfaces that are created at fabric creation time. +# Typically they are loopback0 or loopback1 and use +# the ndfc profile 'int_fabric_loopback_11_1' + +- name: Remove local log file + local_action: command rm -f dcnm_intf.log + +- name: Put the fabric to default state + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: overridden + register: result + +- assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + +- name: Save Data For Loopback0 + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo0 + switch: + - "{{ ansible_switch2 }}" + register: lpk0_data + +- name: Save Data For Loopback1 + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo1 + switch: + - "{{ ansible_switch2 }}" + register: lpk1_data + +- debug: msg="Loopback 0 Data - {{ lpk0_data.response[0]['interfaces'][0]['nvPairs'] }}" +- debug: msg="Loopback 1 Data - {{ lpk1_data.response[0]['interfaces'][0]['nvPairs'] }}" + +- block: + +############################################## +## MERGE ## +############################################## + + - name: Modify fabric loopback interfaces + cisco.dcnm.dcnm_interface: &lo_merge + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - name: lo0 + type: lo + switch: + - "{{ ansible_switch2 }}" + deploy: true + profile: + admin_state: true + mode: fabric # This mode is needed to manage fabric lpbk interfaces + ipv4_addr: 192.168.2.1 # ipv4 address for the loopback interface + ipv6_addr: fd08::0201 # ipV6 address for the loopback interface + route_tag: "55" # Routing Tag for the interface + cmds: # Freeform config + - no shutdown + description: "Fabric Lpk0 Configured By Ansible" + + - name: lo1 + type: lo + switch: + - "{{ ansible_switch2 }}" + deploy: true + profile: + admin_state: true + mode: fabric # This mode is needed to manage fabric lpbk interfaces + ipv4_addr: 192.168.5.1 # ipv4 address for the loopback interface + secondary_ipv4_addr: 172.16.5.1 # secondary ipv4 address for loopback interface + ipv6_addr: fd08::0301 # ipV6 address for the loopback interface + route_tag: "77" # Routing Tag for the interface + cmds: # Freeform config + - no shutdown + description: "Fabric Lpk1 Configured By Ansible" + register: result + + - assert: + that: + - 'result.changed == true' + - '(result["diff"][0]["merged"] | length) == 2' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 0' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 2' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Modify fabric loopback interfaces - Idempotence + cisco.dcnm.dcnm_interface: *lo_merge + register: result + + - assert: + that: + - 'result.changed == false' + - '(result["diff"][0]["merged"] | length) == 0' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 0' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 0' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Query and save new data for loopback0 + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo0 + switch: + - "{{ ansible_switch2 }}" + register: lpk0_data_new + + - name: Query and save new data for loopback1 + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo1 + switch: + - "{{ ansible_switch2 }}" + register: lpk1_data_new + + - assert: + that: + - 'lpk0_data_new.response[0]["interfaces"][0]["nvPairs"]["IP"] == "192.168.2.1"' + - 'lpk0_data_new.response[0]["interfaces"][0]["nvPairs"]["V6IP"] == "fd08::0201"' + - 'lpk0_data_new.response[0]["interfaces"][0]["nvPairs"]["ROUTE_MAP_TAG"] == "55"' + - 'lpk0_data_new.response[0]["interfaces"][0]["nvPairs"]["DESC"] == "Fabric Lpk0 Configured By Ansible"' + - 'lpk1_data_new.response[0]["interfaces"][0]["nvPairs"]["IP"] == "192.168.5.1"' + - 'lpk1_data_new.response[0]["interfaces"][0]["nvPairs"]["SECONDARY_IP"] == "172.16.5.1"' + - 'lpk1_data_new.response[0]["interfaces"][0]["nvPairs"]["V6IP"] == "fd08::0301"' + - 'lpk1_data_new.response[0]["interfaces"][0]["nvPairs"]["ROUTE_MAP_TAG"] == "77"' + - 'lpk1_data_new.response[0]["interfaces"][0]["nvPairs"]["DESC"] == "Fabric Lpk1 Configured By Ansible"' + + # Only execute this test if loopback0 and 1 are fabric loopbacks + when: + - lpk0_data.response[0]['policy'] == 'int_fabric_loopback_11_1' + - lpk1_data.response[0]['policy'] == 'int_fabric_loopback_11_1' + +############################################## +## CLEANUP ## +############################################## + + always: + + - name: Set Loopback0 and Loopback1 back to inital state + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - name: lo0 + type: lo + switch: + - "{{ ansible_switch2 }}" + deploy: true + profile: + admin_state: true + mode: fabric + ipv4_addr: "{{ lpk0_data.response[0]['interfaces'][0]['nvPairs']['IP'] }}" + ipv6_addr: "{{ lpk0_data.response[0]['interfaces'][0]['nvPairs']['V6IP'] }}" + route_tag: "{{ lpk0_data.response[0]['interfaces'][0]['nvPairs']['ROUTE_MAP_TAG'] }}" + description: "{{ lpk0_data.response[0]['interfaces'][0]['nvPairs']['DESC'] }}" + + - name: lo1 + type: lo + switch: + - "{{ ansible_switch2 }}" + deploy: true + profile: + admin_state: true + mode: fabric + ipv4_addr: "{{ lpk1_data.response[0]['interfaces'][0]['nvPairs']['IP'] }}" + secondary_ipv4_addr: "{{ lpk1_data.response[0]['interfaces'][0]['nvPairs']['SECONDARY_IP'] }}" + ipv6_addr: "{{ lpk1_data.response[0]['interfaces'][0]['nvPairs']['V6IP'] }}" + route_tag: "{{ lpk1_data.response[0]['interfaces'][0]['nvPairs']['ROUTE_MAP_TAG'] }}" + description: "{{ lpk1_data.response[0]['interfaces'][0]['nvPairs']['DESC'] }}" + when: + - lpk0_data.response[0]['policy'] == 'int_fabric_loopback_11_1' + - lpk1_data.response[0]['policy'] == 'int_fabric_loopback_11_1' + + - name: Put fabric to default state + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: overridden # only choose form [merged, replaced, deleted, overridden, query] + register: result + when: IT_CONTEXT is not defined + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + when: IT_CONTEXT is not defined diff --git a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_mpls.yaml b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_mpls.yaml new file mode 100644 index 000000000..bff211e6b --- /dev/null +++ b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_lo_mpls.yaml @@ -0,0 +1,232 @@ +############################################## +## SETUP ## +############################################## + +# This test file specfically validates fabric loopback +# interfaces that are created at fabric creation time +# for VXLAN-EVPN to SR-MPLS and MPLS LDP interconnection + +# By default they are loopback101 as defined in the fabric +# settings and use the ndfc profile 'int_mpls_loopback' + +- name: Remove local log file + local_action: command rm -f dcnm_intf.log + +- name: Save Data For Loopback101 + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo101 + switch: + - "{{ ansible_switch1 }}" + register: lpk101_data + +- name: Set Test Control Flag + ansible.builtin.set_fact: + run_test: True + +- name: Test will not be run since Loopback101 does not appear to exist + ansible.builtin.set_fact: + run_test: False + when: lpk101_data.response == [] + +- name: Access Policy Data If Loopack101 Data Is Available + ansible.builtin.set_fact: + loopback_policy: "{{ lpk101_data.response[0]['policy'] }}" + when: lpk101_data.response != [] + +- name: Test will not be run since Loopback101 is not an MPLS Fabric Loopback + ansible.builtin.set_fact: + run_test: False + when: (loopback_policy is defined) and (loopback_policy != 'int_mpls_loopback') + +- debug: msg="Loopback 101 Data - {{ lpk101_data.response[0]['interfaces'][0]['nvPairs'] }}" + when: run_test + +- block: + +############################################## +## MERGE ## +############################################## + + - name: Modify mpls fabric loopback interface using merge + cisco.dcnm.dcnm_interface: &lo_merge + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: merged + config: + - name: lo101 + type: lo + switch: + - "{{ ansible_switch1 }}" + deploy: true + profile: + admin_state: true + mode: mpls # This mode is needed to manage mpls fabric lpbk interfaces + ipv4_addr: 192.168.55.2 # ipv4 address for the loopback interface + cmds: # Freeform config + - no shutdown + description: "Fabric Lpk101 Configured By Ansible" + register: result + + - assert: + that: + - 'result.changed == true' + - '(result["diff"][0]["merged"] | length) == 1' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 0' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 1' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Verify interface properties are modified using merge + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo101 + switch: + - "{{ ansible_switch1 }}" + register: lpk101_data_new + until: + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["IP"] == "192.168.55.2"' + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["DESC"] == "Fabric Lpk101 Configured By Ansible"' + retries: 5 + delay: 2 + + - name: Modify mpls fabric loopback interface using merge - Idempotence + cisco.dcnm.dcnm_interface: *lo_merge + register: result + + - assert: + that: + - 'result.changed == false' + - '(result["diff"][0]["merged"] | length) == 0' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 0' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 0' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Modify mpls fabric loopback interface using replace + cisco.dcnm.dcnm_interface: &lo_replace + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: replaced + config: + - name: lo101 + type: lo + switch: + - "{{ ansible_switch1 }}" + deploy: true + profile: + admin_state: true + mode: mpls # This mode is needed to manage mpls fabric lpbk interfaces + ipv4_addr: 192.168.88.55 # ipv4 address for the loopback interface + cmds: # Freeform config + - no shutdown + description: "Fabric Lpk101 Replaced By Ansible" + register: result + + - assert: + that: + - 'result.changed == true' + - '(result["diff"][0]["merged"] | length) == 0' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 1' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 1' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Modify mpls fabric loopback interface using replace - Idempotence + cisco.dcnm.dcnm_interface: *lo_replace + register: result + + - assert: + that: + - 'result.changed == false' + - '(result["diff"][0]["merged"] | length) == 0' + - '(result["diff"][0]["deleted"] | length) == 0' + - '(result["diff"][0]["replaced"] | length) == 0' + - '(result["diff"][0]["overridden"] | length) == 0' + - '(result["diff"][0]["deploy"] | length) == 0' + + - assert: + that: + - 'item["RETURN_CODE"] == 200' + loop: '{{ result.response }}' + + - name: Verify interface properties are modified using replace + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo101 + switch: + - "{{ ansible_switch1 }}" + register: lpk101_data_new + until: + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["IP"] == "192.168.88.55"' + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["DESC"] == "Fabric Lpk101 Replaced By Ansible"' + retries: 5 + delay: 2 + + # Only execute this test if loopback101 is a fabric mpls loopback + when: run_test + +############################################## +## CLEANUP ## +############################################## + + always: + + - name: Set Loopback101 back to inital state + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: overridden + config: + - name: lo101 + type: lo + switch: + - "{{ ansible_switch1 }}" + deploy: true + profile: + admin_state: true + mode: mpls + ipv4_addr: "{{ lpk101_data.response[0]['interfaces'][0]['nvPairs']['IP'] }}" + description: "{{ lpk101_data.response[0]['interfaces'][0]['nvPairs']['DESC'] }}" + when: run_test + + - name: Verify interface properties are restored to original values using overridden + cisco.dcnm.dcnm_interface: + check_deploy: True + fabric: "{{ ansible_it_fabric }}" + state: query + config: + - name: lo101 + switch: + - "{{ ansible_switch1 }}" + register: lpk101_data_new + until: + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["IP"] == lpk101_data.response[0]["interfaces"][0]["nvPairs"]["IP"]' + - 'lpk101_data_new.response[0]["interfaces"][0]["nvPairs"]["DESC"] == lpk101_data.response[0]["interfaces"][0]["nvPairs"]["DESC"]' + retries: 5 + delay: 2 + when: run_test \ No newline at end of file