From d24d5e0ec969493299b1c34149a3787d4bec66c8 Mon Sep 17 00:00:00 2001 From: Saket Date: Fri, 26 Sep 2025 09:24:35 +0000 Subject: [PATCH 1/3] feat: Add pre-upgrade warning for APIC 6.2.1 that downgrade is not supported to pre-6.2.1 version. --- aci-preupgrade-validation-script.py | 20 ++++++++++++ docs/docs/validations.md | 12 +++++++ .../test_apic_621_upgrade_warning.py | 32 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index ebe04773..7d05ea36 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6007,6 +6007,25 @@ def apic_vmm_inventory_sync_faults_check(**kwargs): recommended_action=recommended_action, doc_url=doc_url) + +@check_wrapper(check_title='APIC 6.2.1 Upgrade Warning') +def controller_621_pre_warning(cversion, tversion, **kwargs): + result = PASS + headers = ["Current version", "Target Version", "Warning"] + data = [] + recommended_action = '' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#controller-621-pre-warning' + + if not tversion or not cversion: + return Result(result=MANUAL, msg=TVER_MISSING) + if cversion.older_than("6.2(1a)") \ + and (tversion.same_as("6.2(1a)") or tversion.newer_than("6.2(1a)")): + result = MANUAL + data.append([cversion, tversion, "Downgrade from 6.2.1 to pre 6.2.1 is not supported."]) + + return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) + + # ---- Script Execution ---- @@ -6168,6 +6187,7 @@ class CheckManager: standby_sup_sync_check, isis_database_byte_check, configpush_shard_check, + controller_621_pre_warning, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index fa1fc0e4..cd2f7816 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -36,6 +36,7 @@ Items | This Script [6.0(2)+ requires 32 and 64 bit switch images][g16] | :white_check_mark: | :no_entry_sign: [Fabric Link Redundancy][g17] | :white_check_mark: | :no_entry_sign: [APIC Database Size][g18] | :white_check_mark: | :no_entry_sign: +[Controller 6.2.1 Pre Warning][g19] | :white_check_mark: | :no_entry_sign: [g1]: #compatibility-target-aci-version [g2]: #compatibility-cimc-version @@ -55,6 +56,7 @@ Items | This Script [g16]: #602-requires-32-and-64-bit-switch-images [g17]: #fabric-link-redundancy [g18]: #apic-database-size +[g19]: #controller-621-pre-warning ### Fault Checks Items | Faults | This Script | APIC built-in @@ -494,6 +496,16 @@ For current version is 6.1(3f): In either scenario, contact TAC to collect a database dump of the flagged DME(s) and shard(s) for further analysis. +### Controller 6.2.1 Pre Warning + +APIC version 6.2.1 introduces significant limitations that must be considered before upgrading: + +**Downgrade Limitations**: Downgrading from APIC 6.2.1 to any pre-6.2.1 version is not supported and will fail. Once you upgrade to 6.2.1, the policy based downgrade process cannot be used to revert to earlier versions. + +**Recovery Process**: If you need to move from 6.2.1 to a pre-6.2.1 version, you must perform a clean installation of the desired pre-6.2.1 version followed by an ID recovery process. This involves: + +1. Performing a clean install of the target pre-6.2.1 APIC version +2. Executing the ID recovery procedure to restore the APIC configuration and cluster membership ## Fault Check Details diff --git a/tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py b/tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py new file mode 100644 index 00000000..519bcfc9 --- /dev/null +++ b/tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py @@ -0,0 +1,32 @@ +import importlib +import logging +import os +import pytest + +script = importlib.import_module("aci-preupgrade-validation-script") + +log = logging.getLogger(__name__) +dir = os.path.dirname(os.path.abspath(__file__)) + + +@pytest.mark.parametrize( + "cversion, tversion, expected_result", + [ + (None, None, script.MANUAL), + ("4.2(1b)", None, script.MANUAL), + (None, "5.2(2a)", script.MANUAL), + ("5.2(2a)", "6.1(4a)", script.PASS), + ("6.1(3a)", "6.1(4c)", script.PASS), + ("6.1(3a)", "6.2(1a)", script.MANUAL), + ("6.1(3a)", "6.2(2a)", script.MANUAL), + ("6.2(1a)", "6.2(2c)", script.PASS), + ], +) +def test_logic(mock_icurl, cversion, tversion, expected_result): + result = script.controller_621_pre_warning( + 1, + 1, + script.AciVersion(cversion) if cversion else None, + script.AciVersion(tversion) if tversion else None, + ) + assert result == expected_result From b36b627a94f9ffa719780cf6d7e1beabdd5f9541 Mon Sep 17 00:00:00 2001 From: tkishida Date: Wed, 17 Dec 2025 12:42:49 -0800 Subject: [PATCH 2/3] fix: Update doc, default result as NA, rename check name --- aci-preupgrade-validation-script.py | 14 +++---- docs/docs/validations.md | 38 +++++++++++++++---- ...st_apic_downgrade_compat_warning_check.py} | 8 ++-- 3 files changed, 41 insertions(+), 19 deletions(-) rename tests/{apic_621_upgrade_warning/test_apic_621_upgrade_warning.py => apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py} (80%) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 7d05ea36..4b83f4c7 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -6008,20 +6008,20 @@ def apic_vmm_inventory_sync_faults_check(**kwargs): doc_url=doc_url) -@check_wrapper(check_title='APIC 6.2.1 Upgrade Warning') -def controller_621_pre_warning(cversion, tversion, **kwargs): - result = PASS +@check_wrapper(check_title='APIC downgrade compatibility when crossing 6.2 release') +def apic_downgrade_compat_warning_check(cversion, tversion, **kwargs): + result = NA headers = ["Current version", "Target Version", "Warning"] data = [] - recommended_action = '' - doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#controller-621-pre-warning' + recommended_action = 'No action required. Just be aware of the downgrade limitation after the upgrade.' + doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#apic-downgrade-compatibility-when-crossing-62-release' if not tversion or not cversion: return Result(result=MANUAL, msg=TVER_MISSING) if cversion.older_than("6.2(1a)") \ and (tversion.same_as("6.2(1a)") or tversion.newer_than("6.2(1a)")): result = MANUAL - data.append([cversion, tversion, "Downgrade from 6.2.1 to pre 6.2.1 is not supported."]) + data.append([cversion, tversion, "Downgrading APIC from 6.2(1)+ to pre-6.2(1) will not be supported."]) return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) @@ -6113,6 +6113,7 @@ class CheckManager: post_upgrade_cb_check, validate_32_64_bit_image_check, fabric_link_redundancy_check, + apic_downgrade_compat_warning_check, # Faults apic_disk_space_faults_check, @@ -6187,7 +6188,6 @@ class CheckManager: standby_sup_sync_check, isis_database_byte_check, configpush_shard_check, - controller_621_pre_warning, ] ssh_checks = [ diff --git a/docs/docs/validations.md b/docs/docs/validations.md index cd2f7816..68ca1c0b 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -36,7 +36,7 @@ Items | This Script [6.0(2)+ requires 32 and 64 bit switch images][g16] | :white_check_mark: | :no_entry_sign: [Fabric Link Redundancy][g17] | :white_check_mark: | :no_entry_sign: [APIC Database Size][g18] | :white_check_mark: | :no_entry_sign: -[Controller 6.2.1 Pre Warning][g19] | :white_check_mark: | :no_entry_sign: +[APIC downgrade compatibility when crossing 6.2 release][g19]| :white_check_mark: | :no_entry_sign: [g1]: #compatibility-target-aci-version [g2]: #compatibility-cimc-version @@ -56,7 +56,7 @@ Items | This Script [g16]: #602-requires-32-and-64-bit-switch-images [g17]: #fabric-link-redundancy [g18]: #apic-database-size -[g19]: #controller-621-pre-warning +[g19]: #apic-downgrade-compatibility-when-crossing-62-release ### Fault Checks Items | Faults | This Script | APIC built-in @@ -496,16 +496,38 @@ For current version is 6.1(3f): In either scenario, contact TAC to collect a database dump of the flagged DME(s) and shard(s) for further analysis. -### Controller 6.2.1 Pre Warning -APIC version 6.2.1 introduces significant limitations that must be considered before upgrading: +### APIC downgrade compatibility when crossing 6.2 release -**Downgrade Limitations**: Downgrading from APIC 6.2.1 to any pre-6.2.1 version is not supported and will fail. Once you upgrade to 6.2.1, the policy based downgrade process cannot be used to revert to earlier versions. +APIC 6.2(1) release introduces significant optimizations to the APIC upgrade process, including shorter upgrade time and an orchestrated workflow across the cluster with fewer failure points. This release includes an architecture change on APIC, so APIC running 6.2(1) or newer (e.g., 6.2(1a)) cannot be downgraded to any pre-6.2(1) version (e.g., 6.1(4h)). -**Recovery Process**: If you need to move from 6.2.1 to a pre-6.2.1 version, you must perform a clean installation of the desired pre-6.2.1 version followed by an ID recovery process. This involves: +Upgrading from pre-6.2(1) to 6.2(1)+ is supported; however, rollback (downgrade) after such an upgrade is not possible. + +This check alerts you if you are crossing the 6.2 boundary, beyond which downgrade compatibility is lost. No additional user action is required. + +!!! note + Switch upgrade architecture hasn't been changed in 6.2(1)/16.2(1). The limitation of downgrade compatibility between pre-/post-6.2(1) versions is only for APIC. + +!!! example + These are examples for upgrade/downgrade paths to show which downgrade compatibility is lost. + + Upgrade: + + * 6.1(4) -> **6.2(1)**: Supported + * **6.2(1)** -> 6.2(2): Supported + + Downgrade: + + * **6.2(1)** -> 6.1(4): Not Supported !!! - The API request gets rejected on APIC. + * 6.2(2) -> **6.2(1)**: Supported + + Note that this is just one example. See [APIC Upgrade/Downgrade Matrix][2] for the full list of supported version combinations. + +!!! tip + Make sure to collect the latest configuration backup before you upgrade your APICs from pre-6.2(1) to 6.2(1)+ so that Cisco TAC can perform the fabric recovery process in the case of emergency where you need to downgrade your APICs to the previous version (i.e. 6.2(1)+ -> pre-6.2(1)). + + If it's for a lab environment, you can initialize the fabric and perform a fresh ISO installation of pre-6.2(1) on APICs. -1. Performing a clean install of the target pre-6.2.1 APIC version -2. Executing the ID recovery procedure to restore the APIC configuration and cluster membership ## Fault Check Details diff --git a/tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py b/tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py similarity index 80% rename from tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py rename to tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py index 519bcfc9..89806ffd 100644 --- a/tests/apic_621_upgrade_warning/test_apic_621_upgrade_warning.py +++ b/tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py @@ -15,15 +15,15 @@ (None, None, script.MANUAL), ("4.2(1b)", None, script.MANUAL), (None, "5.2(2a)", script.MANUAL), - ("5.2(2a)", "6.1(4a)", script.PASS), - ("6.1(3a)", "6.1(4c)", script.PASS), + ("5.2(2a)", "6.1(4a)", script.NA), + ("6.1(3a)", "6.1(4c)", script.NA), ("6.1(3a)", "6.2(1a)", script.MANUAL), ("6.1(3a)", "6.2(2a)", script.MANUAL), - ("6.2(1a)", "6.2(2c)", script.PASS), + ("6.2(1a)", "6.2(2c)", script.NA), ], ) def test_logic(mock_icurl, cversion, tversion, expected_result): - result = script.controller_621_pre_warning( + result = script.apic_downgrade_compat_warning_check( 1, 1, script.AciVersion(cversion) if cversion else None, From 9e6aa03da0a190902297e1ef5f1fdac63b3b991e Mon Sep 17 00:00:00 2001 From: tkishida Date: Wed, 17 Dec 2025 14:07:20 -0800 Subject: [PATCH 3/3] test: Update pytest to the new style for apic_downgrade_compat_warning_check --- .../test_apic_downgrade_compat_warning_check.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename tests/{ => checks}/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py (65%) diff --git a/tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py b/tests/checks/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py similarity index 65% rename from tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py rename to tests/checks/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py index 89806ffd..2b886869 100644 --- a/tests/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py +++ b/tests/checks/apic_downgrade_compat_warning_check/test_apic_downgrade_compat_warning_check.py @@ -8,6 +8,8 @@ log = logging.getLogger(__name__) dir = os.path.dirname(os.path.abspath(__file__)) +test_function = "apic_downgrade_compat_warning_check" + @pytest.mark.parametrize( "cversion, tversion, expected_result", @@ -22,11 +24,9 @@ ("6.2(1a)", "6.2(2c)", script.NA), ], ) -def test_logic(mock_icurl, cversion, tversion, expected_result): - result = script.apic_downgrade_compat_warning_check( - 1, - 1, - script.AciVersion(cversion) if cversion else None, - script.AciVersion(tversion) if tversion else None, +def test_logic(run_check, mock_icurl, cversion, tversion, expected_result): + result = run_check( + cversion=script.AciVersion(cversion) if cversion else None, + tversion=script.AciVersion(tversion) if tversion else None, ) - assert result == expected_result + assert result.result == expected_result