Skip to content

Commit 8a19fd9

Browse files
mtarkingccoueffemikewiebe
authored
Rules for 0.5.0 (#611)
* initial update rules for 0.5.0 * avoid ref before assignment issue * update readme * fix problem in rule 208. This fix ignore fabric_link with no ipv4 key, which is the case when used for fabric_link and not underlay_ip Signed-off-by: ccoueffe <ccoueffe@cisco.com> * update rules * normalize input data name from shuffling * address lint errors * address lint errors * update stp rule * update vni and vlan range rule * update stp rule * update bootstrap rule * update vni and vlan range rule * update stp rule * update ibgp underlay ipv6 rule * address lint errors * update readme * remove meta end play * address lint errors * update external 502 as in ibgp to support old and new bgp_asn Signed-off-by: ccoueffe <ccoueffe@cisco.com> * Add check for ebgp key --------- Signed-off-by: ccoueffe <ccoueffe@cisco.com> Co-authored-by: ccoueffe <ccoueffe@cisco.com> Co-authored-by: mwiebe <mwiebe@cisco.com>
1 parent af5c6aa commit 8a19fd9

File tree

53 files changed

+531
-863
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+531
-863
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ This collection is intended for use with the following release versions:
323323
* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.1`
324324
* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.2`
325325
* `Cisco Nexus Dashboard Fabric Controller (NDFC) Release 12.2.3`
326+
* `Cisco Nexus Dashboard Release 4.1.1g` - Unified Nexus Dashboard Tech Preview
326327

327328
<!--start requires_ansible-->
328329
## Ansible Version Compatibility

plugins/action/common/nac_dc_validate.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,17 @@ def run(self, tmp=None, task_vars=None):
103103
rules_list.append(f'{rules}common')
104104
rules_list.append(f'{rules}ibgp_vxlan/')
105105
rules_list.append(f'{rules}common_vxlan')
106+
elif results['data']['vxlan']['fabric']['type'] in ('eBGP_VXLAN'):
107+
rules_list.append(f'{rules}common')
108+
rules_list.append(f'{rules}ebgp_vxlan/')
109+
rules_list.append(f'{rules}common_vxlan')
106110
elif results['data']['vxlan']['fabric']['type'] in ('MSD', 'MCF'):
107111
rules_list.append(f'{rules}multisite/')
108112
elif results['data']['vxlan']['fabric']['type'] in ('ISN'):
109113
rules_list.append(f'{rules}isn/')
110114
elif results['data']['vxlan']['fabric']['type'] in ('External'):
111115
rules_list.append(f'{rules}common')
112116
rules_list.append(f'{rules}external/')
113-
elif results['data']['vxlan']['fabric']['type'] in ('eBGP_VXLAN'):
114-
rules_list.append(f'{rules}ebgp_vxlan/')
115-
rules_list.append(f'{rules}common_vxlan')
116117
else:
117118
results['failed'] = True
118119
results['msg'] = f"vxlan.fabric.type {results['data']['vxlan']['fabric']['type']} is not a supported fabric type."

plugins/action/common/prepare_plugins/prep_002_global.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
"bootstrap"
5252
]
5353

