From 4ba163bed99f7b53050f44afd6951e294b624995 Mon Sep 17 00:00:00 2001 From: GM Date: Fri, 27 Feb 2026 11:11:20 -0500 Subject: [PATCH 01/16] 353 the script incorrectly detects vpc and port channel interfaces as cscwh68103 invalid fabricpathep targets (#357) * specific testing for known failure conditions of cscwh68103 as to not catch valid scenarios --- aci-preupgrade-validation-script.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index ae19670..dfa8fba 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -4824,6 +4824,7 @@ def fabricPathEp_target_check(**kwargs): fex_a = groups.get("fexA") fex_b = groups.get("fexB") path = groups.get("path") + print(path) # CHECK FEX ID(s) of extpath(s) is 101 or greater if fex_a: From 1595695c744f4576912430be5bed4129896aff2d Mon Sep 17 00:00:00 2001 From: Gabriel Date: Fri, 27 Feb 2026 13:45:22 -0500 Subject: [PATCH 02/16] print cleanup --- aci-preupgrade-validation-script.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index dfa8fba..ae19670 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -4824,7 +4824,6 @@ def fabricPathEp_target_check(**kwargs): fex_a = groups.get("fexA") fex_b = groups.get("fexB") path = groups.get("path") - print(path) # CHECK FEX ID(s) of extpath(s) is 101 or greater if fex_a: From 7d7e263c04d5f9833d29e5d056f3cf73471dc6ed Mon Sep 17 00:00:00 2001 From: Priyanka Date: Thu, 9 Apr 2026 19:53:28 +0530 Subject: [PATCH 03/16] Added WRED with affected Leaf/LC/FM model check --- aci-preupgrade-validation-script.py | 109 ++++++++++++++++- .../test_wred_affected_model_check.py | 113 ++++++++++++++++++ 2 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 tests/checks/wred_affected_model_check/test_wred_affected_model_check.py diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index ae19670..bd090a2 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6459,7 +6459,113 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): return Result(result=result, headers=headers, data=data, unformatted_headers=unformatted_headers, unformatted_data=unformatted_data, recommended_action=recommended_action, doc_url=doc_url) -# ---- Script Execution ----. +@check_wrapper(check_title='WRED with Affected Leaf/LC/FM Models') +def wred_affected_model_check(tversion, fabric_nodes, **kwargs): + result = PASS + headers = ["Node ID", "Node Name", "Source", "Model"] + data = [] + recommended_action = ( + 'Detected affected node(s) with WRED enabled. ' + 'Review software fix options and engage TAC.' + ) + doc_url = 'https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt50713' + + if not tversion: + return Result(result=MANUAL, msg=TVER_MISSING) + + version_affected = ( + (tversion.major1 == '6' and tversion.major2 == '1' and tversion.older_than('6.1(6a)')) + or (tversion.major1 == '6' and tversion.major2 == '2' and tversion.older_than('6.2(2a)')) + ) + if not version_affected: + return Result(result=PASS, msg=VER_NOT_AFFECTED) + + qosCong = icurl('class', 'qosCong.json') + wred_enabled = False + for cong in qosCong: + algo = cong.get('qosCong', {}).get('attributes', {}).get('algo', '') + if algo.lower() == 'wred': + wred_enabled = True + break + + if not wred_enabled: + return Result(result=PASS, msg='WRED not enabled. Skipping.') + + affected_models = { + 'N9K-C9236C', + 'N9K-C92300YC', + 'N9K-C9272Q', + 'N9K-C92304QC', + 'N9K-C9504-FM-E', + 'N9K-C9508-FM-E', + 'N9K-C9516-FM-E', + } + + def is_affected_model(model): + m = (model or '').upper() + return m in affected_models or 'LACROSSE' in m + + node_name_map = {} + for node in fabric_nodes: + attr = node.get('fabricNode', {}).get('attributes', {}) + if attr.get('id'): + node_name_map[attr.get('id')] = attr.get('name', '') + + impacted = set() + + # Leaf model gate + for node in fabric_nodes: + attr = node.get('fabricNode', {}).get('attributes', {}) + if attr.get('role') != 'leaf': + continue + model = attr.get('model', '') + if is_affected_model(model): + impacted.add((attr.get('id', ''), attr.get('name', ''), 'Leaf', model)) + + # LC model gate + eqptLC = icurl('class', 'eqptLC.json') + for card in eqptLC: + attr = card.get('eqptLC', {}).get('attributes', {}) + model = attr.get('model', '') + if not is_affected_model(model): + continue + dn = attr.get('dn', '') + m = re.search(node_regex, dn) + if not m: + continue + node_id = m.group('node') + impacted.add((node_id, node_name_map.get(node_id, ''), 'LC', model)) + + # FM model gate + eqptFC = icurl('class', 'eqptFC.json') + for card in eqptFC: + attr = card.get('eqptFC', {}).get('attributes', {}) + model = attr.get('model', '') + if not is_affected_model(model): + continue + dn = attr.get('dn', '') + m = re.search(node_regex, dn) + if not m: + continue + node_id = m.group('node') + impacted.add((node_id, node_name_map.get(node_id, ''), 'FM', model)) + + if impacted: + def sort_key(row): + node_id = row[0] + try: + node_key = int(node_id) + except (TypeError, ValueError): + node_key = node_id + return (node_key, row[2], row[3]) + + data = [list(row) for row in sorted(impacted, key=sort_key)] + result = FAIL_O + + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + +# ---- Script Execution ---- def parse_args(args): @@ -6643,6 +6749,7 @@ class CheckManager: # Bugs observer_db_size_check, multipod_modular_spine_bootscript_check, + wred_affected_model_check, ] cli_checks = [ # General diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py new file mode 100644 index 0000000..58ba098 --- /dev/null +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -0,0 +1,113 @@ +import pytest +import importlib + +script = importlib.import_module("aci-preupgrade-validation-script") + +test_function = "wred_affected_model_check" + + +def _node(node_id, name, role, model): + return { + "fabricNode": { + "attributes": { + "id": str(node_id), + "name": name, + "role": role, + "model": model, + "dn": "topology/pod-1/node-{}".format(node_id), + } + } + } + + +@pytest.mark.parametrize( + "tversion, fabric_nodes, icurl_outputs, expected_result, expected_data", + [ + ( + None, + [_node(101, "leaf101", "leaf", "N9K-C9236C")], + {}, + script.MANUAL, + [], + ), + ( + "6.2(2a)", + [_node(101, "leaf101", "leaf", "N9K-C9236C")], + {}, + script.PASS, + [], + ), + ( + "6.1(5e)", + [_node(101, "leaf101", "leaf", "N9K-C9236C")], + { + "qosCong.json": [ + {"qosCong": {"attributes": {"algo": "wred"}}}, + ], + "eqptLC.json": [], + "eqptFC.json": [], + }, + script.FAIL_O, + [["101", "leaf101", "Leaf", "N9K-C9236C"]], + ), + ( + "6.2(1f)", + [ + _node(1001, "spine1001", "spine", "N9K-C9504"), + ], + { + "qosCong.json": [ + {"qosCong": {"attributes": {"algo": "tail-drop"}}}, + {"qosCong": {"attributes": {"algo": "wred"}}}, + ], + "eqptLC.json": [ + { + "eqptLC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/lcslot-1/lc", + "model": "N9K-C92304QC", + } + } + } + ], + "eqptFC.json": [ + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-1/fc", + "model": "N9K-C9508-FM-E", + } + } + } + ], + }, + script.FAIL_O, + [ + ["1001", "spine1001", "FM", "N9K-C9508-FM-E"], + ["1001", "spine1001", "LC", "N9K-C92304QC"], + ], + ), + ( + "6.1(5e)", + [_node(101, "leaf101", "leaf", "N9K-C9236C")], + { + "qosCong.json": [ + {"qosCong": {"attributes": {"algo": "tail-drop"}}}, + ], + "eqptLC.json": [], + "eqptFC.json": [], + }, + script.PASS, + [], + ), + ], +) +def test_logic(run_check, mock_icurl, tversion, fabric_nodes, expected_result, expected_data): + kwargs = { + "tversion": script.AciVersion(tversion) if tversion else None, + "fabric_nodes": fabric_nodes, + } + + result = run_check(**kwargs) + assert result.result == expected_result + assert result.data == expected_data From 6468f96e5dffcca8e59a7ebc7288595450227f52 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Mon, 13 Apr 2026 12:55:37 +0530 Subject: [PATCH 04/16] Addressed PR review comments --- aci-preupgrade-validation-script.py | 91 +++++++--------- docs/docs/validations.md | 13 +++ .../eqptFC_affected.json | 10 ++ .../eqptFC_empty.json | 1 + .../eqptLC_affected.json | 10 ++ .../eqptLC_empty.json | 1 + .../fabricNode_leaf_affected.json | 13 +++ .../fabricNode_spine.json | 13 +++ .../qosCong_mixed.json | 16 +++ .../qosCong_tail_drop.json | 9 ++ .../qosCong_wred.json | 9 ++ .../test_wred_affected_model_check.py | 102 +++++++----------- 12 files changed, 175 insertions(+), 113 deletions(-) create mode 100644 tests/checks/wred_affected_model_check/eqptFC_affected.json create mode 100644 tests/checks/wred_affected_model_check/eqptFC_empty.json create mode 100644 tests/checks/wred_affected_model_check/eqptLC_affected.json create mode 100644 tests/checks/wred_affected_model_check/eqptLC_empty.json create mode 100644 tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json create mode 100644 tests/checks/wred_affected_model_check/fabricNode_spine.json create mode 100644 tests/checks/wred_affected_model_check/qosCong_mixed.json create mode 100644 tests/checks/wred_affected_model_check/qosCong_tail_drop.json create mode 100644 tests/checks/wred_affected_model_check/qosCong_wred.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index bd090a2..11f7e3e 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6464,32 +6464,18 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): result = PASS headers = ["Node ID", "Node Name", "Source", "Model"] data = [] - recommended_action = ( - 'Detected affected node(s) with WRED enabled. ' - 'Review software fix options and engage TAC.' - ) - doc_url = 'https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt50713' + recommended_action = 'Disable WRED on the affected nodes or move to a fixed release (6.1(6a) or later, 6.2(2a) or later).' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-leaflcfm-models' if not tversion: return Result(result=MANUAL, msg=TVER_MISSING) version_affected = ( - (tversion.major1 == '6' and tversion.major2 == '1' and tversion.older_than('6.1(6a)')) - or (tversion.major1 == '6' and tversion.major2 == '2' and tversion.older_than('6.2(2a)')) + (tversion.major1 == '6' and tversion.major2 == '1' and (tversion.older_than('6.1(5e)') or tversion.same_as('6.1(5e)'))) + or (tversion.major1 == '6' and tversion.major2 == '2' and (tversion.older_than('6.2(1g)') or tversion.same_as('6.2(1g)'))) ) if not version_affected: - return Result(result=PASS, msg=VER_NOT_AFFECTED) - - qosCong = icurl('class', 'qosCong.json') - wred_enabled = False - for cong in qosCong: - algo = cong.get('qosCong', {}).get('attributes', {}).get('algo', '') - if algo.lower() == 'wred': - wred_enabled = True - break - - if not wred_enabled: - return Result(result=PASS, msg='WRED not enabled. Skipping.') + return Result(result=NA, msg=VER_NOT_AFFECTED) affected_models = { 'N9K-C9236C', @@ -6502,53 +6488,54 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): } def is_affected_model(model): - m = (model or '').upper() - return m in affected_models or 'LACROSSE' in m + return model in affected_models or 'LACROSSE' in (model or '') node_name_map = {} for node in fabric_nodes: - attr = node.get('fabricNode', {}).get('attributes', {}) - if attr.get('id'): - node_name_map[attr.get('id')] = attr.get('name', '') + node_id = node['fabricNode']['attributes']['id'] + node_name_map[node_id] = node['fabricNode']['attributes']['name'] impacted = set() + def add_if_affected(obj_class, obj_list, source_label): + for obj in obj_list: + model = obj[obj_class]['attributes']['model'] + if not is_affected_model(model): + continue + dn = obj[obj_class]['attributes']['dn'] + dn_match = re.search(node_regex, dn) + if not dn_match: + continue + node_id = dn_match.group('node') + impacted.add((node_id, node_name_map.get(node_id, ''), source_label, model)) + # Leaf model gate for node in fabric_nodes: - attr = node.get('fabricNode', {}).get('attributes', {}) - if attr.get('role') != 'leaf': + if node['fabricNode']['attributes']['role'] != 'leaf': continue - model = attr.get('model', '') + model = node['fabricNode']['attributes']['model'] if is_affected_model(model): - impacted.add((attr.get('id', ''), attr.get('name', ''), 'Leaf', model)) + impacted.add((node['fabricNode']['attributes']['id'], node['fabricNode']['attributes']['name'], 'Leaf', model)) # LC model gate - eqptLC = icurl('class', 'eqptLC.json') - for card in eqptLC: - attr = card.get('eqptLC', {}).get('attributes', {}) - model = attr.get('model', '') - if not is_affected_model(model): - continue - dn = attr.get('dn', '') - m = re.search(node_regex, dn) - if not m: - continue - node_id = m.group('node') - impacted.add((node_id, node_name_map.get(node_id, ''), 'LC', model)) + add_if_affected('eqptLC', icurl('class', 'eqptLC.json'), 'LC') # FM model gate - eqptFC = icurl('class', 'eqptFC.json') - for card in eqptFC: - attr = card.get('eqptFC', {}).get('attributes', {}) - model = attr.get('model', '') - if not is_affected_model(model): - continue - dn = attr.get('dn', '') - m = re.search(node_regex, dn) - if not m: - continue - node_id = m.group('node') - impacted.add((node_id, node_name_map.get(node_id, ''), 'FM', model)) + add_if_affected('eqptFC', icurl('class', 'eqptFC.json'), 'FM') + + if not impacted: + return Result(result=PASS, msg='No affected hardware models found. Skipping.') + + qosCong = icurl('class', 'qosCong.json') + wred_enabled = False + for cong in qosCong: + algo = cong.get('qosCong', {}).get('attributes', {}).get('algo', '') + if algo == 'wred': + wred_enabled = True + break + + if not wred_enabled: + return Result(result=PASS, msg='WRED not enabled. Skipping.') if impacted: def sort_key(row): diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 807c5ab..e318fd2 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -204,6 +204,7 @@ Items | Defect | This Script [Multi-Pod Modular Spine Bootscript File][d32] | CSCwr66848 | :white_check_mark: | :no_entry_sign: [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: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -239,6 +240,7 @@ Items | Defect | This Script [d32]: #multi-pod-modular-spine-bootscript-file [d33]: #inband-management-policy-misconfiguration [d34]: #bgpProto-timer-policy-already-existing +[d35]: #wred-with-affected-fm-models ## General Check Details @@ -2797,6 +2799,16 @@ Administrators may be unable to access or operate the APIC GUI, potentially impa This check will verify the count of the `svccoreCtrlr` Managed Object and raise and alarm with the bug if object count found more than 240. Remove the content or objects of `svccoreCtrlr` or `svccoreNode`. Contact Cisco TAC or upgrade to a release containing the fix for CSCws84232 before proceeding with an upgrade. +### WRED with Affected Leaf/LC/FM Models + +Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Leaf, Line Card (LC), or Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. + +Affected versions: ACI 6.1(x) older than 6.1(6a), and ACI 6.2(x) older than 6.2(2a). + +Affected hardware models: N9K-C9236C, N9K-C92300YC, N9K-C9272Q, N9K-C92304QC (Leaf/LC), N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E (FM). + +To avoid this issue, disable WRED on the affected nodes or move to a fixed release (6.1(6a) or later, 6.2(2a) or later). + ### BgpProto Timer Policy Already Existing @@ -2875,3 +2887,4 @@ This bug [CSCwt78235][71] validates `F0467` faults where `changeSet` contains 'b [69]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCws84232 [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 diff --git a/tests/checks/wred_affected_model_check/eqptFC_affected.json b/tests/checks/wred_affected_model_check/eqptFC_affected.json new file mode 100644 index 0000000..4e87550 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptFC_affected.json @@ -0,0 +1,10 @@ +[ + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-1/fc", + "model": "N9K-C9508-FM-E" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/eqptFC_empty.json b/tests/checks/wred_affected_model_check/eqptFC_empty.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptFC_empty.json @@ -0,0 +1 @@ +[] diff --git a/tests/checks/wred_affected_model_check/eqptLC_affected.json b/tests/checks/wred_affected_model_check/eqptLC_affected.json new file mode 100644 index 0000000..819f6d6 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptLC_affected.json @@ -0,0 +1,10 @@ +[ + { + "eqptLC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/lcslot-1/lc", + "model": "N9K-C92304QC" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/eqptLC_empty.json b/tests/checks/wred_affected_model_check/eqptLC_empty.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptLC_empty.json @@ -0,0 +1 @@ +[] diff --git a/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json b/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json new file mode 100644 index 0000000..53a02c4 --- /dev/null +++ b/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json @@ -0,0 +1,13 @@ +[ + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-101", + "id": "101", + "name": "leaf101", + "role": "leaf", + "model": "N9K-C9236C" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/fabricNode_spine.json b/tests/checks/wred_affected_model_check/fabricNode_spine.json new file mode 100644 index 0000000..c70eb8f --- /dev/null +++ b/tests/checks/wred_affected_model_check/fabricNode_spine.json @@ -0,0 +1,13 @@ +[ + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-1001", + "id": "1001", + "name": "spine1001", + "role": "spine", + "model": "N9K-C9504" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/qosCong_mixed.json b/tests/checks/wred_affected_model_check/qosCong_mixed.json new file mode 100644 index 0000000..cb3a900 --- /dev/null +++ b/tests/checks/wred_affected_model_check/qosCong_mixed.json @@ -0,0 +1,16 @@ +[ + { + "qosCong": { + "attributes": { + "algo": "tail-drop" + } + } + }, + { + "qosCong": { + "attributes": { + "algo": "wred" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/qosCong_tail_drop.json b/tests/checks/wred_affected_model_check/qosCong_tail_drop.json new file mode 100644 index 0000000..dd814ec --- /dev/null +++ b/tests/checks/wred_affected_model_check/qosCong_tail_drop.json @@ -0,0 +1,9 @@ +[ + { + "qosCong": { + "attributes": { + "algo": "tail-drop" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/qosCong_wred.json b/tests/checks/wred_affected_model_check/qosCong_wred.json new file mode 100644 index 0000000..1c297c8 --- /dev/null +++ b/tests/checks/wred_affected_model_check/qosCong_wred.json @@ -0,0 +1,9 @@ +[ + { + "qosCong": { + "attributes": { + "algo": "wred" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index 58ba098..a62ac16 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -1,85 +1,67 @@ +import os import pytest import importlib +from helpers.utils import read_data script = importlib.import_module("aci-preupgrade-validation-script") -test_function = "wred_affected_model_check" +dir = os.path.dirname(os.path.abspath(__file__)) +test_function = "wred_affected_model_check" -def _node(node_id, name, role, model): - return { - "fabricNode": { - "attributes": { - "id": str(node_id), - "name": name, - "role": role, - "model": model, - "dn": "topology/pod-1/node-{}".format(node_id), - } - } - } +# icurl queries +qosCong_api = "qosCong.json" +eqptLC_api = "eqptLC.json" +eqptFC_api = "eqptFC.json" @pytest.mark.parametrize( "tversion, fabric_nodes, icurl_outputs, expected_result, expected_data", [ + # Case 1: No target version provided (-t flag missing). + # Check cannot determine version gate. Expected: MANUAL CHECK REQUIRED. ( None, - [_node(101, "leaf101", "leaf", "N9K-C9236C")], + read_data(dir, "fabricNode_leaf_affected.json"), {}, script.MANUAL, [], ), + # Case 2: Target version 6.2(2a) is the first fixed release and not in the affected range. + # Version gate fails. Expected: NA without any API calls. ( "6.2(2a)", - [_node(101, "leaf101", "leaf", "N9K-C9236C")], + read_data(dir, "fabricNode_leaf_affected.json"), {}, - script.PASS, + script.NA, [], ), + # Case 3: All 3 gates triggered via an affected leaf node. + # Version 6.1(5e) is in affected range, WRED is enabled, leaf model N9K-C9236C is affected. + # Expected: FAIL_O with node 101 reported under Source=Leaf. ( "6.1(5e)", - [_node(101, "leaf101", "leaf", "N9K-C9236C")], + read_data(dir, "fabricNode_leaf_affected.json"), { - "qosCong.json": [ - {"qosCong": {"attributes": {"algo": "wred"}}}, - ], - "eqptLC.json": [], - "eqptFC.json": [], + qosCong_api: read_data(dir, "qosCong_wred.json"), + eqptLC_api: read_data(dir, "eqptLC_empty.json"), + eqptFC_api: read_data(dir, "eqptFC_empty.json"), }, script.FAIL_O, [["101", "leaf101", "Leaf", "N9K-C9236C"]], ), + # Case 4: All 3 gates triggered via affected LC and FM on a spine node. + # Version 6.2(1f) is in affected range. Spine itself is not an affected leaf model, + # but it has an affected Line Card (N9K-C92304QC) and Fabric Module (N9K-C9508-FM-E). + # Multiple QoS policies exist (one tail-drop, one wred) - WRED gate still triggers. + # Expected: FAIL_O with both FM and LC rows reported for node 1001. ( "6.2(1f)", - [ - _node(1001, "spine1001", "spine", "N9K-C9504"), - ], + read_data(dir, "fabricNode_spine.json"), { - "qosCong.json": [ - {"qosCong": {"attributes": {"algo": "tail-drop"}}}, - {"qosCong": {"attributes": {"algo": "wred"}}}, - ], - "eqptLC.json": [ - { - "eqptLC": { - "attributes": { - "dn": "topology/pod-1/node-1001/sys/ch/lcslot-1/lc", - "model": "N9K-C92304QC", - } - } - } - ], - "eqptFC.json": [ - { - "eqptFC": { - "attributes": { - "dn": "topology/pod-1/node-1001/sys/ch/fcslot-1/fc", - "model": "N9K-C9508-FM-E", - } - } - } - ], + qosCong_api: read_data(dir, "qosCong_mixed.json"), + eqptLC_api: read_data(dir, "eqptLC_affected.json"), + eqptFC_api: read_data(dir, "eqptFC_affected.json"), }, script.FAIL_O, [ @@ -87,15 +69,15 @@ def _node(node_id, name, role, model): ["1001", "spine1001", "LC", "N9K-C92304QC"], ], ), + # Case 5: Version is affected and leaf model is affected, but WRED is not enabled (tail-drop). + # WRED gate fails. Expected: PASS - confirms all 3 gates must be true simultaneously. ( "6.1(5e)", - [_node(101, "leaf101", "leaf", "N9K-C9236C")], + read_data(dir, "fabricNode_leaf_affected.json"), { - "qosCong.json": [ - {"qosCong": {"attributes": {"algo": "tail-drop"}}}, - ], - "eqptLC.json": [], - "eqptFC.json": [], + qosCong_api: read_data(dir, "qosCong_tail_drop.json"), + eqptLC_api: read_data(dir, "eqptLC_empty.json"), + eqptFC_api: read_data(dir, "eqptFC_empty.json"), }, script.PASS, [], @@ -103,11 +85,9 @@ def _node(node_id, name, role, model): ], ) def test_logic(run_check, mock_icurl, tversion, fabric_nodes, expected_result, expected_data): - kwargs = { - "tversion": script.AciVersion(tversion) if tversion else None, - "fabric_nodes": fabric_nodes, - } - - result = run_check(**kwargs) + result = run_check( + tversion=script.AciVersion(tversion) if tversion else None, + fabric_nodes=fabric_nodes, + ) assert result.result == expected_result assert result.data == expected_data From b98e8829c7cb49551cca1547115fd1ce8b01caeb Mon Sep 17 00:00:00 2001 From: Priyanka Date: Wed, 15 Apr 2026 17:09:52 +0530 Subject: [PATCH 05/16] Addressed PR review comments --- aci-preupgrade-validation-script.py | 66 +++++++------------ docs/docs/validations.md | 11 ++-- .../test_wred_affected_model_check.py | 43 +++++------- 3 files changed, 44 insertions(+), 76 deletions(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 11f7e3e..cf8de35 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6459,13 +6459,13 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): return Result(result=result, headers=headers, data=data, unformatted_headers=unformatted_headers, unformatted_data=unformatted_data, recommended_action=recommended_action, doc_url=doc_url) -@check_wrapper(check_title='WRED with Affected Leaf/LC/FM Models') +@check_wrapper(check_title='WRED with Affected FM Models') def wred_affected_model_check(tversion, fabric_nodes, **kwargs): result = PASS headers = ["Node ID", "Node Name", "Source", "Model"] data = [] - recommended_action = 'Disable WRED on the affected nodes or move to a fixed release (6.1(6a) or later, 6.2(2a) or later).' - doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-leaflcfm-models' + recommended_action = 'Disable WRED on the affected nodes or move to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train.' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-fm-models' if not tversion: return Result(result=MANUAL, msg=TVER_MISSING) @@ -6478,18 +6478,11 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): return Result(result=NA, msg=VER_NOT_AFFECTED) affected_models = { - 'N9K-C9236C', - 'N9K-C92300YC', - 'N9K-C9272Q', - 'N9K-C92304QC', 'N9K-C9504-FM-E', 'N9K-C9508-FM-E', 'N9K-C9516-FM-E', } - def is_affected_model(model): - return model in affected_models or 'LACROSSE' in (model or '') - node_name_map = {} for node in fabric_nodes: node_id = node['fabricNode']['attributes']['id'] @@ -6497,31 +6490,17 @@ def is_affected_model(model): impacted = set() - def add_if_affected(obj_class, obj_list, source_label): - for obj in obj_list: - model = obj[obj_class]['attributes']['model'] - if not is_affected_model(model): - continue - dn = obj[obj_class]['attributes']['dn'] - dn_match = re.search(node_regex, dn) - if not dn_match: - continue - node_id = dn_match.group('node') - impacted.add((node_id, node_name_map.get(node_id, ''), source_label, model)) - - # Leaf model gate - for node in fabric_nodes: - if node['fabricNode']['attributes']['role'] != 'leaf': - continue - model = node['fabricNode']['attributes']['model'] - if is_affected_model(model): - impacted.add((node['fabricNode']['attributes']['id'], node['fabricNode']['attributes']['name'], 'Leaf', model)) - - # LC model gate - add_if_affected('eqptLC', icurl('class', 'eqptLC.json'), 'LC') - # FM model gate - add_if_affected('eqptFC', icurl('class', 'eqptFC.json'), 'FM') + for obj in icurl('class', 'eqptFC.json'): + model = obj['eqptFC']['attributes']['model'] + if model not in affected_models: + continue + dn = obj['eqptFC']['attributes']['dn'] + dn_match = re.search(node_regex, dn) + if not dn_match: + continue + node_id = dn_match.group('node') + impacted.add((node_id, node_name_map.get(node_id, ''), 'FM', model)) if not impacted: return Result(result=PASS, msg='No affected hardware models found. Skipping.') @@ -6537,17 +6516,16 @@ def add_if_affected(obj_class, obj_list, source_label): if not wred_enabled: return Result(result=PASS, msg='WRED not enabled. Skipping.') - if impacted: - def sort_key(row): - node_id = row[0] - try: - node_key = int(node_id) - except (TypeError, ValueError): - node_key = node_id - return (node_key, row[2], row[3]) + def sort_key(row): + node_id = row[0] + try: + node_key = int(node_id) + except (TypeError, ValueError): + node_key = node_id + return (node_key, row[2], row[3]) - data = [list(row) for row in sorted(impacted, key=sort_key)] - result = FAIL_O + data = [list(row) for row in sorted(impacted, key=sort_key)] + result = FAIL_O return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) diff --git a/docs/docs/validations.md b/docs/docs/validations.md index e318fd2..6f70add 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2799,15 +2799,16 @@ Administrators may be unable to access or operate the APIC GUI, potentially impa This check will verify the count of the `svccoreCtrlr` Managed Object and raise and alarm with the bug if object count found more than 240. Remove the content or objects of `svccoreCtrlr` or `svccoreNode`. Contact Cisco TAC or upgrade to a release containing the fix for CSCws84232 before proceeding with an upgrade. -### WRED with Affected Leaf/LC/FM Models -Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Leaf, Line Card (LC), or Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. +### WRED with Affected FM Models -Affected versions: ACI 6.1(x) older than 6.1(6a), and ACI 6.2(x) older than 6.2(2a). +Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. -Affected hardware models: N9K-C9236C, N9K-C92300YC, N9K-C9272Q, N9K-C92304QC (Leaf/LC), N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E (FM). +Affected versions: ACI 6.1(x) up to and including 6.1(5e), and ACI 6.2(x) up to and including 6.2(1g). -To avoid this issue, disable WRED on the affected nodes or move to a fixed release (6.1(6a) or later, 6.2(2a) or later). +Affected hardware models: N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E. + +To avoid this issue, disable WRED on the affected nodes or move to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train. ### BgpProto Timer Policy Already Existing diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index a62ac16..3e3726e 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -11,7 +11,6 @@ # icurl queries qosCong_api = "qosCong.json" -eqptLC_api = "eqptLC.json" eqptFC_api = "eqptFC.json" @@ -36,48 +35,38 @@ script.NA, [], ), - # Case 3: All 3 gates triggered via an affected leaf node. - # Version 6.1(5e) is in affected range, WRED is enabled, leaf model N9K-C9236C is affected. - # Expected: FAIL_O with node 101 reported under Source=Leaf. + # Case 3: All 3 gates triggered via an affected FM on a spine node. + # Version 6.2(1f) is in affected range, WRED is enabled, FM model N9K-C9508-FM-E is affected. + # Expected: FAIL_O with node 1001 reported under Source=FM. ( - "6.1(5e)", - read_data(dir, "fabricNode_leaf_affected.json"), + "6.2(1f)", + read_data(dir, "fabricNode_spine.json"), { qosCong_api: read_data(dir, "qosCong_wred.json"), - eqptLC_api: read_data(dir, "eqptLC_empty.json"), - eqptFC_api: read_data(dir, "eqptFC_empty.json"), + eqptFC_api: read_data(dir, "eqptFC_affected.json"), }, script.FAIL_O, - [["101", "leaf101", "Leaf", "N9K-C9236C"]], + [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], ), - # Case 4: All 3 gates triggered via affected LC and FM on a spine node. - # Version 6.2(1f) is in affected range. Spine itself is not an affected leaf model, - # but it has an affected Line Card (N9K-C92304QC) and Fabric Module (N9K-C9508-FM-E). - # Multiple QoS policies exist (one tail-drop, one wred) - WRED gate still triggers. - # Expected: FAIL_O with both FM and LC rows reported for node 1001. + # Case 4: Version is affected but no affected FM hardware found. + # Hardware gate fails before WRED is checked. Expected: PASS. ( - "6.2(1f)", + "6.1(5e)", read_data(dir, "fabricNode_spine.json"), { - qosCong_api: read_data(dir, "qosCong_mixed.json"), - eqptLC_api: read_data(dir, "eqptLC_affected.json"), - eqptFC_api: read_data(dir, "eqptFC_affected.json"), + eqptFC_api: read_data(dir, "eqptFC_empty.json"), }, - script.FAIL_O, - [ - ["1001", "spine1001", "FM", "N9K-C9508-FM-E"], - ["1001", "spine1001", "LC", "N9K-C92304QC"], - ], + script.PASS, + [], ), - # Case 5: Version is affected and leaf model is affected, but WRED is not enabled (tail-drop). + # Case 5: Version is affected and FM is affected, but WRED is not enabled (tail-drop). # WRED gate fails. Expected: PASS - confirms all 3 gates must be true simultaneously. ( "6.1(5e)", - read_data(dir, "fabricNode_leaf_affected.json"), + read_data(dir, "fabricNode_spine.json"), { qosCong_api: read_data(dir, "qosCong_tail_drop.json"), - eqptLC_api: read_data(dir, "eqptLC_empty.json"), - eqptFC_api: read_data(dir, "eqptFC_empty.json"), + eqptFC_api: read_data(dir, "eqptFC_affected.json"), }, script.PASS, [], From 592b9184dd5b50db75741ddb9fb902be0d82b1d9 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Mon, 20 Apr 2026 10:23:43 +0530 Subject: [PATCH 06/16] Addressed PR review comments and updated the docs --- aci-preupgrade-validation-script.py | 69 +++++++------------ docs/docs/validations.md | 4 +- .../eqptFC_mixed.json | 18 +++++ .../eqptLC_affected.json | 10 --- .../eqptLC_empty.json | 1 - .../fabricNode_leaf_affected.json | 13 ---- .../test_wred_affected_model_check.py | 42 ++++++----- 7 files changed, 67 insertions(+), 90 deletions(-) create mode 100644 tests/checks/wred_affected_model_check/eqptFC_mixed.json delete mode 100644 tests/checks/wred_affected_model_check/eqptLC_affected.json delete mode 100644 tests/checks/wred_affected_model_check/eqptLC_empty.json delete mode 100644 tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index cf8de35..cb096da 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6459,72 +6459,51 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): return Result(result=result, headers=headers, data=data, unformatted_headers=unformatted_headers, unformatted_data=unformatted_data, recommended_action=recommended_action, doc_url=doc_url) -@check_wrapper(check_title='WRED with Affected FM Models') +@check_wrapper(check_title="WRED with Affected FM Models") def wred_affected_model_check(tversion, fabric_nodes, **kwargs): result = PASS headers = ["Node ID", "Node Name", "Source", "Model"] data = [] - recommended_action = 'Disable WRED on the affected nodes or move to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train.' - doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-fm-models' - - if not tversion: - return Result(result=MANUAL, msg=TVER_MISSING) + recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(1g)." + doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-fm-models" version_affected = ( - (tversion.major1 == '6' and tversion.major2 == '1' and (tversion.older_than('6.1(5e)') or tversion.same_as('6.1(5e)'))) - or (tversion.major1 == '6' and tversion.major2 == '2' and (tversion.older_than('6.2(1g)') or tversion.same_as('6.2(1g)'))) + (tversion.major1 == "6" and tversion.major2 == "1" and (tversion.older_than("6.1(5e)") or tversion.same_as("6.1(5e)"))) + or (tversion.major1 == "6" and tversion.major2 == "2" and (tversion.older_than("6.2(1g)") or tversion.same_as("6.2(1g)"))) ) if not version_affected: return Result(result=NA, msg=VER_NOT_AFFECTED) - affected_models = { - 'N9K-C9504-FM-E', - 'N9K-C9508-FM-E', - 'N9K-C9516-FM-E', - } - - node_name_map = {} - for node in fabric_nodes: - node_id = node['fabricNode']['attributes']['id'] - node_name_map[node_id] = node['fabricNode']['attributes']['name'] + affected_models = {"N9K-C9504-FM-E", "N9K-C9508-FM-E", "N9K-C9516-FM-E"} - impacted = set() + node_name_map = { + node["fabricNode"]["attributes"]["id"]: node["fabricNode"]["attributes"]["name"] + for node in fabric_nodes + } # FM model gate - for obj in icurl('class', 'eqptFC.json'): - model = obj['eqptFC']['attributes']['model'] + for obj in icurl("class", "eqptFC.json"): + attr = obj["eqptFC"]["attributes"] + model = attr.get("model", "") if model not in affected_models: continue - dn = obj['eqptFC']['attributes']['dn'] - dn_match = re.search(node_regex, dn) + dn_match = re.search(node_regex, attr.get("dn", "")) if not dn_match: continue - node_id = dn_match.group('node') - impacted.add((node_id, node_name_map.get(node_id, ''), 'FM', model)) - - if not impacted: - return Result(result=PASS, msg='No affected hardware models found. Skipping.') + node_id = dn_match.group("node") + data.append([node_id, node_name_map.get(node_id, ""), "FM", model]) - qosCong = icurl('class', 'qosCong.json') - wred_enabled = False - for cong in qosCong: - algo = cong.get('qosCong', {}).get('attributes', {}).get('algo', '') - if algo == 'wred': - wred_enabled = True - break + if not data: + return Result(result=NA, msg="No affected FM hardware models found.") + wred_enabled = any( + cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred" + for cong in icurl("class", "qosCong.json") + ) if not wred_enabled: - return Result(result=PASS, msg='WRED not enabled. Skipping.') - - def sort_key(row): - node_id = row[0] - try: - node_key = int(node_id) - except (TypeError, ValueError): - node_key = node_id - return (node_key, row[2], row[3]) + return Result(result=PASS, msg="WRED not enabled.") - data = [list(row) for row in sorted(impacted, key=sort_key)] + data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) result = FAIL_O return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 6f70add..7fb38e0 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2804,11 +2804,11 @@ This check will verify the count of the `svccoreCtrlr` Managed Object and raise Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. -Affected versions: ACI 6.1(x) up to and including 6.1(5e), and ACI 6.2(x) up to and including 6.2(1g). +Affected versions: ACI 6.1(5e) and below, and ACI 6.2(1g) and below. Affected hardware models: N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E. -To avoid this issue, disable WRED on the affected nodes or move to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train. +To avoid this issue, disable WRED on the affected nodes or upgrade to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train. ### BgpProto Timer Policy Already Existing diff --git a/tests/checks/wred_affected_model_check/eqptFC_mixed.json b/tests/checks/wred_affected_model_check/eqptFC_mixed.json new file mode 100644 index 0000000..0e346b0 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptFC_mixed.json @@ -0,0 +1,18 @@ +[ + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-1/fc", + "model": "N9K-C9508-FM-E" + } + } + }, + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-2/fc", + "model": "N9K-C9504-FM-G" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/eqptLC_affected.json b/tests/checks/wred_affected_model_check/eqptLC_affected.json deleted file mode 100644 index 819f6d6..0000000 --- a/tests/checks/wred_affected_model_check/eqptLC_affected.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "eqptLC": { - "attributes": { - "dn": "topology/pod-1/node-1001/sys/ch/lcslot-1/lc", - "model": "N9K-C92304QC" - } - } - } -] diff --git a/tests/checks/wred_affected_model_check/eqptLC_empty.json b/tests/checks/wred_affected_model_check/eqptLC_empty.json deleted file mode 100644 index fe51488..0000000 --- a/tests/checks/wred_affected_model_check/eqptLC_empty.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json b/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json deleted file mode 100644 index 53a02c4..0000000 --- a/tests/checks/wred_affected_model_check/fabricNode_leaf_affected.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "fabricNode": { - "attributes": { - "dn": "topology/pod-1/node-101", - "id": "101", - "name": "leaf101", - "role": "leaf", - "model": "N9K-C9236C" - } - } - } -] diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index 3e3726e..4627857 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -17,29 +17,20 @@ @pytest.mark.parametrize( "tversion, fabric_nodes, icurl_outputs, expected_result, expected_data", [ - # Case 1: No target version provided (-t flag missing). - # Check cannot determine version gate. Expected: MANUAL CHECK REQUIRED. - ( - None, - read_data(dir, "fabricNode_leaf_affected.json"), - {}, - script.MANUAL, - [], - ), - # Case 2: Target version 6.2(2a) is the first fixed release and not in the affected range. + # Case 1: Target version 6.2(2a) is the first fixed release and not in the affected range. # Version gate fails. Expected: NA without any API calls. ( "6.2(2a)", - read_data(dir, "fabricNode_leaf_affected.json"), + read_data(dir, "fabricNode_spine.json"), {}, script.NA, [], ), - # Case 3: All 3 gates triggered via an affected FM on a spine node. - # Version 6.2(1f) is in affected range, WRED is enabled, FM model N9K-C9508-FM-E is affected. + # Case 2: All 3 gates triggered via an affected FM on a spine node. + # Version 6.2(1g) is in affected range, WRED is enabled, FM model N9K-C9508-FM-E is affected. # Expected: FAIL_O with node 1001 reported under Source=FM. ( - "6.2(1f)", + "6.2(1g)", read_data(dir, "fabricNode_spine.json"), { qosCong_api: read_data(dir, "qosCong_wred.json"), @@ -48,18 +39,18 @@ script.FAIL_O, [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], ), - # Case 4: Version is affected but no affected FM hardware found. - # Hardware gate fails before WRED is checked. Expected: PASS. + # Case 3: Version is affected but no affected FM hardware found. + # Hardware gate fails before WRED is checked. Expected: NA - issue is model-specific. ( "6.1(5e)", read_data(dir, "fabricNode_spine.json"), { eqptFC_api: read_data(dir, "eqptFC_empty.json"), }, - script.PASS, + script.NA, [], ), - # Case 5: Version is affected and FM is affected, but WRED is not enabled (tail-drop). + # Case 4: Version is affected and FM is affected, but WRED is not enabled (tail-drop). # WRED gate fails. Expected: PASS - confirms all 3 gates must be true simultaneously. ( "6.1(5e)", @@ -71,11 +62,24 @@ script.PASS, [], ), + # Case 5: Multiple FM objects — one affected (N9K-C9508-FM-E), one unaffected (N9K-C9504-FM-G). + # WRED is enabled. Only the affected FM should be reported. + # Expected: FAIL_O with only the affected FM row reported. + ( + "6.1(5e)", + read_data(dir, "fabricNode_spine.json"), + { + qosCong_api: read_data(dir, "qosCong_wred.json"), + eqptFC_api: read_data(dir, "eqptFC_mixed.json"), + }, + script.FAIL_O, + [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], + ), ], ) def test_logic(run_check, mock_icurl, tversion, fabric_nodes, expected_result, expected_data): result = run_check( - tversion=script.AciVersion(tversion) if tversion else None, + tversion=script.AciVersion(tversion), fabric_nodes=fabric_nodes, ) assert result.result == expected_result From 67a0b66fb71d7451f4108cfe3e78effc22068b1a Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 21 Apr 2026 09:02:27 +0530 Subject: [PATCH 07/16] Upated the message --- 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 cb096da..d227026 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6494,7 +6494,7 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): data.append([node_id, node_name_map.get(node_id, ""), "FM", model]) if not data: - return Result(result=NA, msg="No affected FM hardware models found.") + return Result(result=NA, msg="No affected Fabric module found.") wred_enabled = any( cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred" From 49d3ed0ab8469149040200b3d04f23702c765e96 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 21 Apr 2026 11:47:11 +0530 Subject: [PATCH 08/16] Addressed review comments --- docs/docs/validations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 7fb38e0..4c3751c 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2804,7 +2804,7 @@ This check will verify the count of the `svccoreCtrlr` Managed Object and raise Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. -Affected versions: ACI 6.1(5e) and below, and ACI 6.2(1g) and below. +Affected versions: version <= 6.1(5e) or version <= 6.2(1g). Affected hardware models: N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E. From b25610584aa0bcb3f4ed1c4c53893e6b161a65c2 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 5 May 2026 18:34:01 +0530 Subject: [PATCH 09/16] Refactored result variable in wred_affected_model_check --- aci-preupgrade-validation-script.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index d227026..e9ca47f 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6461,7 +6461,6 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): @check_wrapper(check_title="WRED with Affected FM Models") def wred_affected_model_check(tversion, fabric_nodes, **kwargs): - result = PASS headers = ["Node ID", "Node Name", "Source", "Model"] data = [] recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(1g)." @@ -6504,9 +6503,8 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): return Result(result=PASS, msg="WRED not enabled.") data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) - result = FAIL_O - return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + return Result(result=FAIL_O, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) # ---- Script Execution ---- From 3ae8178443597bf1c1ca4dee5a853c902befe403 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Mon, 25 May 2026 17:59:26 +0530 Subject: [PATCH 10/16] Updated wred_affected_model_check --- aci-preupgrade-validation-script.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index e9ca47f..883ff7e 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6461,6 +6461,7 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): @check_wrapper(check_title="WRED with Affected FM Models") def wred_affected_model_check(tversion, fabric_nodes, **kwargs): + result = PASS headers = ["Node ID", "Node Name", "Source", "Model"] data = [] recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(1g)." @@ -6480,7 +6481,6 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): for node in fabric_nodes } - # FM model gate for obj in icurl("class", "eqptFC.json"): attr = obj["eqptFC"]["attributes"] model = attr.get("model", "") @@ -6495,16 +6495,19 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): if not data: return Result(result=NA, msg="No affected Fabric module found.") - wred_enabled = any( - cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred" - for cong in icurl("class", "qosCong.json") - ) - if not wred_enabled: - return Result(result=PASS, msg="WRED not enabled.") + wred_enabled = False + for cong in icurl("class", "qosCong.json"): + if cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred": + wred_enabled = True + break - data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) + if wred_enabled: + data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) + result = FAIL_O + else: + data = [] - return Result(result=FAIL_O, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) # ---- Script Execution ---- From f10ba8134273d44f9da232a368bd3588e4477748 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 26 May 2026 13:13:49 +0530 Subject: [PATCH 11/16] Addressed PR review comments --- aci-preupgrade-validation-script.py | 22 +++++++-------- .../test_wred_affected_model_check.py | 28 +++++++++++++++++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 883ff7e..1511269 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6467,6 +6467,9 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(1g)." doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-fm-models" + if not tversion: + return Result(result=MANUAL, msg=TVER_MISSING) + version_affected = ( (tversion.major1 == "6" and tversion.major2 == "1" and (tversion.older_than("6.1(5e)") or tversion.same_as("6.1(5e)"))) or (tversion.major1 == "6" and tversion.major2 == "2" and (tversion.older_than("6.2(1g)") or tversion.same_as("6.2(1g)"))) @@ -6481,6 +6484,12 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): for node in fabric_nodes } + for cong in icurl("class", "qosCong.json"): + if cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred": + break + else: + return Result(result=PASS, msg="WRED not enabled.") + for obj in icurl("class", "eqptFC.json"): attr = obj["eqptFC"]["attributes"] model = attr.get("model", "") @@ -6495,17 +6504,8 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): if not data: return Result(result=NA, msg="No affected Fabric module found.") - wred_enabled = False - for cong in icurl("class", "qosCong.json"): - if cong.get("qosCong", {}).get("attributes", {}).get("algo") == "wred": - wred_enabled = True - break - - if wred_enabled: - data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) - result = FAIL_O - else: - data = [] + data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) + result = FAIL_O return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index 4627857..f9e04d8 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -17,7 +17,15 @@ @pytest.mark.parametrize( "tversion, fabric_nodes, icurl_outputs, expected_result, expected_data", [ - # Case 1: Target version 6.2(2a) is the first fixed release and not in the affected range. + # Case 1: Target version not supplied. Expected: MANUAL. + ( + None, + read_data(dir, "fabricNode_spine.json"), + {}, + script.MANUAL, + [], + ), + # Case 2: Target version 6.2(2a) is the first fixed release and not in the affected range. # Version gate fails. Expected: NA without any API calls. ( "6.2(2a)", @@ -40,11 +48,13 @@ [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], ), # Case 3: Version is affected but no affected FM hardware found. - # Hardware gate fails before WRED is checked. Expected: NA - issue is model-specific. + # WRED is enabled so the script proceeds to the FM check, which finds nothing. + # Hardware gate fails. Expected: NA - issue is model-specific. ( "6.1(5e)", read_data(dir, "fabricNode_spine.json"), { + qosCong_api: read_data(dir, "qosCong_wred.json"), eqptFC_api: read_data(dir, "eqptFC_empty.json"), }, script.NA, @@ -75,11 +85,23 @@ script.FAIL_O, [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], ), + # Case 6: Version is affected, WRED is enabled, but no affected FM models found. + # FM gate fails. Expected: NA. + ( + "6.2(1g)", + read_data(dir, "fabricNode_spine.json"), + { + qosCong_api: read_data(dir, "qosCong_wred.json"), + eqptFC_api: read_data(dir, "eqptFC_empty.json"), + }, + script.NA, + [], + ), ], ) def test_logic(run_check, mock_icurl, tversion, fabric_nodes, expected_result, expected_data): result = run_check( - tversion=script.AciVersion(tversion), + tversion=script.AciVersion(tversion) if tversion else None, fabric_nodes=fabric_nodes, ) assert result.result == expected_result From 82e6a080646da677e3b1facc9db0b398e4e464f2 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 26 May 2026 14:31:17 +0530 Subject: [PATCH 12/16] Remove the sort method --- aci-preupgrade-validation-script.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 1511269..67f22e0 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6504,7 +6504,6 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): if not data: return Result(result=NA, msg="No affected Fabric module found.") - data.sort(key=lambda row: (int(row[0]) if row[0].isdigit() else row[0], row[3])) result = FAIL_O return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) From f2c2ff7ded181b019f2d0dfdd54af912cc74254c Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 26 May 2026 14:53:08 +0530 Subject: [PATCH 13/16] Addressed PR review comments --- 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 67f22e0..e9ac864 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6681,6 +6681,7 @@ class CheckManager: n9k_c9408_model_lem_count_check, inband_management_policy_misconfig_check, bgpProto_timer_policy_already_existing_check, + wred_affected_model_check, ] ssh_checks = [ # General @@ -6693,7 +6694,6 @@ class CheckManager: # Bugs observer_db_size_check, multipod_modular_spine_bootscript_check, - wred_affected_model_check, ] cli_checks = [ # General From b5ea5206e0318a84c713152aad0e7b824a3f3388 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 26 May 2026 16:03:32 +0530 Subject: [PATCH 14/16] Fix non-ASCII char in test comment --- .../wred_affected_model_check/test_wred_affected_model_check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index f9e04d8..13a2eea 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -72,7 +72,7 @@ script.PASS, [], ), - # Case 5: Multiple FM objects — one affected (N9K-C9508-FM-E), one unaffected (N9K-C9504-FM-G). + # Case 5: Multiple FM objects - one affected (N9K-C9508-FM-E), one unaffected (N9K-C9504-FM-G). # WRED is enabled. Only the affected FM should be reported. # Expected: FAIL_O with only the affected FM row reported. ( From abf0dc8586fd13c78e4e591ad46caf27e99095b9 Mon Sep 17 00:00:00 2001 From: Priyanka Date: Tue, 26 May 2026 17:51:11 +0530 Subject: [PATCH 15/16] Fixed duplicate entries --- aci-preupgrade-validation-script.py | 4 +++- .../test_wred_affected_model_check.py | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index e9ac864..e1213af 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6490,6 +6490,7 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): else: return Result(result=PASS, msg="WRED not enabled.") + unique_list = {} for obj in icurl("class", "eqptFC.json"): attr = obj["eqptFC"]["attributes"] model = attr.get("model", "") @@ -6499,7 +6500,8 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): if not dn_match: continue node_id = dn_match.group("node") - data.append([node_id, node_name_map.get(node_id, ""), "FM", model]) + unique_list[(node_id, model)] = [node_id, node_name_map.get(node_id, ""), "FM", model] + data = list(unique_list.values()) if not data: return Result(result=NA, msg="No affected Fabric module found.") diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index 13a2eea..438f965 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -97,6 +97,19 @@ script.NA, [], ), + # Case 7: Same node has two FM slots with the same affected model (duplicate eqptFC objects). + # Deduplication by (node_id, model) must result in only one row. + # Expected: FAIL_O with a single row for node 1001. + ( + "6.2(1g)", + read_data(dir, "fabricNode_spine.json"), + { + qosCong_api: read_data(dir, "qosCong_wred.json"), + eqptFC_api: read_data(dir, "eqptFC_duplicate.json"), + }, + script.FAIL_O, + [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], + ), ], ) def test_logic(run_check, mock_icurl, tversion, fabric_nodes, expected_result, expected_data): From 1ab5633e8cb518f0589eddce357c6a4b6e23c32e Mon Sep 17 00:00:00 2001 From: Priyanka Date: Fri, 12 Jun 2026 15:07:13 +0530 Subject: [PATCH 16/16] Address PR review comments --- aci-preupgrade-validation-script.py | 21 ++++++++++--------- docs/docs/validations.md | 7 ++++--- .../eqptFC_duplicate.json | 18 ++++++++++++++++ .../test_wred_affected_model_check.py | 12 +++++------ 4 files changed, 39 insertions(+), 19 deletions(-) create mode 100644 tests/checks/wred_affected_model_check/eqptFC_duplicate.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index e1213af..78110c1 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6462,9 +6462,9 @@ def bgpProto_timer_policy_already_existing_check(tversion, cversion, **kwargs): @check_wrapper(check_title="WRED with Affected FM Models") def wred_affected_model_check(tversion, fabric_nodes, **kwargs): result = PASS - headers = ["Node ID", "Node Name", "Source", "Model"] + headers = ["Node ID", "Node Name", "Model"] data = [] - recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(1g)." + recommended_action = "Disable WRED in fabric or upgrade to a release newer than 6.1(5e) or 6.2(2d)." doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#wred-with-affected-fm-models" if not tversion: @@ -6472,7 +6472,7 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): version_affected = ( (tversion.major1 == "6" and tversion.major2 == "1" and (tversion.older_than("6.1(5e)") or tversion.same_as("6.1(5e)"))) - or (tversion.major1 == "6" and tversion.major2 == "2" and (tversion.older_than("6.2(1g)") or tversion.same_as("6.2(1g)"))) + or (tversion.major1 == "6" and tversion.major2 == "2" and tversion.older_than("6.2(2e)")) ) if not version_affected: return Result(result=NA, msg=VER_NOT_AFFECTED) @@ -6496,19 +6496,20 @@ def wred_affected_model_check(tversion, fabric_nodes, **kwargs): model = attr.get("model", "") if model not in affected_models: continue - dn_match = re.search(node_regex, attr.get("dn", "")) + dn = attr.get("dn", "") + if not dn.startswith("topology/"): + continue + dn_match = re.search(node_regex, dn) if not dn_match: continue node_id = dn_match.group("node") - unique_list[(node_id, model)] = [node_id, node_name_map.get(node_id, ""), "FM", model] + unique_list[(node_id, model)] = [node_id, node_name_map.get(node_id, ""), model] data = list(unique_list.values()) - if not data: - return Result(result=NA, msg="No affected Fabric module found.") - - result = FAIL_O + if data: + return Result(result=FAIL_O, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) - return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + return Result(result=NA, msg="No affected Fabric module found.") # ---- Script Execution ---- diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 4c3751c..bd0de6d 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2802,13 +2802,14 @@ This check will verify the count of the `svccoreCtrlr` Managed Object and raise ### WRED with Affected FM Models -Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. +Due to [CSCwt50713][72], when WRED (Weighted Random Early Detection) is enabled and specific Fabric Module (FM) hardware models are present in the fabric, the spine switch may crash after moving to an affected ACI release in the 6.1(x) or 6.2(x) range. The crash is specifically triggered by running a tech-support collection or QoS-related commands on the affected spine. -Affected versions: version <= 6.1(5e) or version <= 6.2(1g). +Affected versions: +version <= 6.1(5e) or version < 6.2(2e). Affected hardware models: N9K-C9504-FM-E, N9K-C9508-FM-E, N9K-C9516-FM-E. -To avoid this issue, disable WRED on the affected nodes or upgrade to a release newer than 6.1(5e) in the 6.1(x) train or newer than 6.2(1g) in the 6.2(x) train. +To avoid this issue, disable WRED on the affected nodes or upgrade to a release newer than 6.1(5e) in the 6.1(x) train or 6.2(2e) or later in the 6.2(x) train. ### BgpProto Timer Policy Already Existing diff --git a/tests/checks/wred_affected_model_check/eqptFC_duplicate.json b/tests/checks/wred_affected_model_check/eqptFC_duplicate.json new file mode 100644 index 0000000..d121050 --- /dev/null +++ b/tests/checks/wred_affected_model_check/eqptFC_duplicate.json @@ -0,0 +1,18 @@ +[ + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-2/fc", + "model": "N9K-C9508-FM-E" + } + } + }, + { + "eqptFC": { + "attributes": { + "dn": "topology/pod-1/node-1001/sys/ch/fcslot-6/fc", + "model": "N9K-C9508-FM-E" + } + } + } +] diff --git a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py index 438f965..f3610a9 100644 --- a/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py +++ b/tests/checks/wred_affected_model_check/test_wred_affected_model_check.py @@ -25,10 +25,10 @@ script.MANUAL, [], ), - # Case 2: Target version 6.2(2a) is the first fixed release and not in the affected range. + # Case 2: Target version 6.2(2e) is the first fixed release and not in the affected range. # Version gate fails. Expected: NA without any API calls. ( - "6.2(2a)", + "6.2(2e)", read_data(dir, "fabricNode_spine.json"), {}, script.NA, @@ -36,7 +36,7 @@ ), # Case 2: All 3 gates triggered via an affected FM on a spine node. # Version 6.2(1g) is in affected range, WRED is enabled, FM model N9K-C9508-FM-E is affected. - # Expected: FAIL_O with node 1001 reported under Source=FM. + # Expected: FAIL_O with node 1001 reported. ( "6.2(1g)", read_data(dir, "fabricNode_spine.json"), @@ -45,7 +45,7 @@ eqptFC_api: read_data(dir, "eqptFC_affected.json"), }, script.FAIL_O, - [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], + [["1001", "spine1001", "N9K-C9508-FM-E"]], ), # Case 3: Version is affected but no affected FM hardware found. # WRED is enabled so the script proceeds to the FM check, which finds nothing. @@ -83,7 +83,7 @@ eqptFC_api: read_data(dir, "eqptFC_mixed.json"), }, script.FAIL_O, - [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], + [["1001", "spine1001", "N9K-C9508-FM-E"]], ), # Case 6: Version is affected, WRED is enabled, but no affected FM models found. # FM gate fails. Expected: NA. @@ -108,7 +108,7 @@ eqptFC_api: read_data(dir, "eqptFC_duplicate.json"), }, script.FAIL_O, - [["1001", "spine1001", "FM", "N9K-C9508-FM-E"]], + [["1001", "spine1001", "N9K-C9508-FM-E"]], ), ], )