2828from ansible .plugins .action import ActionBase
2929from ansible .template import Templar
3030from ansible .errors import AnsibleFileNotFound
31+ from ansible_collections .cisco .nac_dc_vxlan .plugins .filter import version_compare
3132
3233
34+ import re
3335import json
3436
3537display = Display ()
3638
3739# Path to Jinja template files relative to create role
38- MSD_CHILD_FABRIC_VRF_TEMPLATE = "/../common/templates/ndfc_vrfs/msd_fabric/child_fabric/msd_child_fabric_vrf.j2"
40+ MSD_CHILD_FABRIC_VRF_TEMPLATE_PATH = "/../common/templates/ndfc_vrfs/msd_fabric/child_fabric/"
41+ MSD_CHILD_FABRIC_VRF_TEMPLATE = "/msd_child_fabric_vrf.j2"
42+
43+ # Currently supported VRF template config keys and their mapping to data model keys
44+ VRF_TEMPLATE_CONFIG_MAP = {
45+ 'advertiseHostRouteFlag' : {'dm_key' : 'adv_host_routes' , 'default' : '' },
46+ 'advertiseDefaultRouteFlag' : {'dm_key' : 'adv_default_routes' , 'default' : '' },
47+ 'configureStaticDefaultRouteFlag' : {'dm_key' : 'config_static_default_route' , 'default' : '' },
48+ 'bgpPassword' : {'dm_key' : 'bgp_password' , 'default' : '' },
49+ 'bgpPasswordKeyType' : {'dm_key' : 'bgp_password_key_type' , 'default' : '' },
50+ 'ENABLE_NETFLOW' : {'dm_key' : 'netflow_enable' , 'default' : False },
51+ 'NETFLOW_MONITOR' : {'dm_key' : 'netflow_monitor' , 'default' : '' },
52+ 'trmEnabled' : {'dm_key' : 'trm_enable' , 'default' : False },
53+ 'loopbackNumber' : {'dm_key' : 'rp_loopback_id' , 'default' : '' },
54+ 'rpAddress' : {'dm_key' : 'rp_address' , 'default' : '' },
55+ 'isRPAbsent' : {'dm_key' : 'no_rp' , 'default' : False },
56+ 'isRPExternal' : {'dm_key' : 'rp_external' , 'default' : False },
57+ 'L3VniMcastGroup' : {'dm_key' : 'underlay_mcast_ip' , 'default' : '' },
58+ 'multicastGroup' : {'dm_key' : 'overlay_multicast_group' , 'default' : '' },
59+ 'routeTargetImportMvpn' : {'dm_key' : 'import_mvpn_rt' , 'default' : '' },
60+ 'routeTargetExportMvpn' : {'dm_key' : 'export_mvpn_rt' , 'default' : '' }
61+ }
3962
4063
4164class ActionModule (ActionBase ):
@@ -46,8 +69,21 @@ def run(self, tmp=None, task_vars=None):
4669 results ['failed' ] = False
4770 results ['child_fabrics_changed' ] = []
4871
72+ nd_version = self ._task .args ["nd_version" ]
4973 msite_data = self ._task .args ["msite_data" ]
5074
75+ # Extract major, minor, patch and patch letter from nd_version
76+ # that is set in nac_dc_vxlan.dtc.connectivity_check role
77+ # Example nd_version: "3.1.1l" or "3.2.2m"
78+ # where 3.1.1/3.2.2 are major.minor.patch respectively
79+ # and l/m are the patch letter respectively
80+ nd_major_minor_patch = None
81+ nd_patch_letter = None
82+ match = re .match (r'^(\d+\.\d+\.\d+)([a-z])?$' , nd_version )
83+ if match :
84+ nd_major_minor_patch = match .group (1 )
85+ nd_patch_letter = match .group (2 )
86+
5187 vrfs = msite_data ['overlay_attach_groups' ]['vrfs' ]
5288 vrf_attach_groups_dict = msite_data ['overlay_attach_groups' ]['vrf_attach_groups' ]
5389
@@ -95,6 +131,7 @@ def run(self, tmp=None, task_vars=None):
95131 vrf_child_fabric = vrf_child_fabric [0 ]
96132
97133 # Need to clean these up and make them more dynamic
134+ # Check if fabric settings are properly enabled
98135 if vrf_child_fabric .get ('netflow_enable' ):
99136 if child_fabric_attributes ['ENABLE_NETFLOW' ] == 'false' :
100137 error_msg = (
@@ -145,24 +182,21 @@ def run(self, tmp=None, task_vars=None):
145182 # Check for differences between the data model and the template config from NDFC for the
146183 # attributes that are configurable by the user in a child fabric.
147184 # Note: This excludes IPv6 related attributes at this time as they are not yet supported fully in the data model.
148- if (
149- (ndfc_vrf_template_config ['advertiseHostRouteFlag' ] != str (vrf_child_fabric .get ('adv_host_routes' , '' )).lower ()) or
150- (ndfc_vrf_template_config ['advertiseDefaultRouteFlag' ] != str (vrf_child_fabric .get ('adv_default_routes' , '' )).lower ()) or
151- (ndfc_vrf_template_config ['configureStaticDefaultRouteFlag' ] != str (vrf_child_fabric .get ('config_static_default_route' , '' )).lower ()) or # noqa: E501
152- (ndfc_vrf_template_config ['bgpPassword' ] != vrf_child_fabric .get ('bgp_password' , '' )) or
153- (ndfc_vrf_template_config .get ('bgpPasswordKeyType' , '' ) != vrf_child_fabric .get ('bgp_password_key_type' , '' )) or
154- (ndfc_vrf_template_config ['ENABLE_NETFLOW' ] != str (vrf_child_fabric .get ('netflow_enable' , False )).lower ()) or
155- (ndfc_vrf_template_config ['NETFLOW_MONITOR' ] != vrf_child_fabric .get ('netflow_monitor' , '' )) or
156- (ndfc_vrf_template_config ['trmEnabled' ] != str (vrf_child_fabric .get ('trm_enable' , False )).lower ()) or
157- (ndfc_vrf_template_config .get ('loopbackNumber' , '' ) != vrf_child_fabric .get ('rp_loopback_id' , '' )) or
158- (ndfc_vrf_template_config .get ('rpAddress' , '' ) != vrf_child_fabric .get ('rp_address' , '' )) or
159- (ndfc_vrf_template_config ['isRPAbsent' ] != str (vrf_child_fabric .get ('no_rp' , False )).lower ()) or
160- (ndfc_vrf_template_config ['isRPExternal' ] != str (vrf_child_fabric .get ('rp_external' , False )).lower ()) or
161- (ndfc_vrf_template_config .get ('L3VniMcastGroup' , '' ) != vrf_child_fabric .get ('underlay_mcast_ip' , '' )) or
162- (ndfc_vrf_template_config ['multicastGroup' ] != vrf_child_fabric .get ('overlay_multicast_group' , '' )) or
163- (ndfc_vrf_template_config .get ('routeTargetImportMvpn' , '' ) != vrf_child_fabric .get ('import_mvpn_rt' , '' )) or
164- (ndfc_vrf_template_config .get ('routeTargetExportMvpn' , '' ) != vrf_child_fabric .get ('export_mvpn_rt' , '' ))
165- ):
185+ diff_found = False
186+ for template_key , map_info in VRF_TEMPLATE_CONFIG_MAP .items ():
187+ dm_key = map_info ['dm_key' ]
188+ default = map_info ['default' ]
189+ template_value = ndfc_vrf_template_config .get (template_key , default )
190+ dm_value = vrf_child_fabric .get (dm_key , default )
191+ # Normalize boolean/string values for comparison
192+ if isinstance (default , bool ):
193+ template_value = str (template_value ).lower ()
194+ dm_value = str (dm_value ).lower ()
195+ if template_value != dm_value :
196+ diff_found = True
197+ break
198+
199+ if diff_found :
166200 results ['child_fabrics_changed' ].append (child_fabric )
167201
168202 # Combine task_vars with local_vars for template rendering
@@ -179,7 +213,11 @@ def run(self, tmp=None, task_vars=None):
179213
180214 # Attempt to find and read the template file
181215 role_path = task_vars .get ('role_path' )
182- template_path = role_path + MSD_CHILD_FABRIC_VRF_TEMPLATE
216+ version = '3.2'
217+ if version_compare .version_compare (nd_major_minor_patch , '3.1.1' , '<=' ):
218+ version = '3.1'
219+ template_path = f"{ role_path } { MSD_CHILD_FABRIC_VRF_TEMPLATE_PATH } { version } { MSD_CHILD_FABRIC_VRF_TEMPLATE } "
220+
183221 try :
184222 template_full_path = self ._find_needle ('templates' , template_path )
185223 with open (template_full_path , 'r' ) as template_file :
0 commit comments