diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index f29c66b..9ee408a 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6053,6 +6053,86 @@ def auto_firmware_update_on_switch_check(cversion, tversion, **kwargs): return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + +@check_wrapper(check_title='N9300 Switch Memory') +def n9300_switch_memory_check(tversion, fabric_nodes, **kwargs): + result = PASS + headers = ["NodeId", "Name", "Model", "Memory Detected (GB)"] + data = [] + recommended_action = 'Increase the switch memory to at least 24GB on affected N9300-series switches.' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#n9300-switch-memory' + min_memory_kb = 24 * 1024 * 1024 + msg = '' + + affected_nodes = [ + node for node in fabric_nodes + if node.get('fabricNode', {}).get('attributes', {}).get('model', '').startswith('N9K-C93') + ] + + if not affected_nodes: + result = NA + msg = 'No N9300 switches found. Skipping.' + else: + proc_mem_mos = icurl('class', 'procMemUsage.json') + node_total_kb = {} + parse_errors = [] + + for memory_mo in proc_mem_mos: + attrs = memory_mo.get('procMemUsage', {}).get('attributes', {}) + total = attrs.get('Total') + mem_dn = attrs.get('dn', '') + if not total or '/memusage-sup' not in mem_dn: + continue + dn_match = re.search(node_regex, mem_dn) + if not dn_match: + continue + try: + total_kb = int(total) + except (TypeError, ValueError): + parse_errors.append([mem_dn, total]) + continue + + node_id = dn_match.group('node') + if node_id not in node_total_kb: + node_total_kb[node_id] = total_kb + + if parse_errors: + result = ERROR + msg = 'Failed to parse procMemUsage Total for one or more nodes.' + headers = ['DN', 'Total'] + data = parse_errors + else: + missing_nodes = [] + + for node in affected_nodes: + node_id = node['fabricNode']['attributes']['id'] + total_kb = node_total_kb.get(node_id) + if total_kb is None: + missing_nodes.append([ + node_id, + node['fabricNode']['attributes'].get('name', ''), + node['fabricNode']['attributes'].get('model', ''), + ]) + continue + + if total_kb < min_memory_kb: + memory_in_gb = round(total_kb / 1048576, 2) + result = FAIL_O + data.append([ + node_id, + node['fabricNode']['attributes'].get('name', ''), + node['fabricNode']['attributes'].get('model', ''), + memory_in_gb, + ]) + + if missing_nodes: + result = ERROR + msg = 'Missing procMemUsage data for one or more affected N9300 nodes.' + headers = ['NodeId', 'Name', 'Model'] + data = missing_nodes + + return Result(result=result, msg=msg, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + # ---- Script Execution ---- @@ -6216,6 +6296,7 @@ class CheckManager: isis_database_byte_check, configpush_shard_check, auto_firmware_update_on_switch_check, + n9300_switch_memory_check, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index f46e03d..537a289 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -194,6 +194,7 @@ Items | Defect | This Script [ISIS DTEPs Byte Size][d27] | CSCwp15375 | :white_check_mark: | :no_entry_sign: [Policydist configpushShardCont Crash][d28] | CSCwp95515 | :white_check_mark: | :no_entry_sign: [Auto Firmware Update on Switch Discovery][d29] | CSCwe83941 | :white_check_mark: | :no_entry_sign: +[N9300 Switch Memory][d30] | - | :white_check_mark: | :no_entry_sign: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -224,6 +225,7 @@ Items | Defect | This Script [d27]: #isis-dteps-byte-size [d28]: #policydist-configpushshardcont-crash [d29]: #auto-firmware-update-on-switch-discovery +[d30]: #n9300-switch-memory ## General Check Details @@ -2667,6 +2669,14 @@ To avoid this risk, consider disabling Auto Firmware Update before upgrading to !!! note This issue occurs because older switch firmware versions are not compatible with switch images 6.0(3) or newer. The APIC version is not a factor. +### N9300 Switch Memory + +This check applies to N9300-series switches only. It reviews `procMemUsage` and flags nodes with less than 24GB memory installed. + +Impact: Running an N9300-series switch with less than 24GB memory can lead to memory pressure and increase the risk of service instability. + +If any N9300-series switch is flagged by this check, increase the switch memory to at least 24GB. + [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 diff --git a/tests/checks/n9300_switch_memory_24g_check/fabricNode_non_n9300.json b/tests/checks/n9300_switch_memory_24g_check/fabricNode_non_n9300.json new file mode 100644 index 0000000..a82341a --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/fabricNode_non_n9300.json @@ -0,0 +1,13 @@ +[ + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-201", + "id": "201", + "name": "leaf201", + "model": "N9K-C9508", + "role": "leaf" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/fabricNode_one.json b/tests/checks/n9300_switch_memory_24g_check/fabricNode_one.json new file mode 100644 index 0000000..74a31ad --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/fabricNode_one.json @@ -0,0 +1,13 @@ +[ + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-101", + "id": "101", + "name": "leaf101", + "model": "N9K-C93180YC-FX3", + "role": "leaf" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/fabricNode_two.json b/tests/checks/n9300_switch_memory_24g_check/fabricNode_two.json new file mode 100644 index 0000000..fad0289 --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/fabricNode_two.json @@ -0,0 +1,24 @@ +[ + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-101", + "id": "101", + "name": "leaf101", + "model": "N9K-C93180YC-FX3", + "role": "leaf" + } + } + }, + { + "fabricNode": { + "attributes": { + "dn": "topology/pod-1/node-102", + "id": "102", + "name": "leaf102", + "model": "N9K-C9364C", + "role": "leaf" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_all_gt24gb.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_all_gt24gb.json new file mode 100644 index 0000000..dab23d2 --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_all_gt24gb.json @@ -0,0 +1,20 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32535444" + } + } + }, + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-102/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "28535444" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_gt24gb.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_gt24gb.json new file mode 100644 index 0000000..597db59 --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_gt24gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "26535444" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_invalid_total.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_invalid_total.json new file mode 100644 index 0000000..dc1a4ee --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_invalid_total.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "unknown" + } + } + } +] diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_lt24gb.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_lt24gb.json new file mode 100644 index 0000000..d84e82c --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_lt24gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "22535444" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_missing_affected_node.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_missing_affected_node.json new file mode 100644 index 0000000..e11293a --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_missing_affected_node.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-201/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "26535444" + } + } + } +] diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_mixed.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_mixed.json new file mode 100644 index 0000000..58ece8e --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_mixed.json @@ -0,0 +1,20 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32535444" + } + } + }, + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-102/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "22535444" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/procMemUsage_node201_gt24gb.json b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_node201_gt24gb.json new file mode 100644 index 0000000..bca2b9f --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/procMemUsage_node201_gt24gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-201/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "28535444" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9300_switch_memory_24g_check/test_n9300_switch_memory_24g_check.py b/tests/checks/n9300_switch_memory_24g_check/test_n9300_switch_memory_24g_check.py new file mode 100644 index 0000000..0f6aa00 --- /dev/null +++ b/tests/checks/n9300_switch_memory_24g_check/test_n9300_switch_memory_24g_check.py @@ -0,0 +1,105 @@ +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 = "n9300_switch_memory_check" + +# icurl queries +proc_mem_query = 'procMemUsage.json' + + +@pytest.mark.parametrize( + "fabric_nodes, icurl_outputs, tversion, expected_result, expected_msg, expected_data", + [ + # No nodes returned + ( + [], + {}, + "6.0(3c)", + script.NA, + 'No N9300 switches found. Skipping.', + [], + ), + # Non-N9300 node with >=24GB memory + ( + read_data(dir, "fabricNode_non_n9300.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_node201_gt24gb.json"), + }, + "6.0(3c)", + script.NA, + 'No N9300 switches found. Skipping.', + [], + ), + # N9300 node with >=24GB memory + ( + read_data(dir, "fabricNode_one.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_gt24gb.json"), + }, + "6.0(3c)", + script.PASS, + '', + [], + ), + # Multiple N9300 nodes, all >=24GB memory + ( + read_data(dir, "fabricNode_two.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_all_gt24gb.json"), + }, + "6.0(3c)", + script.PASS, + '', + [], + ), + # Invalid procMemUsage Total value + ( + read_data(dir, "fabricNode_one.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_invalid_total.json"), + }, + "6.0(3c)", + script.ERROR, + 'Failed to parse procMemUsage Total for one or more nodes.', + [["topology/pod-1/node-101/sys/procmem/memusage-sup", "unknown"]], + ), + # Missing procMemUsage data for affected node + ( + read_data(dir, "fabricNode_one.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_missing_affected_node.json"), + }, + "6.0(3c)", + script.ERROR, + 'Missing procMemUsage data for one or more affected N9300 nodes.', + [["101", "leaf101", "N9K-C93180YC-FX3"]], + ), + # N9300 node with <24GB memory + ( + read_data(dir, "fabricNode_two.json"), + { + proc_mem_query: read_data(dir, "procMemUsage_mixed.json"), + }, + "6.0(3c)", + script.FAIL_O, + '', + [["102", "leaf102", "N9K-C9364C", 21.49]], + ), + ], +) +def test_logic(run_check, mock_icurl, fabric_nodes, tversion, expected_result, expected_msg, expected_data): + result = run_check( + tversion=script.AciVersion(tversion), + fabric_nodes=fabric_nodes, + ) + assert result.result == expected_result + assert result.msg == expected_msg + assert result.data == expected_data \ No newline at end of file