diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index f68bce96..f5664765 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -52,6 +52,39 @@ # 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)", +) +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, +} # regex constants node_regex = r'topology/pod-(?P\d+)/node-(?P\d+)' port_regex = node_regex + r'/sys/phys-\[(?P.+)\]' @@ -3780,7 +3813,10 @@ def cimc_compatibilty_check(tversion, cversion, **kwargs): if compatMo and recommended_cimc: if not is_firstver_gt_secondver(current_cimc, "3.0(3a)"): warning = "Multi-step Upgrade may be required, check UCS CIMC Matrix." - if not is_firstver_gt_secondver(current_cimc, recommended_cimc): + release_note_supported = current_cimc in CIMC_RELEASE_NOTE_SUPPORT.get( + (tversion.simple_version, model), () + ) + if not release_note_supported and not is_firstver_gt_secondver(current_cimc, recommended_cimc): nodeid = eqptCh['eqptCh']['attributes']['dn'].split('/')[2] data.append([nodeid, apic_model, current_cimc, recommended_cimc, warning]) diff --git a/docs/docs/validations.md b/docs/docs/validations.md index 81cf68fb..c9f91efd 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -264,6 +264,8 @@ 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. + 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]. !!! note diff --git a/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M5.json b/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M5.json new file mode 100644 index 00000000..e66e5870 --- /dev/null +++ b/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M5.json @@ -0,0 +1,10 @@ +[ + { + "compatRsSuppHw": { + "attributes": { + "cimcVersion": "4.3(2.250016)", + "dn": "uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm3]" + } + } + } +] diff --git a/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M6.json b/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M6.json new file mode 100644 index 00000000..74f8a93e --- /dev/null +++ b/tests/checks/cimc_compatibilty_check/compatRsSuppHw_615_M6.json @@ -0,0 +1,10 @@ +[ + { + "compatRsSuppHw": { + "attributes": { + "cimcVersion": "4.3(4.252002)", + "dn": "uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm4]" + } + } + } +] diff --git a/tests/checks/cimc_compatibilty_check/eqptCh_615_supported_423e.json b/tests/checks/cimc_compatibilty_check/eqptCh_615_supported_423e.json new file mode 100644 index 00000000..ce34bb09 --- /dev/null +++ b/tests/checks/cimc_compatibilty_check/eqptCh_615_supported_423e.json @@ -0,0 +1,42 @@ +[ + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3e)", + "descr": "APIC-SERVER-L3", + "dn": "topology/pod-1/node-1/sys/ch", + "model": "APIC-SERVER-L3" + } + } + }, + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3e)", + "descr": "APIC-SERVER-M3", + "dn": "topology/pod-1/node-2/sys/ch", + "model": "APIC-SERVER-M3" + } + } + }, + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3e)", + "descr": "APIC-SERVER-L4", + "dn": "topology/pod-1/node-3/sys/ch", + "model": "APIC-SERVER-L4" + } + } + }, + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3e)", + "descr": "APIC-SERVER-M4", + "dn": "topology/pod-1/node-4/sys/ch", + "model": "APIC-SERVER-M4" + } + } + } +] diff --git a/tests/checks/cimc_compatibilty_check/eqptCh_615_unsupported_423d.json b/tests/checks/cimc_compatibilty_check/eqptCh_615_unsupported_423d.json new file mode 100644 index 00000000..a7cdf801 --- /dev/null +++ b/tests/checks/cimc_compatibilty_check/eqptCh_615_unsupported_423d.json @@ -0,0 +1,22 @@ +[ + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3d)", + "descr": "APIC-SERVER-M3", + "dn": "topology/pod-1/node-1/sys/ch", + "model": "APIC-SERVER-M3" + } + } + }, + { + "eqptCh": { + "attributes": { + "cimcVersion": "4.2(3d)", + "descr": "APIC-SERVER-M4", + "dn": "topology/pod-1/node-2/sys/ch", + "model": "APIC-SERVER-M4" + } + } + } +] diff --git a/tests/checks/cimc_compatibilty_check/test_cimc_compatibilty_check.py b/tests/checks/cimc_compatibilty_check/test_cimc_compatibilty_check.py index 4db1b7ea..1092eca9 100644 --- a/tests/checks/cimc_compatibilty_check/test_cimc_compatibilty_check.py +++ b/tests/checks/cimc_compatibilty_check/test_cimc_compatibilty_check.py @@ -21,10 +21,79 @@ compatRsSuppHwM4_605_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.0(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm4].json' compatRsSuppHwL4_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicl4].json' compatRsSuppHwM4_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm4].json' +compatRsSuppHwL3_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicl3].json' +compatRsSuppHwM3_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.1(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm3].json' + +release_note_supported_615_outputs = { + eqptCh_api: read_data(dir, "eqptCh_615_supported_423e.json"), + compatRsSuppHwL3_api: read_data(dir, "compatRsSuppHw_615_M5.json"), + compatRsSuppHwM3_api: read_data(dir, "compatRsSuppHw_615_M5.json"), + compatRsSuppHwL4_api: read_data(dir, "compatRsSuppHw_615_M6.json"), + 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] + return { + eqptCh_api: [ + { + "eqptCh": { + "attributes": { + "cimcVersion": cimc_version, + "descr": apic_model, + "dn": "topology/pod-1/node-1/sys/ch", + "model": apic_model, + } + } + } + ], + compat_api: read_data(dir, compat_fixture), + } + + +release_note_supported_cases = [ + release_note_supported_outputs(model, cimc_version) + for (target, model), cimc_versions in script.CIMC_RELEASE_NOTE_SUPPORT.items() + if target == "6.1(5)" + for cimc_version in cimc_versions +] @pytest.mark.parametrize( "icurl_outputs, tversion, cversion, expected_result", [ + # CIMC 4.2(3e) is explicitly supported for M5/M6 APICs by the 6.1(5) release notes. + ( + release_note_supported_615_outputs, + "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, + "6.1(5e)", + "5.3(1d)", + script.FAIL_UF, + ), + # Other CIMC versions below the catalog recommendation remain unsupported. + ( + { + eqptCh_api: read_data(dir, "eqptCh_615_unsupported_423d.json"), + compatRsSuppHwM3_api: read_data(dir, "compatRsSuppHw_615_M5.json"), + compatRsSuppHwM4_api: read_data(dir, "compatRsSuppHw_615_M6.json"), + }, + "6.1(5e)", + "5.2(8g)", + script.FAIL_UF, + ), #m4/l4 model check and targeting affected version and cversion affected and cimc < 4.3.5 ( {eqptCh_api: read_data(dir, "eqptCh_m4l4_model_old_cimc.json"), @@ -102,3 +171,12 @@ def test_logic(run_check, mock_icurl, tversion, cversion, expected_result): result = run_check(tversion=script.AciVersion(tversion), cversion=script.AciVersion(cversion) if cversion is not None else None) assert result.result == expected_result + + +@pytest.mark.parametrize("icurl_outputs", release_note_supported_cases) +def test_release_note_supported_versions(run_check, mock_icurl): + result = run_check( + tversion=script.AciVersion("6.1(5e)"), + cversion=script.AciVersion("5.2(8g)"), + ) + assert result.result == script.PASS