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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,23 @@ For every check that has been flagged as `FAIL`, a general recommended action ha

[1]: https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/
[2]: https://www.cisco.com/c/en/us/td/docs/switches/datacenter/aci/apic/sw/all/apic-installation-upgrade-downgrade/Cisco-APIC-Installation-Upgrade-Downgrade-Guide.html

# Maintainer Workflows

## Refresh CIMC Release-Note Support

Before preparing a script release, add any new APIC target release, its Cisco
release-note URL, expected APIC models, and per-model minimum version counts to
`tools/cimc_release_note_sources.json`, then run:

```sh
python tools/update_cimc_release_note_support.py
python tools/update_cimc_release_note_support.py --check
```

The updater extracts supported CIMC versions by APIC model, ignores deferred
releases, normalizes Cisco's displayed version format, and rejects incomplete
or unrecognized model mappings. Legacy entries without model applicability must
be explicitly listed as ignored in the source configuration. The updater then
refreshes the generated data embedded in `aci-preupgrade-validation-script.py`.
Review the generated diff and run the test suite before publishing the script.
131 changes: 99 additions & 32 deletions aci-preupgrade-validation-script.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
import os
import re

SCRIPT_VERSION = "v4.2.0"
SCRIPT_VERSION = "v4.2.1"
DEFAULT_TIMEOUT = 600 # sec
# result constants
DONE = 'DONE'
Expand All @@ -52,39 +52,106 @@
# message constants
TVER_MISSING = "Target version not supplied. Skipping."
VER_NOT_AFFECTED = "Version not affected."
# APIC 6.1(5) release notes, verified 2026-08-10.
CIMC_RELEASE_NOTE_SUPPORT_615_M5 = (
"4.3(2.260007)",
"4.3(2.250016)",
"4.3(2.240077)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
"4.2(2a)",
"4.1(3m)",
"4.1(3f)",
"4.1(3d)",
"4.1(3c)",
)
CIMC_RELEASE_NOTE_SUPPORT_615_M6 = (
"6.0(2.260044)",
"6.0(1.250192)",
"6.0(1.250131)",
"4.3(6.250053)",
"4.3(4.252002)",
"4.3(4.241063)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
)
# BEGIN GENERATED CIMC RELEASE NOTE SUPPORT
# Generated by tools/update_cimc_release_note_support.py; do not edit manually.
CIMC_RELEASE_NOTE_SUPPORT = {
("6.1(5)", "apicl3"): CIMC_RELEASE_NOTE_SUPPORT_615_M5,
("6.1(5)", "apicm3"): CIMC_RELEASE_NOTE_SUPPORT_615_M5,
("6.1(5)", "apicl4"): CIMC_RELEASE_NOTE_SUPPORT_615_M6,
("6.1(5)", "apicm4"): CIMC_RELEASE_NOTE_SUPPORT_615_M6,
("6.1(5)", "apicg5"): (
"6.0(2.260143)",
"6.0(2.260044)",
"6.0(1.250192)",
"6.0(1.250131)",
"4.3(6.250044)",
),
("6.1(5)", "apicl2"): (
"4.1(2m)",
"4.1(2k)",
"4.1(2g)",
"4.1(2b)",
"4.1(1g)",
"4.1(1c)",
"4.0(2g)",
"3.0(4d)",
"3.0(3f)",
),
("6.1(5)", "apicl3"): (
"4.3(2.260020)",
"4.3(2.260007)",
"4.3(2.250016)",
"4.3(2.240077)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
"4.2(2a)",
"4.1(3m)",
"4.1(3f)",
"4.1(3d)",
"4.1(3c)",
"4.1(1g)",
"4.1(1d)",
"4.0(4e)",
"4.0(2g)",
"4.0(1a)",
),
("6.1(5)", "apicl4"): (
"6.0(2.260143)",
"6.0(2.260044)",
"6.0(1.250192)",
"6.0(1.250131)",
"4.3(6.250053)",
"4.3(4.252002)",
"4.3(4.241063)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
),
("6.1(5)", "apicm2"): (
"4.1(2m)",
"4.1(2k)",
"4.1(2g)",
"4.1(2b)",
"4.1(1g)",
"4.1(1c)",
"4.0(2g)",
"3.0(4d)",
"3.0(3f)",
),
("6.1(5)", "apicm3"): (
"4.3(2.260020)",
"4.3(2.260007)",
"4.3(2.250016)",
"4.3(2.240077)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
"4.2(2a)",
"4.1(3m)",
"4.1(3f)",
"4.1(3d)",
"4.1(3c)",
"4.1(1g)",
"4.1(1d)",
"4.0(4e)",
"4.0(2g)",
"4.0(1a)",
),
("6.1(5)", "apicm4"): (
"6.0(2.260143)",
"6.0(2.260044)",
"6.0(1.250192)",
"6.0(1.250131)",
"4.3(6.250053)",
"4.3(4.252002)",
"4.3(4.241063)",
"4.3(2.240009)",
"4.3(2.230207)",
"4.2(3e)",
"4.2(3b)",
),
}
# END GENERATED CIMC RELEASE NOTE SUPPORT
# regex constants
node_regex = r'topology/pod-(?P<pod>\d+)/node-(?P<node>\d+)'
port_regex = node_regex + r'/sys/phys-\[(?P<port>.+)\]'
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ The script checks the minimum recommended CIMC version for the given APIC model