54+
ISN_PARENT_KEYS = ['vxlan', 'multisite']
55+
5456
# Deprecated global keys that are still supported for backwards compatibility
5557
ISN_BACKWARD_COMPATIBLE_KEYS = [
5658
"auth_proto",
@@ -85,7 +87,7 @@ def prepare(self):
8587
elif model_data['vxlan']['fabric']['type'] == 'ISN':
8688
# new_global_key is set to 'isn' here only for the conditional check that follows and is not a new key
8789
new_global_key = 'isn'
88-
ISN_PARENT_KEYS = ['vxlan', 'multisite', new_global_key]
90+
ISN_PARENT_KEYS.append(new_global_key)
8991

9092
if new_global_key in ['ibgp', 'external']:
9193
dm_check = data_model_key_check(model_data, PARENT_KEYS)

roles/validate/files/rules/common/200_global_bgp_asn.py

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,65 @@ class Rule:
44
severity = "HIGH"
55

66
@classmethod
7-
def match(cls, data):
7+
def match(cls, data_model):
88
results = []
99

10-
fabric_type_map = {
11-
"VXLAN_EVPN": "ibgp",
12-
"External": "external"
13-
}
14-
15-
fabric_type = None
16-
fabric_type = fabric_type_map.get(data["vxlan"]["fabric"].get("type"))
17-
18-
# If we check keys vxlan.global.{fabric_type}.bgp_asn then this natively checks for this path
19-
# as well as the legacy vxlan.global path. Examples:
20-
# {'keys_found': ['vxlan', 'global', 'bgp_asn'], 'keys_not_found': ['ibgp'], 'keys_data': ['vxlan', 'global'], 'keys_no_data': ['bgp_asn']}
21-
# {'keys_found': ['vxlan', 'global', 'ibgp', 'bgp_asn'], 'keys_not_found': [], 'keys_data': ['vxlan', 'global', 'ibgp'], 'keys_no_data': ['bgp_asn']}
22-
check = cls.data_model_key_check(data, ['vxlan', 'global', fabric_type, 'bgp_asn'])
23-
if 'bgp_asn' in check['keys_not_found']:
24-
check = cls.data_model_key_check(data, ['vxlan', 'global', 'bgp_asn'])
25-
if 'bgp_asn' in check['keys_not_found']:
26-
results.append(f"vxlan.global.{fabric_type}.bgp_asn must be defined in the data model.")
27-
return results
28-
29-
if 'bgp_asn' in check['keys_found'] and 'bgp_asn' in check['keys_no_data']:
30-
results.append(f"vxlan.global.{fabric_type}.bgp_asn must have a value defined in the data model.")
10+
dm_fabric_type = None
11+
fabric_type_keys = ['vxlan', 'fabric', 'type']
12+
check_fabric_type_key = cls.data_model_key_check(data_model, fabric_type_keys)
13+
if 'type' in check_fabric_type_key['keys_found'] and 'type' in check_fabric_type_key['keys_data']:
14+
dm_fabric_type = data_model['vxlan']['fabric']['type']
15+
16+
if dm_fabric_type:
17+
# Map fabric types to the keys used in the data model based on controller fabric types
18+
fabric_type_map = {
19+
"VXLAN_EVPN": "ibgp",
20+
"eBGP_VXLAN": "ebgp",
21+
"External": "external"
22+
}
23+
24+
fabric_type = fabric_type_map.get(dm_fabric_type)
25+
26+
if fabric_type in ["ibgp", "external"]:
27+
# If we check keys vxlan.global.{fabric_type}.bgp_asn then this natively checks for this path
28+
# as well as the legacy vxlan.global path. Examples:
29+
# {'keys_found': ['vxlan', 'global'], 'keys_not_found': ['ibgp'], 'keys_data': ['vxlan', 'global'], 'keys_no_data': ['bgp_asn']} # noqa: E501
30+
# {'keys_found': ['vxlan', 'global', 'ibgp'], 'keys_not_found': ['bgp_asn'], 'keys_data': ['vxlan', 'global', 'ibgp'], 'keys_no_data': ['bgp_asn']} # noqa: E501
31+
check = cls.data_model_key_check(data_model, ['vxlan', 'global', fabric_type, 'bgp_asn'])
32+
if 'bgp_asn' in check['keys_not_found']:
33+
check = cls.data_model_key_check(data_model, ['vxlan', 'global', 'bgp_asn'])
34+
if 'bgp_asn' in check['keys_not_found']:
35+
results.append(f"vxlan.global.{fabric_type}.bgp_asn must be defined in the data model.")
36+
return results
37+
38+
# {'keys_found': ['vxlan', 'global', 'bgp_asn'], 'keys_not_found': [], 'keys_data': ['vxlan', 'global'], 'keys_no_data': ['bgp_asn']} # noqa: E501
39+
# {'keys_found': ['vxlan', 'global', 'ibgp', 'bgp_asn'], 'keys_not_found': [], 'keys_data': ['vxlan', 'global', 'ibgp'], 'keys_no_data': ['bgp_asn']} # noqa: E501
40+
if 'bgp_asn' in check['keys_found'] and 'bgp_asn' in check['keys_no_data']:
41+
results.append(f"vxlan.global.{fabric_type}.bgp_asn must have a value defined in the data model.")
42+
return results
43+
44+
if fabric_type in ["ebgp"]:
45+
# Since ebgp keys are only supported under vxlan.global.ebgp we need to ensure the ebgp key exists
46+
check = cls.data_model_key_check(data_model, ['vxlan', 'global', fabric_type])
47+
if 'ebgp' in check['keys_not_found']:
48+
results.append(f"Fabric type is 'ebgp'. Key vxlan.global.{fabric_type} must be defined in the data model.")
49+
return results
50+
51+
# Examples:
52+
# {'keys_found': ['vxlan', 'global', 'ebgp'], 'keys_not_found': ['spine_bgp_asn'], 'keys_data': ['vxlan', 'global', 'ebgp'], 'keys_no_data': []} # noqa: E501
53+
check = cls.data_model_key_check(data_model, ['vxlan', 'global', fabric_type, 'spine_bgp_asn'])
54+
if 'spine_bgp_asn' in check['keys_not_found']:
55+
results.append(f"vxlan.global.{fabric_type}.spine_bgp_asn must be defined in the data model.")
56+
return results
57+
58+
# Examples:
59+
# {'keys_found': ['vxlan', 'global', 'ebgp', 'spine_bgp_asn'], 'keys_not_found': [], 'keys_data': ['vxlan', 'global', 'ebgp'], 'keys_no_data': ['spine_bgp_asn']} # noqa: E501
60+
if 'spine_bgp_asn' in check['keys_found'] and 'spine_bgp_asn' in check['keys_no_data']:
61+
results.append(f"vxlan.global.{fabric_type}.spine_bgp_asn must have a value defined in the data model.")
62+
return results
63+
64+
else:
65+
results.append("vxlan.fabric.type must be defined in the data model.")
3166
return results
3267

3368
return results

roles/validate/files/rules/ibgp_vxlan/204_global_bootstrap.py renamed to roles/validate/files/rules/common/204_global_bootstrap.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,56 @@ class Rule:
44
severity = "HIGH"
55

66
@classmethod
7-
def match(cls, inventory):
7+
def match(cls, data_model):
88
results = []
99
dhcp = None
1010

11-
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_bootstrap']
12-
check = cls.data_model_key_check(inventory, bootstrap_keys)
11+
# Map fabric types to the keys used in the data model based on controller fabric types
12+
fabric_type_map = {
13+
"VXLAN_EVPN": "ibgp",
14+
"eBGP_VXLAN": "ebgp",
15+
}
16+
17+
fabric_type = fabric_type_map.get(data_model['vxlan']['fabric']['type'])
18+
19+
bootstrap_keys = ['vxlan', 'global', fabric_type]
20+
check = cls.data_model_key_check(data_model, bootstrap_keys)
21+
if fabric_type in check['keys_found']:
22+
bootstrap_keys = ['vxlan', 'global', fabric_type, 'bootstrap', 'enable_bootstrap']
23+
check = cls.data_model_key_check(data_model, bootstrap_keys)
24+
25+
if fabric_type in check['keys_not_found'] or 'enable_bootstrap' in check['keys_not_found']:
26+
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_bootstrap']
27+
check = cls.data_model_key_check(data_model, bootstrap_keys)
28+
1329
if 'enable_bootstrap' in check['keys_found']:
14-
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server']
15-
check = cls.data_model_key_check(inventory, bootstrap_keys)
16-
enable_local_dhcp_server = cls.safeget(inventory, ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server'])
30+
if fabric_type in bootstrap_keys:
31+
bootstrap_keys = ['vxlan', 'global', fabric_type, 'bootstrap', 'enable_local_dhcp_server']
32+
else:
33+
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'enable_local_dhcp_server']
34+
check = cls.data_model_key_check(data_model, bootstrap_keys)
35+
enable_local_dhcp_server = cls.safeget(data_model, bootstrap_keys)
1736
if 'enable_local_dhcp_server' in check['keys_found'] and enable_local_dhcp_server:
18-
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'dhcp_version']
19-
check = cls.data_model_key_check(inventory, bootstrap_keys)
37+
if fabric_type in bootstrap_keys:
38+
bootstrap_keys = ['vxlan', 'global', fabric_type, 'bootstrap', 'dhcp_version']
39+
else:
40+
bootstrap_keys = ['vxlan', 'global', 'bootstrap', 'dhcp_version']
41+
check = cls.data_model_key_check(data_model, bootstrap_keys)
2042
if 'dhcp_version' in check['keys_found']:
21-
if inventory['vxlan']['global']['bootstrap']['dhcp_version'] == 'DHCPv4':
43+
if cls.safeget(data_model, bootstrap_keys) == 'DHCPv4':
2244
dhcp = 'dhcp_v4'
23-
elif inventory['vxlan']['global']['bootstrap']['dhcp_version'] == 'DHCPv6':
45+
elif cls.safeget(data_model, bootstrap_keys) == 'DHCPv6':
2446
dhcp = 'dhcp_v6'
2547
else:
26-
results.append("A vxlan.global.bootstrap.dhcp_version is required for bootstrap in a VXLAN type fabric.")
48+
results.append(f"A vxlan.global.{fabric_type}.bootstrap.dhcp_version is required for bootstrap in a VXLAN type fabric.")
2749
return results
2850

