From a6d91a8149674b856c46f5144f9f4aa5c012ea0b Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 15 Nov 2024 11:58:55 -1000 Subject: [PATCH 1/3] Fix for issue #343 1. module_utils/fabric/create.py Modify the payload for external fabric types to include EXT_FABRIC_TYPE key with value being the default value that the NDFC GUI uses to display the fabric type. 2. module_utils/fabric/fabric_types.py Add a mapping between external fabric types and the string NDFC uses when displaying the fabric type. --- plugins/module_utils/fabric/create.py | 42 +++++++++++++++++--- plugins/module_utils/fabric/fabric_types.py | 44 +++++++++++++++++++++ 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/fabric/create.py b/plugins/module_utils/fabric/create.py index 8c404908f..d70f8342f 100644 --- a/plugins/module_utils/fabric/create.py +++ b/plugins/module_utils/fabric/create.py @@ -23,12 +23,15 @@ import json import logging -from ansible_collections.cisco.dcnm.plugins.module_utils.common.api.v1.lan_fabric.rest.control.fabrics.fabrics import \ - EpFabricCreate -from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.common import \ - FabricCommon -from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.fabric_types import \ - FabricTypes +from ansible_collections.cisco.dcnm.plugins.module_utils.common.api.v1.lan_fabric.rest.control.fabrics.fabrics import ( + EpFabricCreate, +) +from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.common import ( + FabricCommon, +) +from ansible_collections.cisco.dcnm.plugins.module_utils.fabric.fabric_types import ( + FabricTypes, +) class FabricCreateCommon(FabricCommon): @@ -112,6 +115,31 @@ def _set_fabric_create_endpoint(self, payload): self.path = self.ep_fabric_create.path self.verb = self.ep_fabric_create.verb + def _fixup_payload_ext_fabric_type(self, payload: dict) -> dict: + """ + # Summary + + If the payload contains an external fabric type (e.g ISN) + and does not contain the EXT_FABRIC_TYPE key, add this + key with the default value that NDFC GUI uses for displaying + the fabric type. + + # Raises + + None + """ + self.log.debug(f"ZZZ: payload {json.dumps(payload, indent=4, sort_keys=True)}") + fabric_type = payload.get("FABRIC_TYPE") + if fabric_type not in self.fabric_types.external_fabric_types: + return payload + if "EXT_FABRIC_TYPE" in payload: + return payload + value = self.fabric_types.fabric_type_to_ext_fabric_type_map.get(fabric_type) + if value is None: + return payload + payload["EXT_FABRIC_TYPE"] = value + return payload + def _send_payloads(self): """ - If ``check_mode`` is ``False``, send the payloads @@ -125,6 +153,8 @@ def _send_payloads(self): - This overrides the parent class method. """ for payload in self._payloads_to_commit: + payload = self._fixup_payload_ext_fabric_type(payload) + try: self._set_fabric_create_endpoint(payload) except ValueError as error: diff --git a/plugins/module_utils/fabric/fabric_types.py b/plugins/module_utils/fabric/fabric_types.py index f96dc41ce..74010c9b3 100644 --- a/plugins/module_utils/fabric/fabric_types.py +++ b/plugins/module_utils/fabric/fabric_types.py @@ -88,8 +88,26 @@ def _init_fabric_types(self) -> None: self._fabric_type_to_feature_name_map["VXLAN_EVPN"] = "vxlan" self._fabric_type_to_feature_name_map["VXLAN_EVPN_MSD"] = "vxlan" + # Map fabric type to the value that the controller GUI displays + # in the Fabric Type column at NDFC -> Manage -> Fabrics + # This is needed only for fabrics that use the External_Fabric + # template, e.g. ISN, and will be inserted into the POST request + # payload for external fabrics as (in the case of ISN fabric type): + # "EXT_FABRIC_TYPE": "Multi-Site External Network" + # + # Exposed via property fabric_type_to_ext_fabric_type_map + self._fabric_type_to_ext_fabric_type_map = {} + self._fabric_type_to_ext_fabric_type_map["ISN"] = "Multi-Site External Network" + self._valid_fabric_types = sorted(self._fabric_type_to_template_name_map.keys()) + # Adding self._external_fabric_types to be used in conjunction with + # self._fabric_type_to_ext_fabric_type_map. This is used in (at least) + # FabricCreateCommon() to determine if EXT_FABRIC_TYPE key needs to be + # added to a payload. + self._external_fabric_types = set() + self._external_fabric_types.add("ISN") + self._mandatory_parameters_all_fabrics = [] self._mandatory_parameters_all_fabrics.append("FABRIC_NAME") self._mandatory_parameters_all_fabrics.append("FABRIC_TYPE") @@ -128,6 +146,19 @@ def _init_properties(self) -> None: self._properties["template_name"] = None self._properties["valid_fabric_types"] = self._valid_fabric_types + @property + def external_fabric_types(self): + """ + # Summary + + set() containing all external fabric types e.g. ISN. + + # Raises + + None + """ + return self._external_fabric_types + @property def fabric_type(self): """ @@ -150,6 +181,19 @@ def fabric_type(self, value): raise ValueError(msg) self._properties["fabric_type"] = value + @property + def fabric_type_to_ext_fabric_type_map(self): + """ + # Summary + + Returns a dictionary, keyed on fabric_type (e.g. "ISN"), + whose value is a string that the NDFC GUI uses to describe the + external fabric type. See the Fabric Type column at + NDFC -> Manage -> Fabrics for an example of how this is used + by the NDFC GUI. + """ + return self._fabric_type_to_ext_fabric_type_map + @property def feature_name(self): """ From 2f7ea180b961b0191ce50252cb97f05abe1bbdac Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 15 Nov 2024 14:21:41 -1000 Subject: [PATCH 2/3] Add log message when payload is modified. 1. plugins/module_utils/fabric/create.py a. Change the method name _fixup_payload_ext_fabric_type() to _add_ext_fabric_type_to_payload() b. Add a log message in _add_ext_fabric_type_to_payload() when a payload has been modified. --- plugins/module_utils/fabric/create.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/module_utils/fabric/create.py b/plugins/module_utils/fabric/create.py index d70f8342f..298fab3d7 100644 --- a/plugins/module_utils/fabric/create.py +++ b/plugins/module_utils/fabric/create.py @@ -115,7 +115,7 @@ def _set_fabric_create_endpoint(self, payload): self.path = self.ep_fabric_create.path self.verb = self.ep_fabric_create.verb - def _fixup_payload_ext_fabric_type(self, payload: dict) -> dict: + def _add_ext_fabric_type_to_payload(self, payload: dict) -> dict: """ # Summary @@ -128,7 +128,8 @@ def _fixup_payload_ext_fabric_type(self, payload: dict) -> dict: None """ - self.log.debug(f"ZZZ: payload {json.dumps(payload, indent=4, sort_keys=True)}") + method_name = inspect.stack()[0][3] + fabric_type = payload.get("FABRIC_TYPE") if fabric_type not in self.fabric_types.external_fabric_types: return payload @@ -138,6 +139,12 @@ def _fixup_payload_ext_fabric_type(self, payload: dict) -> dict: if value is None: return payload payload["EXT_FABRIC_TYPE"] = value + + msg = f"{self.class_name}.{method_name}: " + msg += "Added EXT_FABRIC_TYPE to payload. " + msg += f"fabric_type: {fabric_type}, " + msg += f"value: {value}" + self.log.debug(msg) return payload def _send_payloads(self): @@ -153,7 +160,7 @@ def _send_payloads(self): - This overrides the parent class method. """ for payload in self._payloads_to_commit: - payload = self._fixup_payload_ext_fabric_type(payload) + payload = self._add_ext_fabric_type_to_payload(payload) try: self._set_fabric_create_endpoint(payload) From 95c7f626df0758412ec54f73d6f2267111024a8b Mon Sep 17 00:00:00 2001 From: Allen Robel Date: Fri, 15 Nov 2024 14:26:39 -1000 Subject: [PATCH 3/3] Update comment 1. module_utils.fabric/fabric_types.py Edit comment to mention that the private set is exposed via property external_fabric_types. --- plugins/module_utils/fabric/fabric_types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/module_utils/fabric/fabric_types.py b/plugins/module_utils/fabric/fabric_types.py index 74010c9b3..cb737b53a 100644 --- a/plugins/module_utils/fabric/fabric_types.py +++ b/plugins/module_utils/fabric/fabric_types.py @@ -101,10 +101,12 @@ def _init_fabric_types(self) -> None: self._valid_fabric_types = sorted(self._fabric_type_to_template_name_map.keys()) - # Adding self._external_fabric_types to be used in conjunction with + # self._external_fabric_types is used in conjunction with # self._fabric_type_to_ext_fabric_type_map. This is used in (at least) # FabricCreateCommon() to determine if EXT_FABRIC_TYPE key needs to be # added to a payload. + # + # Exposed via property external_fabric_types self._external_fabric_types = set() self._external_fabric_types.add("ISN")