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
Choices:
- lo
+ - fabric
+ - mpls
|
- 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