2951
if dhcp:
30-
bootstrap_keys = ['vxlan', 'global', 'bootstrap', dhcp, 'domain_name']
31-
check = cls.data_model_key_check(inventory, bootstrap_keys)
52+
if fabric_type in bootstrap_keys:
53+
bootstrap_keys = ['vxlan', 'global', fabric_type, 'bootstrap', dhcp, 'domain_name']
54+
else:
55+
bootstrap_keys = ['vxlan', 'global', 'bootstrap', dhcp, 'domain_name']
56+
check = cls.data_model_key_check(data_model, bootstrap_keys)
3257
if dhcp in check['keys_not_found']:
3358
results.append(
3459
"When vxlan.global.bootstrap.dhcp_version is defined, either "

roles/validate/files/rules/external/301_topology_switch_serial.py renamed to roles/validate/files/rules/common/301_topology_switch_serial.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ class Rule:
44
severity = "HIGH"
55

66
@classmethod
7-
def match(cls, inventory):
7+
def match(cls, data_model):
88
results = []
99
switches = []
1010

11-
check = cls.data_model_key_check(inventory, ['vxlan', 'topology', 'switches'])
11+
check = cls.data_model_key_check(data_model, ['vxlan', 'topology', 'switches'])
1212
if 'switches' in check['keys_data']:
13-
switches = inventory.get("vxlan").get("topology").get("switches")
13+
switches = data_model.get("vxlan").get("topology").get("switches")
1414
else:
1515
return results
1616

roles/validate/files/rules/ibgp_vxlan/302_topology_switch_management.py renamed to roles/validate/files/rules/common/302_topology_switch_management.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ class Rule:
44
severity = "HIGH"
55

66
@classmethod
7-
def match(cls, inventory):
7+
def match(cls, data_model):
88
results = []
99
management_defined = []
1010
switches = []
11-
if inventory.get("vxlan", None):
12-
if inventory["vxlan"].get("topology", None):
13-
if inventory.get("vxlan").get("topology").get("switches", None):
14-
switches = inventory.get("vxlan").get("topology").get("switches")
11+
if data_model.get("vxlan", None):
12+
if data_model["vxlan"].get("topology", None):
13+
if data_model.get("vxlan").get("topology").get("switches", None):
14+
switches = data_model.get("vxlan").get("topology").get("switches")
1515
for switch in switches:
1616
if not switch.get("management", False):
1717
results.append(

roles/validate/files/rules/external/303_topology_switch_role.py renamed to roles/validate/files/rules/common/303_topology_switch_role.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ class Rule:
44
severity = "HIGH"
55

66
@classmethod
7-
def match(cls, inventory):
7+
def match(cls, data_model):
88
results = []
99
switches = []
10-
if inventory.get("vxlan", None):
11-
if inventory["vxlan"].get("topology", None):
12-
if inventory.get("vxlan").get("topology").get("switches", None):
13-
switches = inventory.get("vxlan").get("topology").get("switches")
10+
if data_model.get("vxlan", None):
11+
if data_model["vxlan"].get("topology", None):
12+
if data_model.get("vxlan").get("topology").get("switches", None):
13+
switches = data_model.get("vxlan").get("topology").get("switches")
1414
for switch in switches:
1515
if not switch.get("role", False):
1616
results.append(

roles/validate/files/rules/external/304_topology_switch_interfaces_members_unique.py renamed to roles/validate/files/rules/common/304_topology_switch_interfaces_members_unique.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ class Rule:
88

99
# Check if interface names are unique per switch and member interfaces are not repeated within a switch
1010
@classmethod
11-
def match(cls, inventory):
11+
def match(cls, data_model):
1212
results = []
1313
# Check if fabric topology switches are defined
1414
switches = []
15-
if inventory.get("vxlan", None):
16-
if inventory["vxlan"].get("topology", None):
17-
if inventory.get("vxlan").get("topology").get("switches", None):
18-
switches = inventory.get("vxlan").get("topology").get("switches")
15+
if data_model.get("vxlan", None):
16+
if data_model["vxlan"].get("topology", None):
17+
if data_model.get("vxlan").get("topology").get("switches", None):
18+
switches = data_model.get("vxlan").get("topology").get("switches")
1919
for switch in switches:
2020
# Check if interfaces are defined
2121
if switch.get("interfaces"):

roles/validate/files/rules/external/305_topology_switch_interfaces_vpc.py renamed to roles/validate/files/rules/common/305_topology_switch_interfaces_vpc.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@
33

44
class Rule:
55
id = "305"
6-
description = (
7-
"Verify vPC interfaces are compliant with vPC configuration requirements"
8-
)
6+
description = "Verify vPC interfaces are compliant with vPC configuration requirements"
97
severity = "HIGH"
108

119
# Check if vPC interfaces are compliant with vPC configuration requirements
1210
@classmethod
13-
def match(cls, inventory):
11+
def match(cls, data_model):
1412
# initialize results list, vpc_interfaces_dict and vpc_interfaces_dict_parameters dictionaries, vpc_params_to_match list and vpc_peers_list
1513
results = []
1614
vpc_interfaces_dict = {}
@@ -22,13 +20,13 @@ def match(cls, inventory):
2220
"spanning_tree_portfast",
2321
"pc_mode",
2422
]
25-
vpc_peers_list = cls.get_vpc_peers(inventory)
23+
vpc_peers_list = cls.get_vpc_peers(data_model)
2624
# Check if fabric topology switches are defined
2725
switches = []
28-
if inventory.get("vxlan", None):
29-
if inventory["vxlan"].get("topology", None):
30-
if inventory.get("vxlan").get("topology").get("switches", None):
31-
switches = inventory.get("vxlan").get("topology").get("switches")
26+
if data_model.get("vxlan", None):
27+
if data_model["vxlan"].get("topology", None):
28+
if data_model.get("vxlan").get("topology").get("switches", None):
29+
switches = data_model.get("vxlan").get("topology").get("switches")
3230
for switch in switches:
3331
switch_name = switch["name"]
3432
# Check if interfaces are defined
@@ -190,13 +188,13 @@ def normalize_interface_name(cls, interface_name):
190188

191189
# Get vpc pairs from fabric topology vpc_peers
192190
@classmethod
193-
def get_vpc_peers(cls, inventory):
191+
def get_vpc_peers(cls, data_model):
194192
vpc_peers_list = []
195-
if inventory.get("vxlan", None):
196-
if inventory["vxlan"].get("topology", None):
197-
if inventory.get("vxlan").get("topology").get("vpc_peers", None):
193+
if data_model.get("vxlan", None):
194+
if data_model["vxlan"].get("topology", None):
195+
if data_model.get("vxlan").get("topology").get("vpc_peers", None):
198196
for vpc_peers in (
199-
inventory.get("vxlan").get("topology").get("vpc_peers")
197+
data_model.get("vxlan").get("topology").get("vpc_peers")
200198
):
201199
vpc_peers_list.append(
202200
sorted([vpc_peers.get("peer1"), vpc_peers.get("peer2")])

0 commit comments

Comments
 (0)