From 8f68a28f60609624fb1e6287313c08f08d9ad6d3 Mon Sep 17 00:00:00 2001 From: muthuku Date: Thu, 2 Jul 2026 11:15:10 +0000 Subject: [PATCH 1/4] Added validation check for CSCwt58626 --- aci-preupgrade-validation-script.py | 59 +++++++++++++++++ docs/docs/validations.md | 12 +++- .../fvnsEncapBlk_no_overlap.json | 11 ++++ .../fvnsEncapBlk_overlap.json | 11 ++++ .../lldpInst_infra_vlan.json | 10 +++ ...t_infravlan_overlap_access_policy_check.py | 65 +++++++++++++++++++ 6 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index a3ca853..91ad5ae 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6532,6 +6532,64 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): return Result(result=NA, msg="No affected Fabric module found.") +@check_wrapper(check_title="InfraVLAN Overlap in Access Policy VLAN Pools") +def infravlan_overlap_access_policy_check(tversion, **kwargs): + result = PASS + headers = ["InfraVLAN", "VLAN Pool", "Encap Block"] + data = [] + recommended_action = ( + "Ensure InfraVLAN is not part of any access VLAN pool range. " + "Remove the overlapping InfraVLAN or adjust VLAN pool blocks." + ) + doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#infravlan-overlap-access-policy-check" + + if not tversion: + return Result(result=MANUAL, msg=TVER_MISSING) + + if (tversion.same_as("6.2(1g)") or tversion.same_as("6.1(3f)") or + (tversion.newer_than("6.1(3f)") and tversion.older_than("6.1(5e)")) or tversion.same_as("6.1(5e)")): + + infra_vlan = None + lldpInsts = icurl('class', 'lldpInst.json') + for lldpInst in lldpInsts: + infra_vlan_id = lldpInst.get('lldpInst', {}).get('attributes', {}).get('infraVlan') + if not infra_vlan_id: + continue + match = re.search(r'\d+', str(infra_vlan_id)) + if match: + infra_vlan = int(match.group(0)) + break + + encap_blocks = icurl('class', 'fvnsEncapBlk.json') + dn_pool_re = re.compile(r'vlanns-\[(?P[^\]]+)\]') + for obj in encap_blocks: + + blk_attr = obj.get('fvnsEncapBlk', {}).get('attributes', {}) + dn = blk_attr.get('dn', '') + from_encap = blk_attr.get('from') + to_encap = blk_attr.get('to') + if not dn or not from_encap or not to_encap: + continue + + pool_match = dn_pool_re.search(dn) + pool_name = pool_match.group('pool') if pool_match else '-' + + try: + from_vlan = int(str(from_encap).split('-')[-1]) + to_vlan = int(str(to_encap).split('-')[-1]) + except (ValueError, TypeError): + continue + + if min(from_vlan, to_vlan) <= infra_vlan <= max(from_vlan, to_vlan): + result = FAIL_O + data.append([str(infra_vlan), pool_name, "{} to {}".format(from_encap, to_encap)]) + + else: + return Result(result=NA, msg=VER_NOT_AFFECTED) + + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + # ---- Script Execution ---- @@ -6705,6 +6763,7 @@ class CheckManager: inband_management_policy_misconfig_check, bgpProto_timer_policy_already_existing_check, wred_affected_model_check, + infravlan_overlap_access_policy_check, ] ssh_checks = [ # General diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 76e9c14..5bd1cdf 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -205,6 +205,7 @@ Items | Defect | This Script [Inband Management Policy Misconfiguration][d33]| CSCwd40071 | :white_check_mark: | :no_entry_sign: [BgpProto timer policy already existing][d34] | CSCwt78235 | :white_check_mark: | :no_entry_sign: [WRED with Affected FM Models][d35] | CSCwt50713 | :white_check_mark: | :no_entry_sign: +[InfraVLAN Overlap in Access Policy VLAN Pools][d36] | CSCwt58626 | :white_check_mark: | :no_entry_sign: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -241,6 +242,7 @@ Items | Defect | This Script [d33]: #inband-management-policy-misconfiguration [d34]: #bgpProto-timer-policy-already-existing [d35]: #wred-with-affected-fm-models +[d36]: #infravlan-overlap-access-policy-check ## General Check Details @@ -2819,6 +2821,13 @@ To avoid this issue, disable WRED on the affected nodes or upgrade to a release This bug [CSCwt78235][71] validates `F0467` faults where `changeSet` contains 'bgpProt-policy-already-existing'. The fault indicates conflicting BGP protocol timer policy under an L3Outs deployed in same vrf under same node. If this fault is not resolved, l3out will not be programmed properly in the leaf after the clean reboot or the upgrade. +#### Infravlan Overlap Access Policy Check + +Due to [CSCwt58626][74], when targeting APIC version 6.1(3f) to 6.1(5e) or 6.2(1g) , if the InfraVLAN overlaps with any user-configured VLAN pool range in Access Policies, fault `F4701` is raised for VLAN pools that include the InfraVLAN. After the upgrade, domains linked to those VLAN pools cannot be associated with new EPGs, although existing EPGs continue to function. + +To avoid this issue, modify user VLAN pool ranges so that the InfraVLAN does not overlap with any configured block or select the fixed version as a target release. + + [0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script [1]: https://www.cisco.com/c/dam/en/us/td/docs/Website/datacenter/apicmatrix/index.html [2]: https://www.cisco.com/c/en/us/support/switches/nexus-9000-series-switches/products-release-notes-list.html @@ -2892,4 +2901,5 @@ This bug [CSCwt78235][71] validates `F0467` faults where `changeSet` contains 'b [70]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvo27498 [71]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt78235 [72]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt50713 -[73]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwo74485 \ No newline at end of file +[73]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwo74485 +[74]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt58626 \ No newline at end of file diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json new file mode 100644 index 0000000..ca6c6cb --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json @@ -0,0 +1,11 @@ +[ + { + "fvnsEncapBlk": { + "attributes": { + "from": "vlan-200", + "to": "vlan-300", + "dn": "uni/infra/vlanns-[vlan_pool]-static/from-[vlan-200]-to-[vlan-300]" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json new file mode 100644 index 0000000..beedded --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json @@ -0,0 +1,11 @@ +[ + { + "fvnsEncapBlk": { + "attributes": { + "from": "vlan-100", + "to": "vlan-4094", + "dn": "uni/infra/vlanns-[vlan_pool]-static/from-[vlan-100]-to-[vlan-4094]" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json new file mode 100644 index 0000000..a76980e --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json @@ -0,0 +1,10 @@ +[ + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "infraVlan": "vlan-4093" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py b/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py new file mode 100644 index 0000000..30795da --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py @@ -0,0 +1,65 @@ +import os +import pytest +import logging +import importlib +from helpers.utils import read_data + +script = importlib.import_module("aci-preupgrade-validation-script") + +log = logging.getLogger(__name__) +dir = os.path.dirname(os.path.abspath(__file__)) + +test_function = "infravlan_overlap_access_policy_check" + +# icurl queries +lldpInst_api = "lldpInst.json" +fvnsEncapBlk_api = "fvnsEncapBlk.json" + + +@pytest.mark.parametrize( + "icurl_outputs, tversion, expected_result", + [ + # Case 1 : infraVlan overlapping in user configured vlan pool range + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + }, + "6.2(1g)", + script.FAIL_O, + ), + # Case 2 : infraVlan not overlapping in user configured vlan pool range + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_no_overlap.json"), + }, + "6.2(1g)", + script.PASS, + ), + # case 3 : version not impacting the check, so result should be NA + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + }, + "6.0(9f)", + script.NA, + ), + # case 3 : tversion missing check + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + }, + None, + script.MANUAL, + ), + ], +) +def test_logic(run_check, mock_icurl, tversion, expected_result): + result = run_check(tversion=script.AciVersion(tversion)if tversion else None) + assert result.result == expected_result + + + From 8f858b87072e9e7517d29898c2f86727826baf0d Mon Sep 17 00:00:00 2001 From: muthuku Date: Fri, 3 Jul 2026 06:28:26 +0000 Subject: [PATCH 2/4] updated comments --- aci-preupgrade-validation-script.py | 167 ++++++++++++++---- docs/docs/validations.md | 4 +- .../fvnsEncapBlk_empty.json | 1 + .../fvnsEncapBlk_no_overlap.json | 11 +- ...nsEncapBlk_overlap_multiple_vlan_pool.json | 20 +++ ...vnsEncapBlk_overlap_single_vlan_pool.json} | 0 .../lldpInst_empty.json | 1 + .../lldpInst_infra_vlan.json | 10 -- .../lldpInst_infra_vlan_multiple_entry.json | 102 +++++++++++ .../lldpInst_infra_vlan_single_entry.json | 12 ++ ...t_infravlan_overlap_access_policy_check.py | 124 +++++++++++-- 11 files changed, 382 insertions(+), 70 deletions(-) create mode 100644 tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_empty.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_multiple_vlan_pool.json rename tests/checks/infravlan_overlap_access_policy_check/{fvnsEncapBlk_overlap.json => fvnsEncapBlk_overlap_single_vlan_pool.json} (100%) create mode 100644 tests/checks/infravlan_overlap_access_policy_check/lldpInst_empty.json delete mode 100644 tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_multiple_entry.json create mode 100644 tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_single_entry.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 91ad5ae..2303e51 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6532,60 +6532,149 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): return Result(result=NA, msg="No affected Fabric module found.") +@check_wrapper(check_title='N9K-C93180YC-FX3 Switch Memory Less Than 32GB') +def n9k_c93180yc_fx3_switch_memory_check(fabric_nodes, **kwargs): + result = PASS + headers = ["NodeId", "Name", "Model", "Memory Detected (GB)"] + data = [] + recommended_action = 'Increase the switch memory to at least 32GB on affected N9K-C93180YC-FX3.' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#n9k-c93180yc-fx3-switch-memory-less-than-32gb' + min_memory_kb = 32 * 1000 * 1000 + msg = '' + + affected_nodes = [ + node for node in fabric_nodes + if node['fabricNode']['attributes']['model'] == 'N9K-C93180YC-FX3' + ] + + if not affected_nodes: + result = NA + msg = 'No N9K-C93180YC-FX3 switches found. Skipping.' + else: + node_ids = [node['fabricNode']['attributes']['id'] for node in affected_nodes] + node_filter = 'or({})'.format(','.join( + 'wcard(procMemUsage.dn,"node-{}/")'.format(nid) for nid in node_ids + )) + query = 'procMemUsage.json?query-target-filter=and({},wcard(procMemUsage.dn,"memusage-sup"),lt(procMemUsage.Total,"{}"))'.format( + node_filter, min_memory_kb + ) + proc_mem_mos = icurl('class', query) + + node_id_to_attrs = { + node['fabricNode']['attributes']['id']: node['fabricNode']['attributes'] + for node in affected_nodes + } + + for memory_mo in proc_mem_mos: + attrs = memory_mo['procMemUsage']['attributes'] + dn_match = re.search(node_regex, attrs['dn']) + if not dn_match: + continue + node_id = dn_match.group('node') + if node_id not in node_id_to_attrs: + continue + memory_in_gb = round(int(attrs['Total']) / 1000000, 2) + result = FAIL_O + data.append([ + node_id, + node_id_to_attrs[node_id]['name'], + node_id_to_attrs[node_id]['model'], + memory_in_gb, + ]) + + if data: + msg = ( + 'N9K-C93180YC-FX3 requires a minimum of 32GB RAM for proper operation in ACI mode. ' + 'One or more switches with less than 32GB of memory may experience service instability. ' + 'Upgrade the switch memory to at least 32GB.' + ) + + return Result(result=result, msg=msg, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + +@check_wrapper(check_title="Stale dbgacEpgSummaryTask Objects") +def stale_dbgacEpgSummaryTask_check(tversion, **kwargs): + result = PASS + headers = ["DN", "Start Time"] + data = [] + recommended_action = "Contact Cisco TAC for next steps. For more details, refer to the workaround in [CSCwt69100](https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt69100)." + doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#stale-dbgacepgsummarytask-objects" + + if tversion and ((tversion.major1 == "6" and tversion.major2 == "1" and tversion.newer_than("6.1(5e)")) or tversion.newer_than("6.2(1g)")): + return Result(result=NA, msg=VER_NOT_AFFECTED, doc_url=doc_url) + + threshold = datetime.utcnow() - timedelta(hours=24) + for obj in icurl("class", 'dbgacEpgSummaryTask.json?query-target-filter=eq(dbgacEpgSummaryTask.operSt,"processing")'): + attr = obj["dbgacEpgSummaryTask"]["attributes"] + dn = attr.get("dn", "") + start_ts = attr.get("startTs", "") + try: + task_dt = datetime.strptime(start_ts[:19], "%Y-%m-%dT%H:%M:%S") + except ValueError: + continue + if task_dt < threshold: + data.append([dn, start_ts]) + + if data: + result = FAIL_UF + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + @check_wrapper(check_title="InfraVLAN Overlap in Access Policy VLAN Pools") def infravlan_overlap_access_policy_check(tversion, **kwargs): result = PASS headers = ["InfraVLAN", "VLAN Pool", "Encap Block"] data = [] - recommended_action = ( - "Ensure InfraVLAN is not part of any access VLAN pool range. " - "Remove the overlapping InfraVLAN or adjust VLAN pool blocks." - ) + recommended_action = "Remove InfraVLAN from VLAN pool block highligted or upgrade to fix version" + doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#infravlan-overlap-access-policy-check" if not tversion: return Result(result=MANUAL, msg=TVER_MISSING) - if (tversion.same_as("6.2(1g)") or tversion.same_as("6.1(3f)") or - (tversion.newer_than("6.1(3f)") and tversion.older_than("6.1(5e)")) or tversion.same_as("6.1(5e)")): - - infra_vlan = None - lldpInsts = icurl('class', 'lldpInst.json') - for lldpInst in lldpInsts: - infra_vlan_id = lldpInst.get('lldpInst', {}).get('attributes', {}).get('infraVlan') - if not infra_vlan_id: - continue - match = re.search(r'\d+', str(infra_vlan_id)) - if match: - infra_vlan = int(match.group(0)) - break + if not (tversion.same_as("6.2(1g)") or ( + not tversion.older_than("6.1(3f)") and not tversion.newer_than("6.1(5e)") + )): + return Result(result=NA, msg=VER_NOT_AFFECTED) - encap_blocks = icurl('class', 'fvnsEncapBlk.json') - dn_pool_re = re.compile(r'vlanns-\[(?P[^\]]+)\]') - for obj in encap_blocks: + infra_vlan = None + lldpInsts = icurl('class', 'lldpInst.json') + for lldpInst in lldpInsts: + infra_vlan_id = lldpInst.get('lldpInst', {}).get('attributes', {}).get('infraVlan') + if not infra_vlan_id: + continue + match = re.search(r'\d+', str(infra_vlan_id)) + if match: + infra_vlan = int(match.group(0)) + break - blk_attr = obj.get('fvnsEncapBlk', {}).get('attributes', {}) - dn = blk_attr.get('dn', '') - from_encap = blk_attr.get('from') - to_encap = blk_attr.get('to') - if not dn or not from_encap or not to_encap: - continue + if infra_vlan is None: + return Result(result=NA, msg="Unable to determine InfraVLAN from lldpInst.") + + encap_blocks = icurl('class', 'fvnsEncapBlk.json') + dn_pool_re = re.compile(r'vlanns-\[(?P[^\]]+)\]') + for obj in encap_blocks: + blk_attr = obj.get('fvnsEncapBlk', {}).get('attributes', {}) + dn = blk_attr.get('dn', '') + from_encap = blk_attr.get('from') + to_encap = blk_attr.get('to') + if not dn or not from_encap or not to_encap: + continue - pool_match = dn_pool_re.search(dn) - pool_name = pool_match.group('pool') if pool_match else '-' + pool_match = dn_pool_re.search(dn) + pool_name = pool_match.group('vlan_pool') if pool_match else '-' - try: - from_vlan = int(str(from_encap).split('-')[-1]) - to_vlan = int(str(to_encap).split('-')[-1]) - except (ValueError, TypeError): - continue + try: + from_vlan = int(str(from_encap).split('-')[-1]) + to_vlan = int(str(to_encap).split('-')[-1]) + except (ValueError, TypeError): + continue - if min(from_vlan, to_vlan) <= infra_vlan <= max(from_vlan, to_vlan): - result = FAIL_O - data.append([str(infra_vlan), pool_name, "{} to {}".format(from_encap, to_encap)]) + if min(from_vlan, to_vlan) <= infra_vlan <= max(from_vlan, to_vlan): + data.append([str(infra_vlan), pool_name, "{} to {}".format(from_encap, to_encap)]) - else: - return Result(result=NA, msg=VER_NOT_AFFECTED) + if data: + result = FAIL_O return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) @@ -6763,6 +6852,8 @@ class CheckManager: inband_management_policy_misconfig_check, bgpProto_timer_policy_already_existing_check, wred_affected_model_check, + n9k_c93180yc_fx3_switch_memory_check, + stale_dbgacEpgSummaryTask_check, infravlan_overlap_access_policy_check, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 5bd1cdf..0cfe317 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2821,11 +2821,11 @@ To avoid this issue, disable WRED on the affected nodes or upgrade to a release This bug [CSCwt78235][71] validates `F0467` faults where `changeSet` contains 'bgpProt-policy-already-existing'. The fault indicates conflicting BGP protocol timer policy under an L3Outs deployed in same vrf under same node. If this fault is not resolved, l3out will not be programmed properly in the leaf after the clean reboot or the upgrade. -#### Infravlan Overlap Access Policy Check +### Infravlan Overlap Access Policy Check Due to [CSCwt58626][74], when targeting APIC version 6.1(3f) to 6.1(5e) or 6.2(1g) , if the InfraVLAN overlaps with any user-configured VLAN pool range in Access Policies, fault `F4701` is raised for VLAN pools that include the InfraVLAN. After the upgrade, domains linked to those VLAN pools cannot be associated with new EPGs, although existing EPGs continue to function. -To avoid this issue, modify user VLAN pool ranges so that the InfraVLAN does not overlap with any configured block or select the fixed version as a target release. +To avoid this issue, modify user VLAN pool ranges so that the InfraVLAN does not overlap with any configured block or select target version with fix. [0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_empty.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_empty.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json index ca6c6cb..823d709 100644 --- a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json +++ b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_no_overlap.json @@ -4,7 +4,16 @@ "attributes": { "from": "vlan-200", "to": "vlan-300", - "dn": "uni/infra/vlanns-[vlan_pool]-static/from-[vlan-200]-to-[vlan-300]" + "dn": "uni/infra/vlanns-[vlan_pool1]-static/from-[vlan-200]-to-[vlan-300]" + } + } + }, + { + "fvnsEncapBlk": { + "attributes": { + "from": "vlan-500", + "to": "vlan-1000", + "dn": "uni/infra/vlanns-[vlan_pool2]-static/from-[vlan-500]-to-[vlan-1000]" } } } diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_multiple_vlan_pool.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_multiple_vlan_pool.json new file mode 100644 index 0000000..c6fdd17 --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_multiple_vlan_pool.json @@ -0,0 +1,20 @@ +[ + { + "fvnsEncapBlk": { + "attributes": { + "from": "vlan-100", + "to": "vlan-4094", + "dn": "uni/infra/vlanns-[vlan_pool1]-static/from-[vlan-100]-to-[vlan-4094]" + } + } + }, + { + "fvnsEncapBlk": { + "attributes": { + "from": "vlan-4000", + "to": "vlan-4094", + "dn": "uni/infra/vlanns-[vlan_pool2]-static/from-[vlan-4000]-to-[vlan-4094]" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json b/tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_single_vlan_pool.json similarity index 100% rename from tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap.json rename to tests/checks/infravlan_overlap_access_policy_check/fvnsEncapBlk_overlap_single_vlan_pool.json diff --git a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_empty.json b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_empty.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_empty.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json deleted file mode 100644 index a76980e..0000000 --- a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "lldpInst": { - "attributes": { - "adminSt": "enabled", - "infraVlan": "vlan-4093" - } - } - } -] diff --git a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_multiple_entry.json b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_multiple_entry.json new file mode 100644 index 0000000..6a1bb8f --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_multiple_entry.json @@ -0,0 +1,102 @@ +[ + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-201/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-201" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-202/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-202" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-203/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-203" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-204/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-204" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-205/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-205" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-206/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-206" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-207/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-207" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-208/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-208" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-209/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-209" + } + } + }, + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-210/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-210" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_single_entry.json b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_single_entry.json new file mode 100644 index 0000000..5b14d8d --- /dev/null +++ b/tests/checks/infravlan_overlap_access_policy_check/lldpInst_infra_vlan_single_entry.json @@ -0,0 +1,12 @@ +[ + { + "lldpInst": { + "attributes": { + "adminSt": "enabled", + "dn": "topology/pod-1/node-201/sys/lldp/inst", + "infraVlan": "vlan-4093", + "sysDesc": "topology/pod-1/node-201" + } + } + } +] diff --git a/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py b/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py index 30795da..c268c9b 100644 --- a/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py +++ b/tests/checks/infravlan_overlap_access_policy_check/test_infravlan_overlap_access_policy_check.py @@ -17,49 +17,135 @@ @pytest.mark.parametrize( - "icurl_outputs, tversion, expected_result", + "icurl_outputs, tversion, expected_result, expected_data", [ - # Case 1 : infraVlan overlapping in user configured vlan pool range + # Case 1: tversion missing. Expected: MANUAL. + ( + {}, + None, + script.MANUAL, + [], + ), + # Case 2: Version not affected (6.0(9f) is below 6.1(3f)). Expected: NA. + ( + {}, + "6.0(9f)", + script.NA, + [], + ), + # Case 3: Version not affected (6.1(3e) is just below lower boundary 6.1(3f)). Expected: NA. + ( + {}, + "6.1(3e)", + script.NA, + [], + ), + # Case 4: Version not affected (6.1(6a) is above upper boundary 6.1(5e) and not 6.2(1g)). Expected: NA. + ( + {}, + "6.1(6a)", + script.NA, + [], + ), + # Case 5: lldpInst returns no data so infraVlan cannot be determined. Expected: NA. + ( + { + lldpInst_api: read_data(dir, "lldpInst_empty.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), + }, + "6.2(1g)", + script.NA, + [], + ), + # Case 6: InfraVLAN overlaps on lower boundary version 6.1(3f). Expected: FAIL_O. + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), + }, + "6.1(3f)", + script.FAIL_O, + [["4093", "vlan_pool", "vlan-100 to vlan-4094"]], + ), + # Case 7: InfraVLAN overlaps on a mid-range version 6.1(4a). Expected: FAIL_O. ( { - lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), - fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), + }, + "6.1(4a)", + script.FAIL_O, + [["4093", "vlan_pool", "vlan-100 to vlan-4094"]], + ), + # Case 8: InfraVLAN overlaps on upper boundary version 6.1(5e). Expected: FAIL_O. + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), + }, + "6.1(5e)", + script.FAIL_O, + [["4093", "vlan_pool", "vlan-100 to vlan-4094"]], + ), + # Case 9: InfraVLAN overlaps on standalone affected version 6.2(1g). Expected: FAIL_O. + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), }, "6.2(1g)", script.FAIL_O, + [["4093", "vlan_pool", "vlan-100 to vlan-4094"]], ), - # Case 2 : infraVlan not overlapping in user configured vlan pool range + # Case 10: InfraVLAN does not overlap on affected version 6.2(1g). Expected: PASS. ( { - lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_no_overlap.json"), }, "6.2(1g)", script.PASS, + [], ), - # case 3 : version not impacting the check, so result should be NA + # Case 11: Single lldpInst entry with overlap on affected version 6.2(1g). Expected: FAIL_O. ( { - lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), - fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_single_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_single_vlan_pool.json"), }, - "6.0(9f)", - script.NA, + "6.2(1g)", + script.FAIL_O, + [["4093", "vlan_pool", "vlan-100 to vlan-4094"]], ), - # case 3 : tversion missing check + # Case 12: InfraVLAN overlaps on multiple vlan pools on standalone affected version 6.2(1g). Expected: FAIL_O. ( { - lldpInst_api: read_data(dir, "lldpInst_infra_vlan.json"), - fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap.json"), + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_overlap_multiple_vlan_pool.json"), }, - None, - script.MANUAL, + "6.2(1g)", + script.FAIL_O, + [ + ["4093", "vlan_pool1", "vlan-100 to vlan-4094"], + ["4093", "vlan_pool2", "vlan-4000 to vlan-4094"], + ], + ), + # Case 13: InfraVLAN exists and empty fvnsEncapBlk for vlan pools on standalone affected version 6.2(1g). Expected: PASS. + ( + { + lldpInst_api: read_data(dir, "lldpInst_infra_vlan_multiple_entry.json"), + fvnsEncapBlk_api: read_data(dir, "fvnsEncapBlk_empty.json"), + }, + "6.2(1g)", + script.PASS, + [], ), ], ) -def test_logic(run_check, mock_icurl, tversion, expected_result): - result = run_check(tversion=script.AciVersion(tversion)if tversion else None) +def test_logic(run_check, mock_icurl, tversion, expected_result, expected_data): + result = run_check(tversion=script.AciVersion(tversion) if tversion else None) assert result.result == expected_result - + assert result.data == expected_data + From 1dad1ef893c4031c1ce7e000b58798b40a3e9ffd Mon Sep 17 00:00:00 2001 From: muthuku Date: Fri, 3 Jul 2026 07:09:26 +0000 Subject: [PATCH 3/4] updated merge conflict --- aci-preupgrade-validation-script.py | 92 +---------------------------- 1 file changed, 1 insertion(+), 91 deletions(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 7e53909..b1a9a73 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6702,94 +6702,6 @@ def stale_dbgacEpgSummaryTask_check(tversion, **kwargs): return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) -@check_wrapper(check_title='N9K-C93180YC-FX3 Switch Memory Less Than 32GB') -def n9k_c93180yc_fx3_switch_memory_check(fabric_nodes, **kwargs): - result = PASS - headers = ["NodeId", "Name", "Model", "Memory Detected (GB)"] - data = [] - recommended_action = 'Increase the switch memory to at least 32GB on affected N9K-C93180YC-FX3.' - doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#n9k-c93180yc-fx3-switch-memory-less-than-32gb' - min_memory_kb = 32 * 1000 * 1000 - msg = '' - - affected_nodes = [ - node for node in fabric_nodes - if node['fabricNode']['attributes']['model'] == 'N9K-C93180YC-FX3' - ] - - if not affected_nodes: - result = NA - msg = 'No N9K-C93180YC-FX3 switches found. Skipping.' - else: - node_ids = [node['fabricNode']['attributes']['id'] for node in affected_nodes] - node_filter = 'or({})'.format(','.join( - 'wcard(procMemUsage.dn,"node-{}/")'.format(nid) for nid in node_ids - )) - query = 'procMemUsage.json?query-target-filter=and({},wcard(procMemUsage.dn,"memusage-sup"),lt(procMemUsage.Total,"{}"))'.format( - node_filter, min_memory_kb - ) - proc_mem_mos = icurl('class', query) - - node_id_to_attrs = { - node['fabricNode']['attributes']['id']: node['fabricNode']['attributes'] - for node in affected_nodes - } - - for memory_mo in proc_mem_mos: - attrs = memory_mo['procMemUsage']['attributes'] - dn_match = re.search(node_regex, attrs['dn']) - if not dn_match: - continue - node_id = dn_match.group('node') - if node_id not in node_id_to_attrs: - continue - memory_in_gb = round(int(attrs['Total']) / 1000000, 2) - result = FAIL_O - data.append([ - node_id, - node_id_to_attrs[node_id]['name'], - node_id_to_attrs[node_id]['model'], - memory_in_gb, - ]) - - if data: - msg = ( - 'N9K-C93180YC-FX3 requires a minimum of 32GB RAM for proper operation in ACI mode. ' - 'One or more switches with less than 32GB of memory may experience service instability. ' - 'Upgrade the switch memory to at least 32GB.' - ) - - return Result(result=result, msg=msg, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) - - -@check_wrapper(check_title="Stale dbgacEpgSummaryTask Objects") -def stale_dbgacEpgSummaryTask_check(tversion, **kwargs): - result = PASS - headers = ["DN", "Start Time"] - data = [] - recommended_action = "Contact Cisco TAC for next steps. For more details, refer to the workaround in [CSCwt69100](https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt69100)." - doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#stale-dbgacepgsummarytask-objects" - - if tversion and ((tversion.major1 == "6" and tversion.major2 == "1" and tversion.newer_than("6.1(5e)")) or tversion.newer_than("6.2(1g)")): - return Result(result=NA, msg=VER_NOT_AFFECTED, doc_url=doc_url) - - threshold = datetime.utcnow() - timedelta(hours=24) - for obj in icurl("class", 'dbgacEpgSummaryTask.json?query-target-filter=eq(dbgacEpgSummaryTask.operSt,"processing")'): - attr = obj["dbgacEpgSummaryTask"]["attributes"] - dn = attr.get("dn", "") - start_ts = attr.get("startTs", "") - try: - task_dt = datetime.strptime(start_ts[:19], "%Y-%m-%dT%H:%M:%S") - except ValueError: - continue - if task_dt < threshold: - data.append([dn, start_ts]) - - if data: - result = FAIL_UF - return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) - - @check_wrapper(check_title="InfraVLAN Overlap in Access Policy VLAN Pools") def infravlan_overlap_access_policy_check(tversion, **kwargs): result = PASS @@ -7022,12 +6934,10 @@ class CheckManager: inband_management_policy_misconfig_check, bgpProto_timer_policy_already_existing_check, wred_affected_model_check, - n9k_c93180yc_fx3_switch_memory_check, - stale_dbgacEpgSummaryTask_check, - n9k_c93180yc_fx3_switch_memory_check, stale_dbgacEpgSummaryTask_check, infravlan_overlap_access_policy_check, + ] ssh_checks = [ # General From bb531b5b14bcd520d275e4393ed645a957862cd7 Mon Sep 17 00:00:00 2001 From: muthuku Date: Fri, 3 Jul 2026 10:20:08 +0000 Subject: [PATCH 4/4] updated missing import for stale_dbgacEpgSummaryTask_check --- aci-preupgrade-validation-script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index b1a9a73..c36d7ba 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -22,7 +22,7 @@ from textwrap import TextWrapper from getpass import getpass from collections import defaultdict, OrderedDict -from datetime import datetime +from datetime import datetime, timedelta from argparse import ArgumentParser from itertools import chain import threading