Skip to content

Commit 8b6e30e

Browse files
committed
Update version check, query mo instead of class, fail type, doc, pytest
1 parent af18002 commit 8b6e30e

6 files changed

Lines changed: 192 additions & 101 deletions

File tree

aci-preupgrade-validation-script.py

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6027,24 +6027,25 @@ def apic_downgrade_compat_warning_check(cversion, tversion, **kwargs):
60276027

60286028

60296029
@check_wrapper(check_title='Auto Firmware Update on Switch Discovery')
6030-
def auto_firmware_update_ondiscovery_check(cversion, tversion, **kwargs):
6031-
result = NA
6032-
headers = ["Auto firmware Policy Dn", "Switch enforced Version"]
6030+
def auto_firmware_update_on_switch_check(cversion, tversion, **kwargs):
6031+
result = PASS
6032+
headers = ["Auto Firmware Update Status", "Default Firmware Version", "Upgrade Target Version"]
60336033
data = []
6034-
recommended_action = 'Disable the Auto Firmware Update on Switch Discovery policy before upgrade'
6034+
recommended_action = 'Disable Auto Firmware Update before the upgrade as a precaution. See the reference doc for details.'
60356035
doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#auto-firmware-update-on-switch-discovery'
6036-
6036+
60376037
if not tversion or not cversion:
60386038
return Result(result=MANUAL, msg=TVER_MISSING)
6039-
if (cversion.older_than("5.2(7a)") and tversion.newer_than("6.0(3a)")) or (cversion.older_than("6.0(3a)") and tversion.newer_than("6.0(3a)")):
6040-
result = PASS
6041-
auto_firmware_update_api = 'firmwareRepoP.json'
6042-
auto_firmware_update_api += '?query-target-filter=eq(firmwareRepoP.enforceBootscriptVersionValidation,"true")'
6043-
auto_firmware_update = icurl('class', auto_firmware_update_api)
6044-
if auto_firmware_update:
6045-
data.append([auto_firmware_update[0]["firmwareRepoP"]["attributes"]["dn"], auto_firmware_update[0]["firmwareRepoP"]["attributes"]["defaultSwitchVersion"]])
6046-
if data:
6047-
result = FAIL_O
6039+
6040+
if tversion.older_than("6.0(3a)") or (
6041+
cversion.newer_than("6.0(3a)") or (cversion.major1 == "5" and cversion.newer_than("5.2(8a)"))
6042+
):
6043+
return Result(result=NA, msg=VER_NOT_AFFECTED)
6044+
6045+
fwrepop = icurl("mo", "uni/fabric/fwrepop.json")
6046+
if fwrepop and fwrepop[0]["firmwareRepoP"]["attributes"]["enforceBootscriptVersionValidation"] == "yes":
6047+
data.append(["Enabled", fwrepop[0]["firmwareRepoP"]["attributes"]["defaultSwitchVersion"], str(tversion)])
6048+
result = MANUAL
60486049

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

@@ -6210,7 +6211,7 @@ class CheckManager:
62106211
standby_sup_sync_check,
62116212
isis_database_byte_check,
62126213
configpush_shard_check,
6213-
auto_firmware_update_ondiscovery_check,
6214+
auto_firmware_update_on_switch_check,
62146215

