Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
1. module_utils/network/dcnm.py

Add two new methods which are duplicate functionality to get_ip_sn_fabric_dict()

get_ip_fabric_dict()
get_sn_fabric_dict()

get_ip_sn_fabric_dict() was not touched.

The reason for the new defs is because patch (in test_dcnm_vrf.py setUp() did not like patching to a def that returns more than one value.  But another reason is that it's cleaner for these utility defs to be as simple as possible.

2. test_dcnm_vrf.py

- Add the mock for sn_fab

- Modify load_fixtures() for all test cases that required having sn_fab dict mocked.

- Define two new vars for fabric details (for a future commit)
    -  fabric_details_mfd
    - fabric_details_vxlan

3. dcnm_vrf.json

Add the following objects (fabric_details_* for a future commit)

- mock_sn_fab
- fabric_details_mfd
- fabric_details_vxlan
  • Loading branch information
allenrobel committed Jan 18, 2025
1 parent 9e49fc9 commit f6e6712
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 17 deletions.
41 changes: 41 additions & 0 deletions plugins/module_utils/network/dcnm/dcnm.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,47 @@ def get_ip_sn_fabric_dict(inventory_data):

return ip_fab, sn_fab

def get_ip_fabric_dict(inventory_data):
"""
Maps the switch IP Address/Serial No. in the multisite inventory
data to respective member site fabric name to which it was actually added.
Parameters:
inventory_data: Fabric inventory data
Returns:
dict: Switch ip - fabric_name mapping
dict: Switch serial_no - fabric_name mapping
"""
ip_fab = {}

for device_key in inventory_data.keys():
ip = inventory_data[device_key].get("ipAddress")
fabric_name = inventory_data[device_key].get("fabricName")
ip_fab.update({ip: fabric_name})

return ip_fab

def get_sn_fabric_dict(inventory_data):
"""
Maps the switch IP Address/Serial No. in the multisite inventory
data to respective member site fabric name to which it was actually added.
Parameters:
inventory_data: Fabric inventory data
Returns:
dict: Switch ip - fabric_name mapping
dict: Switch serial_no - fabric_name mapping
"""
sn_fab = {}

for device_key in inventory_data.keys():
sn = inventory_data[device_key].get("serialNumber")
fabric_name = inventory_data[device_key].get("fabricName")
sn_fab.update({sn: fabric_name})

return sn_fab

# sw_elem can be ip_addr, hostname, dns name or serial number. If the given
# sw_elem is ip_addr, then it is returned as is. If DNS or hostname then a DNS
Expand Down
92 changes: 82 additions & 10 deletions plugins/modules/dcnm_vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,9 @@
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.dcnm.plugins.module_utils.network.dcnm.dcnm import (
dcnm_get_ip_addr_info, dcnm_get_url, dcnm_send, dcnm_version_supported,
get_fabric_details, get_fabric_inventory_details, get_ip_sn_dict,
get_ip_sn_fabric_dict, validate_list_of_dicts)
get_fabric_details, get_fabric_inventory_details, get_ip_fabric_dict,
get_ip_sn_dict, get_ip_sn_fabric_dict, get_sn_fabric_dict,
validate_list_of_dicts)

from ..module_utils.common.log_v2 import Log

Expand Down Expand Up @@ -661,7 +662,9 @@ def __init__(self, module):
self.sn_ip = {value: key for (key, value) in self.ip_sn.items()}
self.fabric_data = get_fabric_details(self.module, self.fabric)
self.fabric_type = self.fabric_data.get("fabricType")
self.ip_fab, self.sn_fab = get_ip_sn_fabric_dict(self.inventory_data)
# self.ip_fab, self.sn_fab = get_ip_sn_fabric_dict(self.inventory_data)
self.ip_fab = get_ip_fabric_dict(self.inventory_data)
self.sn_fab = get_sn_fabric_dict(self.inventory_data)
if self.dcnm_version > 12:
self.paths = dcnm_vrf_paths[12]
else:
Expand Down Expand Up @@ -3049,6 +3052,80 @@ def send_to_controller(self, action, verb, path, payload, is_rollback=False):
self.log.debug(msg)
self.failure(resp)

def update_vrf_attach_fabric_name(self, vrf_attach: dict) -> dict:
"""
# Summary
For multisite fabrics, replace `vrf_attach.fabric` with the name of
the child fabric returned by `self.sn_fab[vrf_attach.serialNumber]`
## params
- `vrf_attach`
A `vrf_attach` dictionary containing the following keys:
- `fabric` : fabric name
- `serialNumber` : switch serial number
"""
method_name = inspect.stack()[0][3]
caller = inspect.stack()[1][3]

msg = "ENTERED. "
msg += f"caller: {caller}. "
self.log.debug(msg)

msg = "Received vrf_attach: "
msg += f"{json.dumps(vrf_attach, indent=4, sort_keys=True)}"
self.log.debug(msg)

if self.fabric_type != "MFD":
msg = "Early return. "
msg += f"FABRIC_TYPE {self.fabric_type} is not MFD. "
msg += "Returning unmodified vrf_attach."
self.log.debug(msg)
return copy.deepcopy(vrf_attach)

