Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 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
104 changes: 104 additions & 0 deletions aci-preupgrade-validation-script.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ def __init__(self, hostname):
self._term_len = 0 # terminal length for cisco devices
self._login = False # set to true at first successful login
self._log = None # private variable for tracking logfile state
self.bind_ip = None # optional source IP to bind for SSH

def __connected(self):
# determine if a connection is already open
Expand Down Expand Up @@ -207,6 +208,8 @@ def connect(self):
"spawning new pexpect connection: ssh %s@%s -p %d" % (self.username, self.hostname, self.port))
no_verify = " -o StrictHostKeyChecking=no -o LogLevel=ERROR -o UserKnownHostsFile=/dev/null"
if self.verify: no_verify = ""
if self.bind_ip:
Comment thread
asraf-khan marked this conversation as resolved.
no_verify += " -b %s" % self.bind_ip
self.child = pexpect.spawn("ssh %s %s@%s -p %d" % (no_verify, self.username, self.hostname, self.port),
searchwindowsize=self.searchwindowsize)
elif self.protocol.lower() == "telnet":
Expand Down Expand Up @@ -5962,6 +5965,106 @@ def configpush_shard_check(tversion, **kwargs):

return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url)


Comment thread
asraf-khan marked this conversation as resolved.
@check_wrapper(check_title="HW Changes bit check for specific node model")
def HW_changes_bit_check(tversion, username, password, fabric_nodes, **kwargs):
result = PASS
headers = ["Node", "Model", "HW Changes Bits", "Recommended Action"]
data = []
recommended_action = "Contact Cisco TAC for Support before upgrade"
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#HW_changes_bit_check"

if not tversion:
return Result(result=MANUAL, msg=TVER_MISSING)
if not tversion.newer_than("14.2(4a)"):
return Result(result=NA, msg=VER_NOT_AFFECTED)

affected_models = {"N9K-C9316D-GX", "N9K-C93600CD-GX"}

node_found = any(
node["fabricNode"]["attributes"]["model"] in affected_models
for node in fabric_nodes
)

Comment thread
asraf-khan marked this conversation as resolved.
if not node_found:
return Result(result=PASS, msg="No switch models found")

# Discover APIC IP (bind source)
apic_ip = None

try:
ifconfig_lines = run_cmd("ifconfig | grep 255.255.255.255", splitlines=True)
Comment thread
asraf-khan marked this conversation as resolved.
Outdated
for line in ifconfig_lines:
match = re.search(r'inet\s+([0-9\.]+)\s+netmask\s+255\.255\.255\.255', line)
if match:
apic_ip = match.group(1)
break
except Exception as e:
return Result(result=ERROR, msg="Failed to get APIC IP: {}".format(e))

if not apic_ip:
return Result(result=ERROR, msg="Could not determine APIC IP from ifconfig output")

hw_bits_re = re.compile(r"HW Changes Bits\s*:\s*(0x[0-9a-fA-F]+)")
has_error = False

# SSH directly to each switch hostname from APIC, binding source to APIC IP (-b <apic_ip>)
for node in fabric_nodes:
if node["fabricNode"]["attributes"]["model"] not in ["N9K-C9316D-GX", "N9K-C93600CD-GX"]:
continue
attr = node['fabricNode']['attributes']
node_name = attr['name']
node_model = attr['model']

node_title = "Checking {} ({})...".format(node_name, node_model)
try:
c = Connection(node_name)
c.username = username
c.password = password
c.log = LOG_FILE
c.bind_ip = apic_ip # enables: ssh <hostname> -b <APIC_IP>
c.connect()
except Exception as e:
data.append([node_name, node_model, "-", "Connection Error: {}".format(str(e))])
has_error = True
continue

try:
# Execute command to check HW Changes Bits
c.cmd("vsh -c 'show sprom cpu-info' | grep \"HW Changes Bits\"")
raw = c.output.strip()
match = hw_bits_re.search(raw)
if not match:
data.append([node_name, node_model, "Parse Error", "Unable to parse HW Changes Bits"])
has_error = True
else:
hw_bits = match.group(1)
val = int(hw_bits, 16)
if val < 2:
result = FAIL_O
data.append([node_name, node_model, hw_bits, "This switch need Manual Upgrade (CSCvv04251). Contact TAC for Support"])
except Exception as e:
data.append([
node_name,
node_model,
'-',
'Failed to check HW Changes Bits: {}. Please check MANUALLY.'.format(str(e))
])
has_error = True
continue
finally:
try:
c.close()
except Exception:
pass

if has_error and result == PASS:
result = ERROR
elif not data:
result = PASS

return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url)

# ---- Script Execution ----