As the `compatRsSuppHw` object recommendation is strictly tied to the target software image, it is possible that the [Release Note Documentation][4] for your model/target version has a different recommendation than what the software recommends. Always check the release note of your Target version and APIC model to ensure you are getting the latest recommendations.

The APIC 6.1(5) release notes explicitly support multiple CIMC releases on UCS C220/C240 M5 (APIC-L3/M3) and UCS C225 M6 (APIC-L4/M4) that may be older than the image catalog recommendation. The check uses an embedded, model-specific list for those release-note-supported combinations before applying the image catalog recommendation to other CIMC releases.
The APIC release notes explicitly support multiple model-specific CIMC releases that may be older than the image catalog recommendation. The check uses release-note support data refreshed from Cisco documentation during script release preparation before applying the image catalog recommendation to other CIMC releases. The released validator remains standalone and does not require internet access.

Due to the defect CSCwo74485, APIC-SERVER-M4/L4 systems will fail to boot correctly after upgrading CIMC firmware to version 4.3.5 or later while on Non-fixed APIC releases 5.3.x/6.0.9d/6.1(3g) and below. Upgrade the APIC software first, then proceed with the CIMC upgrade for the releases 6.0.9e/ 6.1.4h and above, will avoid this issue. Follow the software advisory for this defect [CSCwo74485][73].

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,12 @@
compatRsSuppHwM4_api: read_data(dir, "compatRsSuppHw_615_M6.json"),
}

release_note_model_data = {
"apicl3": ("APIC-SERVER-L3", compatRsSuppHwL3_api, "compatRsSuppHw_615_M5.json"),
"apicm3": ("APIC-SERVER-M3", compatRsSuppHwM3_api, "compatRsSuppHw_615_M5.json"),
"apicl4": ("APIC-SERVER-L4", compatRsSuppHwL4_api, "compatRsSuppHw_615_M6.json"),
"apicm4": ("APIC-SERVER-M4", compatRsSuppHwM4_api, "compatRsSuppHw_615_M6.json"),
}


def release_note_supported_outputs(model, cimc_version):
apic_model, compat_api, compat_fixture = release_note_model_data[model]
apic_model = "APIC-SERVER-{}".format(model[4:].upper())
compat_api = (
"uni/fabric/compcat-default/ctlrfw-apic-6.1(5)"
"/rssuppHw-[uni/fabric/compcat-default/ctlrhw-{}].json".format(model)
)
return {
eqptCh_api: [
{
Expand All @@ -55,7 +51,16 @@ def release_note_supported_outputs(model, cimc_version):
}
}
],
compat_api: read_data(dir, compat_fixture),
compat_api: [
{
"compatRsSuppHw": {
"attributes": {
"cimcVersion": "9.9(9z)",
"dn": compat_api[:-5],
}
}
}
],
}


