diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index da1b4b9e..da5d15f3 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6410,6 +6410,66 @@ def svccore_excessive_data_check(**kwargs): return Result(result=ERROR, msg="Error occurred while fetching svccore object counts: {}".format(str(e)), 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 = MANUAL + 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) + + # ---- Script Execution ---- @@ -6581,6 +6641,7 @@ class CheckManager: rogue_ep_coop_exception_mac_check, n9k_c9408_model_lem_count_check, inband_management_policy_misconfig_check, + n9k_c93180yc_fx3_switch_memory_check, ] ssh_checks = [ # General diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 82f22119..8dda2227 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -203,6 +203,7 @@ Items | Defect | This Script [N9K-C9408 with more than 5 N9K-X9400-16W LEMs][d31] | CSCws82819 | :white_check_mark: | :no_entry_sign: [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: +[N9K-C93180YC-FX3 Switch Memory Less Than 32GB][d34] | CSCwm42741 | :white_check_mark: | :no_entry_sign: [d1]: #ep-announce-compatibility [d2]: #eventmgr-db-size-defect-susceptibility @@ -237,6 +238,7 @@ Items | Defect | This Script [d31]: #n9k-c9408-with-more-than-5-n9k-x9400-16w-lems [d32]: #multi-pod-modular-spine-bootscript-file [d33]: #inband-management-policy-misconfiguration +[d34]: #n9k-c93180yc-fx3-switch-memory-less-than-32gb ## General Check Details @@ -2742,6 +2744,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. +### N9K-C93180YC-FX3 Switch Memory Less Than 32GB + +This check applies to N9K-C93180YC-FX3 switches only. It checks whether the switch has less than 32GB of memory. The minimum RAM requirement for the N9K-C93180YC-FX3 to operate properly in ACI mode is 32GB. This check is not version dependent and runs for all upgrade versions. + +[CSCwm42741][70] tracks this issue. N9K-C93180YC-FX3 switches running in ACI mode with less than 32GB of memory will not perform well and are at risk of service instability. With fix of CSCwm42741, a critical fault F4680 (`eqpt-low-memory-device`) is raised on affected switches. + +If any N9K-C93180YC-FX3 switch is flagged by this check, upgrade the switch memory to at least 32GB before proceeding with the upgrade. + ### Rogue EP Exception List missing on switches @@ -2867,4 +2877,5 @@ This check will verify the count of the `svccoreCtrlr` Managed Object and raise [66]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwr66848 [67]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwh80837 [68]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwd40071 -[69]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCws84232 \ No newline at end of file +[69]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCws84232 +[70]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwm42741 \ No newline at end of file diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_N9K-C9508.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_N9K-C9508.json new file mode 100644 index 00000000..a82341a4 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_N9K-C9508.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/n9k_c93180yc_fx3_switch_memory_check/fabricNode_one.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_one.json new file mode 100644 index 00000000..74a31ad3 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_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/n9k_c93180yc_fx3_switch_memory_check/fabricNode_two.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_two.json new file mode 100644 index 00000000..fad02898 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_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/n9k_c93180yc_fx3_switch_memory_check/fabricNode_two_fx3.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_two_fx3.json new file mode 100644 index 00000000..dfc8a77a --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/fabricNode_two_fx3.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-C93180YC-FX3", + "role": "leaf" + } + } + } +] diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_all_gt32gb.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_all_gt32gb.json new file mode 100644 index 00000000..c3aef55a --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_all_gt32gb.json @@ -0,0 +1,20 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32676092" + } + } + }, + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-102/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32676092" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_fail_and_missing.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_fail_and_missing.json new file mode 100644 index 00000000..5f50d60d --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_fail_and_missing.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "16000000" + } + } + } +] diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_gt32gb.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_gt32gb.json new file mode 100644 index 00000000..5597a511 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_gt32gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32676092" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_invalid_total.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_invalid_total.json new file mode 100644 index 00000000..dc1a4ee3 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_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/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_lt32gb.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_lt32gb.json new file mode 100644 index 00000000..5f50d60d --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_lt32gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "16000000" + } + } + } +] diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_missing_affected_node.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_missing_affected_node.json new file mode 100644 index 00000000..f8b22098 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_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": "32676092" + } + } + } +] diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_mixed.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_mixed.json new file mode 100644 index 00000000..b7c74c07 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_mixed.json @@ -0,0 +1,20 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-101/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32676092" + } + } + }, + { + "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/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_node201_gt32gb.json b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_node201_gt32gb.json new file mode 100644 index 00000000..db65e8c6 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/procMemUsage_node201_gt32gb.json @@ -0,0 +1,11 @@ +[ + { + "procMemUsage": { + "attributes": { + "dn": "topology/pod-1/node-201/sys/procmem/memusage-sup", + "Modname": "sup", + "Total": "32676092" + } + } + } +] \ No newline at end of file diff --git a/tests/checks/n9k_c93180yc_fx3_switch_memory_check/test_n9k_c93180yc_fx3_switch_memory_check.py b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/test_n9k_c93180yc_fx3_switch_memory_check.py new file mode 100644 index 00000000..56a360c2 --- /dev/null +++ b/tests/checks/n9k_c93180yc_fx3_switch_memory_check/test_n9k_c93180yc_fx3_switch_memory_check.py @@ -0,0 +1,82 @@ +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 = "n9k_c93180yc_fx3_switch_memory_check" + +# icurl queries - filtered by affected node IDs and memory threshold +proc_mem_query_node101 = 'procMemUsage.json?query-target-filter=and(or(wcard(procMemUsage.dn,"node-101/")),wcard(procMemUsage.dn,"memusage-sup"),lt(procMemUsage.Total,"32000000"))' + + +@pytest.mark.parametrize( + "fabric_nodes, icurl_outputs, expected_result, expected_msg, expected_data", + [ + # No nodes returned + ( + [], + {}, + script.NA, + 'No N9K-C93180YC-FX3 switches found. Skipping.', + [], + ), + # Non-N9K-C93180YC-FX3 node (N9K-C9508) + ( + read_data(dir, "fabricNode_N9K-C9508.json"), + {}, + script.NA, + 'No N9K-C93180YC-FX3 switches found. Skipping.', + [], + ), + # N9K-C93180YC-FX3 node with >=32GB memory - API returns empty (filtered by lt) + ( + read_data(dir, "fabricNode_one.json"), + { + proc_mem_query_node101: [], + }, + script.PASS, + '', + [], + ), + # Multiple nodes, only N9K-C93180YC-FX3 checked, all >=32GB - API returns empty + ( + read_data(dir, "fabricNode_two.json"), + { + proc_mem_query_node101: [], + }, + script.PASS, + '', + [], + ), + # N9K-C93180YC-FX3 node with <32GB memory (fail case) + ( + read_data(dir, "fabricNode_one.json"), + { + proc_mem_query_node101: read_data(dir, "procMemUsage_lt32gb.json"), + }, + script.MANUAL, + ( + '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.' + ), + [["101", "leaf101", "N9K-C93180YC-FX3", 16.0]], + ), + ], +) +def test_logic(run_check, mock_icurl, fabric_nodes, expected_result, expected_msg, expected_data): + result = run_check( + fabric_nodes=fabric_nodes, + ) + assert result.result == expected_result + assert result.msg == expected_msg + if result.data: + assert result.data == expected_data + else: + assert result.unformatted_data == expected_data \ No newline at end of file