parent_fabric_name = vrf_attach.get("fabric")

msg = f"fabric_type: {self.fabric_type}, "
msg += "replacing parent_fabric_name "
msg += f"({parent_fabric_name}) "
msg += "with child fabric name."
self.log.debug(msg)

serial_number = vrf_attach.get("serialNumber")

if serial_number is None:
msg = f"{self.class_name}.{method_name}: "
msg += f"caller: {caller}. "
msg += "Unable to parse serial_number from vrf_attach. "
msg += f"{json.dumps(vrf_attach, indent=4, sort_keys=True)}"
self.log.debug(msg)
self.module.fail_json(msg)

child_fabric_name = self.sn_fab[serial_number]

if child_fabric_name is None:
msg = f"{self.class_name}.{method_name}: "
msg += f"caller: {caller}. "
msg += "Unable to determine child fabric name for serial_number "
msg += f"{serial_number}."
self.log.debug(msg)
self.module.fail_json(msg)

msg = f"serial_number: {serial_number}, "
msg += f"child fabric name: {child_fabric_name}. "
self.log.debug(msg)

vrf_attach["fabric"] = child_fabric_name

msg += "Updated vrf_attach: "
msg += f"{json.dumps(vrf_attach, indent=4, sort_keys=True)}"
self.log.debug(msg)

return copy.deepcopy(vrf_attach)