Expand All @@ -76,6 +81,13 @@ def release_note_supported_outputs(model, cimc_version):
"5.2(8g)",
script.PASS,
),
# Issue #435: CIMC 4.1(1g) is release-note supported on APIC-L3/M3.
(
release_note_supported_outputs("apicl3", "4.1(1g)"),
"6.1(5e)",
"5.2(8g)",
script.PASS,
),
# The release-note exception must not bypass the CSCwo74485 upgrade ordering check.
(
release_note_supported_615_outputs,
Expand Down
82 changes: 82 additions & 0 deletions tests/tools/test_update_cimc_release_note_support.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import pytest

from tools import update_cimc_release_note_support as updater


RELEASE_NOTE_HTML = """
<html>
<body>
<table>
<tr><th>Product</th><th>Supported Release</th></tr>
<tr>
<td>CIMC HUU ISO</td>
<td>
<p>Note: Install only the CIMC versions mentioned here.</p>
<p>6.0.2.260143 (recommended) CIMC HUU ISO for UCS C225 M8 (APIC-G5)</p>
<p>4.3.6.250053 CIMC HUU ISO (recommended) for UCS C225 M6 (APIC-L4/M4)</p>
<p>4.1(1g) CIMC HUU ISO for UCS C220/C240 M4 (APIC-L2/M2) and M5 (APIC-L3/M3)</p>
<p>4.1(1d) CIMC HUU ISO for UCS C220 M5 (APIC-L3/M3)</p>
<p>4.0(2g) CIMC HUU ISO for UCS C220/C240 M4 and M5 (APIC-L2/M2 and APIC-L3/M3)</p>
<p>2.0(13i) CIMC HUU ISO</p>
<p>4.1(2a) CIMC HUU ISO for UCS C220 M4 (APIC-L2/M2) (deferred release)</p>
</td>
</tr>
</table>
</body>
</html>
"""


def test_extract_cimc_support_maps_models_and_normalizes_versions():
support = updater.extract_cimc_support(
RELEASE_NOTE_HTML, ignored_unqualified_versions=["2.0(13i)"]
)

assert support["apicg5"] == ["6.0(2.260143)"]
assert support["apicl4"] == ["4.3(6.250053)"]
assert support["apicm4"] == ["4.3(6.250053)"]
assert support["apicl3"] == ["4.1(1g)", "4.1(1d)", "4.0(2g)"]
assert support["apicm3"] == ["4.1(1g)", "4.1(1d)", "4.0(2g)"]
assert support["apicl2"] == ["4.1(1g)", "4.0(2g)"]
assert support["apicm2"] == ["4.1(1g)", "4.0(2g)"]


def test_extract_cimc_support_rejects_missing_table():
with pytest.raises(ValueError):
updater.extract_cimc_support("<html><body>No compatibility table</body></html>")


def test_extract_cimc_support_rejects_unknown_unqualified_version():
with pytest.raises(ValueError):
updater.extract_cimc_support(RELEASE_NOTE_HTML)


def test_collect_support_rejects_model_specific_version_loss():
sources = {
"6.1(5)": {
"url": "https://example.invalid/release-notes",
"expected_models": ["apicl3"],
"minimum_versions_per_model": {"apicl3": 4},
"ignored_unqualified_versions": ["2.0(13i)"],
}
}

with pytest.raises(ValueError):
updater.collect_support(sources, fetcher=lambda url: RELEASE_NOTE_HTML)


def test_replace_generated_block_requires_exact_markers():
with pytest.raises(ValueError):
updater.replace_generated_block("CIMC_RELEASE_NOTE_SUPPORT = {}", "generated")


def test_render_generated_block_is_deterministic():
support = {
("6.1(5)", "apicl3"): ("4.1(1g)", "4.1(1d)"),
("6.1(5)", "apicg5"): ("6.0(2.260143)",),
}

generated = updater.render_generated_block(support)

assert generated.index('"apicg5"') < generated.index('"apicl3"')
assert generated.index('"4.1(1g)"') < generated.index('"4.1(1d)"')
Empty file added tools/__init__.py
Empty file.
28 changes: 28 additions & 0 deletions tools/cimc_release_note_sources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"6.1(5)": {
"url": "https://www.cisco.com/c/en/us/td/docs/dcn/aci/apic/6x/release-notes/cisco-apic-release-notes-615.html#Miscellaneouscompatibilityinformation",
"expected_models": [
"apicg5",
"apicl2",
"apicl3",
"apicl4",
"apicm2",
"apicm3",
"apicm4"
],
"minimum_versions_per_model": {
"apicg5": 5,
"apicl2": 9,
"apicl3": 18,
"apicl4": 11,
"apicm2": 9,
"apicm3": 18,
"apicm4": 11
},
"ignored_unqualified_versions": [
"2.0(13i)",
"2.0(9c)",
"2.0(3i)"
]
}
}
Loading
Loading