Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions aci-preupgrade-validation-script.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ----


Expand Down Expand Up @@ -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 = [
Expand Down
10 changes: 10 additions & 0 deletions docs/docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls add bug id, it's missing.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is implemented as a general readiness check for N9300-series memory requirements, not tied to a specific CSC bug.


[d1]: #ep-announce-compatibility
[d2]: #eventmgr-db-size-defect-susceptibility
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"fabricNode": {
"attributes": {
"dn": "topology/pod-1/node-201",
"id": "201",
"name": "leaf201",
"model": "N9K-C9508",
"role": "leaf"
}
}
}
]
13 changes: 13 additions & 0 deletions tests/checks/n9300_switch_memory_24g_check/fabricNode_one.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"fabricNode": {
"attributes": {
"dn": "topology/pod-1/node-101",
"id": "101",
"name": "leaf101",
"model": "N9K-C93180YC-FX3",
"role": "leaf"
}
}
}
]
24 changes: 24 additions & 0 deletions tests/checks/n9300_switch_memory_24g_check/fabricNode_two.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"procMemUsage": {
"attributes": {
"dn": "topology/pod-1/node-101/sys/procmem/memusage-sup",
"Modname": "sup",
"Total": "26535444"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"procMemUsage": {
"attributes": {
"dn": "topology/pod-1/node-101/sys/procmem/memusage-sup",
"Modname": "sup",
"Total": "unknown"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"procMemUsage": {
"attributes": {
"dn": "topology/pod-1/node-101/sys/procmem/memusage-sup",
"Modname": "sup",
"Total": "22535444"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"procMemUsage": {
"attributes": {
"dn": "topology/pod-1/node-201/sys/procmem/memusage-sup",
"Modname": "sup",
"Total": "26535444"
}
}
}
]
20 changes: 20 additions & 0 deletions tests/checks/n9300_switch_memory_24g_check/procMemUsage_mixed.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[
{
"procMemUsage": {
"attributes": {
"dn": "topology/pod-1/node-201/sys/procmem/memusage-sup",
"Modname": "sup",
"Total": "28535444"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -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