Expand Down Expand Up @@ -6122,6 +6225,7 @@ class CheckManager:
standby_sup_sync_check,
isis_database_byte_check,
configpush_shard_check,
HW_changes_bit_check,

]
ssh_checks = [
Expand Down
12 changes: 12 additions & 0 deletions docs/docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ Items | Defect | This Script
[Stale pconsRA Object][d26] | CSCwp22212 | :warning:{title="Deprecated"} | :no_entry_sign:
[ISIS DTEPs Byte Size][d27] | CSCwp15375 | :white_check_mark: | :no_entry_sign:
[Policydist configpushShardCont Crash][d28] | CSCwp95515 | :white_check_mark: |
[HW_changes_bit_check] | CSCvv04251 | :white_check_mark: | :no_entry_sign:

[d1]: #ep-announce-compatibility
[d2]: #eventmgr-db-size-defect-susceptibility
Expand Down Expand Up @@ -220,6 +221,7 @@ Items | Defect | This Script
[d26]: #stale-pconsra-object
[d27]: #isis-dteps-byte-size
[d28]: #policydist-configpushshardcont-crash
[d29]: #HW_changes_bit_check


## General Check Details
Expand Down Expand Up @@ -2604,6 +2606,15 @@ Due to [CSCwp95515][59], upgrading to an affected version while having any `conf
If any instances of `configpushShardCont` are flagged by this script, Cisco TAC must be contacted to identify and resolve the underlying issue before performing the upgrade.


### HW changes bit check

The HW Changes Bit Check is a validation step in the ACI Pre-Upgrade Validation script that verifies the status of `HW Changes Bits` indicators within the ACI fabric before an upgrade.

If discrepancies are detected, the function raises alerts to prompt administrators to investigate and resolve these issues prior to proceeding with the upgrade. This proactive measure helps prevent potential failures or complications during the upgrade process, ensuring a smoother transition to the new software version.

For more detailed information, refer to the defect report [CSCvv04251][62], which outlines specific scenarios and resolutions related to hardware change indicators.


[0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script
[1]: https://www.cisco.com/c/dam/en/us/td/docs/Website/datacenter/apicmatrix/index.html
[2]: https://www.cisco.com/c/en/us/support/switches/nexus-9000-series-switches/products-release-notes-list.html
Expand Down Expand Up @@ -2666,3 +2677,4 @@ If any instances of `configpushShardCont` are flagged by this script, Cisco TAC
[59]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp95515
[60]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#Inter
[61]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#EnablePolicyCompression
[62]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvv04251
130 changes: 130 additions & 0 deletions tests/checks/HW_changes_bit_check/FabricNodes_matching.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
[
{
"fabricNode": {
"attributes": {
"adSt": "on",
"address": "10.0.0.12",
"annotation": "",
"apicType": "not-applicable",
"childAction": "",
"delayedHeartbeat": "no",
"dn": "topology/pod-2/node-302",
"extMngdBy": "",
"fabricSt": "active",
"id": "302",
"lastStateModTs": "2025-11-19T08:23:42.755-08:00",
"lcOwn": "local",
"mfgTm": "2019-01-27T16:00:00.000-08:00",
"modTs": "2025-11-19T08:23:55.984-08:00",
"model": "N9K-C9316D-GX",
"monPolDn": "uni/fabric/monfab-default",
"name": "leaf12",
"nameAlias": "",
"nodeType": "unspecified",
"role": "leaf",
"serial": "FDO23051B9A",
"status": "",
"uid": "0",
"userdom": "all",
"vendor": "Cisco Systems, Inc",
"version": "n9000-16.2(0.167)"
}
}
},
{
"fabricNode": {
"attributes": {
"adSt": "on",
"address": "10.0.0.15",
"annotation": "",
"apicType": "not-applicable",
"childAction": "",
"delayedHeartbeat": "no",
"dn": "topology/pod-3/node-303",
"extMngdBy": "",
"fabricSt": "active",
"id": "303",
"lastStateModTs": "2025-11-19T03:51:11.090-08:00",
"lcOwn": "local",
"mfgTm": "2019-01-13T16:00:00.000-08:00",
"modTs": "2025-11-19T03:51:11.348-08:00",
"model": "N9K-C93600CD-GX",
"monPolDn": "uni/fabric/monfab-default",
"name": "leaf15",
"nameAlias": "",
"nodeType": "unspecified",
"role": "leaf",
"serial": "FDO2303039T",
"status": "",
"uid": "0",
"userdom": "all",
"vendor": "Cisco Systems, Inc",
"version": "n9000-16.2(0.167)"
}
}
},
{
"fabricNode": {
"attributes": {
"adSt": "on",
"address": "10.0.0.18",
"annotation": "",
"apicType": "not-applicable",
"childAction": "",
"delayedHeartbeat": "no",
"dn": "topology/pod-2/node-3002",
"extMngdBy": "",
"fabricSt": "active",
"id": "3002",
"lastStateModTs": "2025-11-10T04:19:08.368-08:00",
"lcOwn": "local",
"mfgTm": "2019-03-10T16:00:00.000-08:00",
"modTs": "2025-11-10T04:20:00.475-08:00",
"model": "N9K-C93600CD-GX",
"monPolDn": "uni/fabric/monfab-default",
"name": "spine8",
"nameAlias": "",
"nodeType": "unspecified",
"role": "spine",
"serial": "FDO2311073Q",
"status": "",
"uid": "0",
"userdom": "all",
"vendor": "Cisco Systems, Inc",
"version": "n9000-16.1(4h)"
}
}
},
{
"fabricNode": {
"attributes": {
"adSt": "on",
"address": "10.0.0.19",
"annotation": "",
"apicType": "not-applicable",
"childAction": "",
"delayedHeartbeat": "no",
"dn": "topology/pod-3/node-3003",
"extMngdBy": "",
"fabricSt": "active",
"id": "3003",
"lastStateModTs": "2025-11-08T20:08:39.435-08:00",
"lcOwn": "local",
"mfgTm": "2019-03-03T16:00:00.000-08:00",
"modTs": "2025-11-08T20:08:56.864-08:00",
"model": "N9K-C93600CD-GX",
"monPolDn": "uni/fabric/monfab-default",
"name": "spine9",
"nameAlias": "",
"nodeType": "unspecified",
"role": "spine",
"serial": "FDO23100QX8",
"status": "",
"uid": "0",
"userdom": "all",
"vendor": "Cisco Systems, Inc",
"version": "n9000-16.2(0.167)"
}
}
}
]
Loading