62156216
]
62166217
ssh_checks = [

docs/docs/validations.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2650,11 +2650,22 @@ If any instances of `configpushShardCont` are flagged by this script, Cisco TAC
26502650

26512651
### Auto Firmware Update on Switch Discovery
26522652

2653-
Due to [CSCwe83941][62] if 'Auto Firmware Update on Switch Discovery' is enabled with the target release of 16.0(3) and later, a new switch commissioned to ACI Fabric could fail discovery.
2653+
[Auto Firmware Update on Switch Discovery][63] automatically upgrades a new switch to the target firmware version before registering it to the ACI fabric. This feature activates in three scenarios:
26542654

2655-
The download of firmware image fails, causing the switch to become "soft-brick" , the switch needs to be recovered.
2655+
* when adding a new switch to expand the fabric
2656+
* when replacing an existing switch
2657+
* when initializing and rediscovering an existing switch
26562658

2657-
Do not upgrade with 'Auto Firmware Update on Switch Discovery' enabled, to avoid this escenario.
2659+
It does not activate during regular upgrades initiated through the APIC.
2660+
2661+
Due to [CSCwe83941][62], if a new switch is running 6.0(1), 6.0(2) or any version older than 5.2(8), attempting to upgrade it to 6.0(3)+ using Auto Firmware Update will fail. The switch will become unusable until a manual recovery procedure is performed directly on the device.
2662+
2663+
While this issue does not occur during standard upgrades, it is important to be aware of the risk when your target version is 6.0(3) or newer and the switch is running 6.0(1), 6.0(2), or a version older than 5.2(8). Auto Firmware Update may get triggered and hit this issue during switch replacement in an upgrade window or if you need to re-initialize a switch after a failed upgrade.
2664+
2665+
To avoid this risk, consider disabling Auto Firmware Update before upgrading to 6.0(3)+ if any switches are running the affected older versions. In the future, ensure that any new switch is running a compatible version before re-enabling Auto Firmware Update and registering it to the fabric.
2666+
2667+
!!! note
2668+
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.
26582669

26592670

26602671
[0]: https://github.com/datacenter/ACI-Pre-Upgrade-Validation-Script
@@ -2719,4 +2730,5 @@ Do not upgrade with 'Auto Firmware Update on Switch Discovery' enabled, to avoi
27192730
[59]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwp95515
27202731
[60]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#Inter
27212732
[61]: https://www.cisco.com/c/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/white-paper-c11-743951.html#EnablePolicyCompression
2722-
[62]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwe83941
2733+
[62]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwe83941
2734+
[63]: https://www.cisco.com/c/en/us/td/docs/dcn/aci/apic/all/apic-installation-aci-upgrade-downgrade/Cisco-APIC-Installation-ACI-Upgrade-Downgrade-Guide/m-auto-firmware-update.html
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
[
2+
{
3+
"firmwareRepoP": {
4+
"attributes": {
5+
"annotation": "",
6+
"childAction": "",
7+
"defaultSwitchVersion": "n9000-16.0(9d)",
8+
"descr": "",
9+
"dn": "uni/fabric/fwrepop",
10+
"enforceBootscriptVersionValidation": "no",
11+
"extMngdBy": "",
12+
"lcOwn": "local",
13+
"modTs": "2025-08-13T17:50:54.830+00:00",
14+
"monPolDn": "uni/fabric/monfab-default",
15+
"name": "default",
16+
"nameAlias": "",
17+
"ownerKey": "",
18+
"ownerTag": "",
19+
"status": "",
20+
"uid": "0",
21+
"userdom": "all"
22+
}
23+
}
24+
}
25+
]

tests/checks/auto_firmware_update_ondiscovery_check/firmwareRepoP-pos.json renamed to tests/checks/auto_firmware_update_on_switch_check/firmwareRepoP-pos.json

File renamed without changes.
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import os
2+
import pytest
3+
import logging
4+
import importlib
5+
from helpers.utils import read_data
6+
7+
script = importlib.import_module("aci-preupgrade-validation-script")
8+
9+
log = logging.getLogger(__name__)
10+
dir = os.path.dirname(os.path.abspath(__file__))
11+
12+
test_function = "auto_firmware_update_on_switch_check"
13+
14+
# icurl queries
15+
auto_firmware_update_api = "uni/fabric/fwrepop.json"
16+
17+
18+
@pytest.mark.parametrize(
19+
"icurl_outputs, cversion, tversion, expected_result, expected_data",
20+
[
21+
# MANUAL cases
22+
(
23+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
24+
None,
25+
None,
26+
script.MANUAL,
27+
[],
28+
),
29+
(
30+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
31+
"5.2(7a)",
32+
None,
33+
script.MANUAL,
34+
[],
35+
),
36+
(
37+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
38+
None,
39+
"6.0(3d)",
40+
script.MANUAL,
41+
[],
42+
),
43+
# NA cases
44+
# firmwareRepoP cversion < 5.2(7) , tversion < 6.0(3) Result NA
45+
(
46+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
47+
"5.2(7a)",
48+
"6.0(2d)",
49+
script.NA,
50+
[],
51+
),
52+
# firmwareRepoP 5.2(7) < cversion < 6.0(1) , tversion < 6.0(3) Result NA
53+
(
54+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
55+
"5.3(2a)",
56+
"6.0(2d)",
57+
script.NA,
58+
[],
59+
),
60+
# firmwareRepoP 5.2(7) < cversion < 6.0(1) , tversion > 6.0(3) Result NA
61+
(
62+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
63+
"5.3(2a)",
64+
"6.0(9d)",
65+
script.NA,
66+
[],
67+
),
68+
# firmwareRepoP cversion > 6.0(3) , tversion > 6.0(3) Result NA
69+
(
70+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
71+
"6.0(3d)",
72+
"6.0(9d)",
73+
script.NA,
74+
[],
75+
),
76+
# Failure cases
77+
# firmwareRepoP cversion < 5.2(7) , tversion > 6.0(3) Result MANUAL
78+
(
79+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
80+
"5.2(7a)",
81+
"6.0(3d)",
82+
script.MANUAL,
83+
[["Enabled", "n9000-16.0(9d)", "6.0(3d)"]],
84+
),
85+
# firmwareRepoP cversion is 6.0(1) or 6.0(2) , tversion > 6.0(3) Result MANUAL
86+
(
87+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-pos.json")},
88+
"6.0(2a)",
89+
"6.0(3d)",
90+
script.MANUAL,
91+
[["Enabled", "n9000-16.0(9d)", "6.0(3d)"]],
92+
),
93+
# Pass cases
94+
# no firmwareRepoP cversion is < 5.2(7) , tversion > 6.0(3) Result PASS
95+
(
96+
{auto_firmware_update_api: []},
97+
"5.2(7a)",
98+
"6.0(3d)",
99+
script.PASS,
100+
[],
101+
),
102+
# no firmwareRepoP cversion is 6.0(1) or 6.0(2) , tversion > 6.0(3) Result PASS
103+
(
104+
{auto_firmware_update_api: []},
105+
"6.0(2a)",
106+
"6.0(3d)",
107+
script.PASS,
108+
[],
109+
),
110+
# no firmwareRepoP cversion is < 5.2(7) , tversion > 6.0(3) Result PASS
111+
(
112+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-neg.json")},
113+
"5.2(7a)",
114+
"6.0(3d)",
115+
script.PASS,
116+
[],
117+
),
118+
# no firmwareRepoP cversion is 6.0(1) or 6.0(2) , tversion > 6.0(3) Result PASS
119+
(
120+
{auto_firmware_update_api: read_data(dir, "firmwareRepoP-neg.json")},
121+
"6.0(2a)",
122+
"6.0(3d)",
123+
script.PASS,
124+
[],
125+
),
126+
],
127+
)
128+
def test_logic(run_check, mock_icurl, cversion, tversion, expected_result, expected_data):
129+
130+
result = run_check(
131+
cversion=script.AciVersion(cversion) if cversion else None,
132+
tversion=script.AciVersion(tversion) if tversion else None,
133+
)
134+
assert result.result == expected_result
135+
assert result.data == expected_data

tests/checks/auto_firmware_update_ondiscovery_check/test_auto_firmware_update_ondiscovery_check.py

Lines changed: 0 additions & 82 deletions
This file was deleted.

0 commit comments

Comments
 (0)