def push_diff_attach(self, is_rollback=False):
"""
# Summary
Expand Down Expand Up @@ -3086,6 +3163,8 @@ def push_diff_attach(self, is_rollback=False):
msg += f"{json.dumps(vrf_attach, indent=4, sort_keys=True)}"
self.log.debug(msg)

vrf_attach = self.update_vrf_attach_fabric_name(vrf_attach)

if "is_deploy" in vrf_attach:
del vrf_attach["is_deploy"]
if not vrf_attach.get("vrf_lite"):
Expand Down Expand Up @@ -3164,13 +3243,6 @@ def push_diff_attach(self, is_rollback=False):
path = self.paths["GET_VRF"].format(self.fabric)
attach_path = path + "/attachments"

# For multisite fabrics, update the fabric name to the child fabric
# containing the switches.
if self.fabric_type == "MFD":
for elem in new_diff_attach_list:
for node in elem["lanAttachList"]:
node["fabric"] = self.sn_fab[node["serialNumber"]]

self.send_to_controller(
action, verb, attach_path, new_diff_attach_list, is_rollback
)
Expand Down
118 changes: 111 additions & 7 deletions tests/unit/modules/dcnm/fixtures/dcnm_vrf.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
"10.10.10.227": "XYZKSJHSMK4",
"10.10.10.228": "XYZKSJHSMK5"
},
"mock_sn_fab" : {
"XYZKSJHSMK1": "test_fabric",
"XYZKSJHSMK2": "test_fabric",
"XYZKSJHSMK3": "test_fabric",
"XYZKSJHSMK4": "test_fabric",
"XYZKSJHSMK5": "test_fabric"
},
"playbook_config_input_validation" : [
{
"vrf_template": "Default_VRF_Universal",
Expand Down Expand Up @@ -1423,15 +1430,15 @@
"switchRole": "border"
}
},
"fabric_details": {
"fabric_details_orig": {
"createdOn": 1613750822779,
"deviceType": "n9k",
"fabricId": "FABRIC-15",
"fabricName": "MS-fabric",
"fabricTechnology": "VXLANFabric",
"fabricTechnologyFriendly": "VXLAN Fabric",
"fabricType": "MFD",
"fabricTypeFriendly": "Multi-Fabric Domain",
"fabricType": "Switch_Fabric",
"fabricTypeFriendly": "Switch Fabric",
"id": 15,
"modifiedOn": 1613750822779,
"networkExtensionTemplate": "Default_Network_Extension_Universal",
Expand All @@ -1448,13 +1455,14 @@
"DCI_SUBNET_TARGET_MASK": "30",
"DELAY_RESTORE": "300",
"FABRIC_NAME": "MS-fabric",
"FABRIC_TYPE": "MFD",
"FF": "MSD",
"FABRIC_TYPE": "Switch_Fabric",
"FF": "Easy_Fabric",
"L2_SEGMENT_ID_RANGE": "30000-49000",
"L3_PARTITION_ID_RANGE": "50000-59000",
"LOOPBACK100_IP_RANGE": "10.10.0.0/24",
"MS_LOOPBACK_ID": "100",
"MS_UNDERLAY_AUTOCONFIG": "true",
"PER_VRF_LOOPBACK_AUTO_PROVISION": "false",
"RP_SERVER_IP": "",
"TOR_AUTO_DEPLOY": "false",
"default_network": "Default_Network_Universal",
Expand All @@ -1466,11 +1474,107 @@
},
"provisionMode": "DCNMTopDown",
"replicationMode": "IngressReplication",
"templateName": "MSD_Fabric_11_1",
"templateName": "Easy_Fabric",
"vrfExtensionTemplate": "Default_VRF_Extension_Universal",
"vrfTemplate": "Default_VRF_Universal"
},
"mock_vrf12_object": {
"fabric_details_vxlan": {
"createdOn": 1613750822779,
"deviceType": "n9k",
"fabricId": "FABRIC-15",
"fabricName": "MS-fabric",
"fabricTechnology": "VXLANFabric",
"fabricTechnologyFriendly": "VXLAN Fabric",
"fabricType": "Switch_Fabric",
"fabricTypeFriendly": "Switch Fabric",
"id": 15,
"modifiedOn": 1613750822779,
"networkExtensionTemplate": "Default_Network_Extension_Universal",
"networkTemplate": "Default_Network_Universal",
"nvPairs": {
"ANYCAST_GW_MAC": "2020.0000.00aa",
"BGP_RP_ASN": "",
"BORDER_GWY_CONNECTIONS": "Direct_To_BGWS",
"CLOUDSEC_ALGORITHM": "",
"CLOUDSEC_AUTOCONFIG": "false",
"CLOUDSEC_ENFORCEMENT": "",
"CLOUDSEC_KEY_STRING": "",
"DCI_SUBNET_RANGE": "10.10.1.0/24",
"DCI_SUBNET_TARGET_MASK": "30",
"DELAY_RESTORE": "300",
"FABRIC_NAME": "MS-fabric",
"FABRIC_TYPE": "Switch_Fabric",
"FF": "Easy_Fabric",
"L2_SEGMENT_ID_RANGE": "30000-49000",
"L3_PARTITION_ID_RANGE": "50000-59000",
"LOOPBACK100_IP_RANGE": "10.10.0.0/24",
"MS_LOOPBACK_ID": "100",
"MS_UNDERLAY_AUTOCONFIG": "true",
"PER_VRF_LOOPBACK_AUTO_PROVISION": "false",
"RP_SERVER_IP": "",
"TOR_AUTO_DEPLOY": "false",
"default_network": "Default_Network_Universal",
"default_vrf": "Default_VRF_Universal",
"enableScheduledBackup": "false",
"network_extension_template": "Default_Network_Extension_Universal",
"scheduledTime": "",
"vrf_extension_template": "Default_VRF_Extension_Universal"
},
"provisionMode": "DCNMTopDown",
"replicationMode": "IngressReplication",
"templateName": "Easy_Fabric",
"vrfExtensionTemplate": "Default_VRF_Extension_Universal",
"vrfTemplate": "Default_VRF_Universal"
},
"fabric_details": {
"createdOn": 1613750822779,
"deviceType": "n9k",
"fabricId": "FABRIC-15",
"fabricName": "MS-fabric",
"fabricTechnology": "VXLANFabric",
"fabricTechnologyFriendly": "VXLAN Fabric",
"fabricType": "MFD",
"fabricTypeFriendly": "Multi-Fabric Domain",
"id": 15,
"modifiedOn": 1613750822779,
"networkExtensionTemplate": "Default_Network_Extension_Universal",
"networkTemplate": "Default_Network_Universal",
"nvPairs": {
"ANYCAST_GW_MAC": "2020.0000.00aa",
"BGP_RP_ASN": "",
"BORDER_GWY_CONNECTIONS": "Direct_To_BGWS",
"CLOUDSEC_ALGORITHM": "",
"CLOUDSEC_AUTOCONFIG": "false",
"CLOUDSEC_ENFORCEMENT": "",
"CLOUDSEC_KEY_STRING": "",
"DCI_SUBNET_RANGE": "10.10.1.0/24",
"DCI_SUBNET_TARGET_MASK": "30",
"DELAY_RESTORE": "300",
"FABRIC_NAME": "MS-fabric",
"FABRIC_TYPE": "MFD",
"FF": "MSD",
"L2_SEGMENT_ID_RANGE": "30000-49000",
"L3_PARTITION_ID_RANGE": "50000-59000",
"LOOPBACK100_IP_RANGE": "10.10.0.0/24",
"MS_LOOPBACK_ID": "100",
"MS_UNDERLAY_AUTOCONFIG": "true",
"PER_VRF_LOOPBACK_AUTO_PROVISION": "false",
"RP_SERVER_IP": "",
"TOR_AUTO_DEPLOY": "false",
"default_network": "Default_Network_Universal",
"default_vrf": "Default_VRF_Universal",
"enableScheduledBackup": "false",
"network_extension_template": "Default_Network_Extension_Universal",
"scheduledTime": "",
"vrf_extension_template": "Default_VRF_Extension_Universal"
},
"provisionMode": "DCNMTopDown",
"replicationMode": "IngressReplication",
"templateName": "MSD_Fabric_11_1",
"vrfExtensionTemplate": "Default_VRF_Extension_Universal",
"vrfTemplate": "Default_VRF_Universal"
},
"mock_vrf12_object": {
"ERROR": "",
"RETURN_CODE": 200,
"MESSAGE":"OK",
Expand Down
Loading

0 comments on commit f6e6712

Please sign in to comment.