Skip to content
Open
93 changes: 90 additions & 3 deletions aci-preupgrade-validation-script.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from textwrap import TextWrapper
from getpass import getpass
from collections import defaultdict, OrderedDict
from datetime import datetime
from datetime import datetime, timedelta
Comment thread
monrog2 marked this conversation as resolved.
from argparse import ArgumentParser
from itertools import chain
import threading
Expand Down Expand Up @@ -6293,6 +6293,9 @@ def is_affected_target(ver):
in_61 = ver.newer_than("6.1(1a)") and ver.older_than("6.1(4h)")
return in_60 or in_61

if not tversion or not cversion:
return Result(result=MANUAL, msg=TVER_MISSING)

pre_apic_upg = is_affected_source(cversion) and is_affected_target(tversion) # Before APIC upgrade
post_apic_upg = is_affected_target(cversion) and is_affected_target(tversion) and cversion.same_as(tversion) # After APIC upgrade (and before switch)

Expand Down Expand Up @@ -6477,6 +6480,9 @@ def inband_management_policy_misconfig_check(cversion, tversion, **kwargs):
recommended_action = "Contact Cisco TAC to remove any identified misconfigured 'mgmtRsInBStNode' objects"
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#inband-management-policy-misconfiguration"

if not tversion or not cversion:
return Result(result=MANUAL, msg=TVER_MISSING)

if (cversion.older_than("5.2(8d)")) and (tversion.newer_than("6.0(4c)") or tversion.same_as("6.0(4c)")):
mgmtRsInBStNodes = icurl('class', 'mgmtRsInBStNode.json?query-target-filter=and(or(eq(mgmtRsInBStNode.addr,"0.0.0.0"),eq(mgmtRsInBStNode.gw,"0.0.0.0")),or(eq(mgmtRsInBStNode.v6Addr,"::"),eq(mgmtRsInBStNode.v6Gw,"::")))')
for mgmtRsInBStNode in mgmtRsInBStNodes:
Expand Down Expand Up @@ -6685,7 +6691,12 @@ def stale_dbgacEpgSummaryTask_check(tversion, **kwargs):
if tversion and ((tversion.major1 == "6" and tversion.major2 == "1" and tversion.newer_than("6.1(5e)")) or tversion.newer_than("6.2(1g)")):
return Result(result=NA, msg=VER_NOT_AFFECTED, doc_url=doc_url)

threshold = datetime.utcnow() - timedelta(hours=24)
try:
from datetime import timezone
threshold = datetime.now(timezone.utc).replace(tzinfo=None) - timedelta(hours=24)
except ImportError:
threshold = datetime.utcnow() - timedelta(hours=24)
Comment on lines +6694 to +6698

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this potion is needed to cover

 /data/techsupport/muthu/aci-preupgrade-validation-script.py:6688: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
threshold = datetime.utcnow() - timedelta(hours=24)

Python version	          Path taken	                                                                              Result
Python 2.x	          ImportError caught → datetime.utcnow()	                             ✅ Works
Python 3.0–3.11.        timezone import succeeds → datetime.now(timezone.utc)	✅ Works, no warning
Python 3.12+	         timezone import succeeds → datetime.now(timezone.utc)	✅ Works, no deprecation warning


for obj in icurl("class", 'dbgacEpgSummaryTask.json?query-target-filter=eq(dbgacEpgSummaryTask.operSt,"processing")'):
attr = obj["dbgacEpgSummaryTask"]["attributes"]
dn = attr.get("dn", "")
Expand All @@ -6702,6 +6713,81 @@ def stale_dbgacEpgSummaryTask_check(tversion, **kwargs):
return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url)


@check_wrapper(check_title="InfraVLAN Overlap in Access Policy VLAN Pools")
def infravlan_overlap_access_policy_check(tversion, **kwargs):
result = FAIL_UF
msg = ""
headers = ["InfraVLAN", "Encap Block", "VLAN Pool DN"]
unformatted_headers = ["InfraVLAN", "Encap Block", "VLAN Pool DN"]

data = []
unformatted_data = []
recommended_action = "Remove InfraVLAN from VLAN pool block highligted or upgrade to fix version"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Do not prescribe unsupported edits to orchestrator-managed blocks. The current CSCwt58626 defect record lists Workaround: NA, and this check intentionally includes VMM/Kubernetes blocks generated by acc-provision. Telling users to remove the InfraVLAN from those blocks may direct them to make unsupported changes that are regenerated by the orchestrator. Please align this guidance with the authoritative record—for example, select a non-affected target or contact Cisco TAC for remediation guidance—and add coverage for the emitted recommended_action and doc_url.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RNE should be updated with proper workaround steps we are proposing here


doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#infravlan-overlap-access-policy-check"

if not tversion:
return Result(result=MANUAL, msg=TVER_MISSING)

if not (tversion.same_as("6.2(1g)") or (
not tversion.older_than("6.1(3f)") and not tversion.newer_than("6.1(5e)")
Comment thread
muthu-ku marked this conversation as resolved.
)):
Comment thread
monrog2 marked this conversation as resolved.
return Result(result=NA, msg=VER_NOT_AFFECTED)

dn_regex1 = r'uni/infra/vlanns-\[.+\]-(static|dynamic)/from-\[vlan-\d+\]-to-\[vlan-\d+\]'

dn_regex2 = r'uni/vmmp-[^/]+/dom-[^/]+/.+/from-\[vlan-\d+\]-to-\[vlan-\d+\]'

infra_vlan = None
has_error = False
lldpInsts = icurl('class', 'lldpInst.json?query-target-filter=wcard(lldpInst.dn,"/node-1/")')
for lldpInst in lldpInsts:
infra_vlan_id = lldpInst.get('lldpInst', {}).get('attributes', {}).get('infraVlan')
if not infra_vlan_id:
continue
match = re.search(r'\d+', str(infra_vlan_id))
if match:
infra_vlan = int(match.group(0))
break

if infra_vlan is None:
return Result(result=ERROR, msg="Unable to determine InfraVLAN from lldpInst.")

encap_blocks = icurl('class', 'fvnsEncapBlk.json?query-target-filter=eq(fvnsEncapBlk.role,"external")')
for obj in encap_blocks:
blk_attr = obj.get('fvnsEncapBlk', {}).get('attributes', {})
Comment thread
muthu-ku marked this conversation as resolved.
dn = blk_attr.get('dn', '')
from_encap = blk_attr.get('from')
to_encap = blk_attr.get('to')

if not dn or not from_encap or not to_encap:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve incomplete overlapping blocks in the failure evidence. This path sets has_error and drops the object entirely. Case 16 already includes a missing-DN block whose from/to range contains the InfraVLAN, but the test expects no unformatted_data; because a later valid overlap keeps the overall result at FAIL_UF, the operator sees neither the omitted affected block nor the incomplete-inventory warning added by AciResult. That can lead them to remediate only the displayed pool and leave another upgrade-impacting overlap. When enough range information exists to establish overlap, preserve the available identifier (dn or rn, with a placeholder if necessary) in unformatted_data, continue scanning, and update Case 16 to assert that evidence and warning.

has_error = True
continue

try:
from_vlan = int(str(from_encap).split('-')[-1])
to_vlan = int(str(to_encap).split('-')[-1])
except (ValueError, TypeError):
has_error = True
continue

if min(from_vlan, to_vlan) <= infra_vlan <= max(from_vlan, to_vlan):
row = [str(infra_vlan), "{} to {}".format(from_encap, to_encap), dn]
if re.search(dn_regex1, dn) or re.search(dn_regex2, dn):
data.append(row)
else:
unformatted_data.append(row)

if not data and not unformatted_data:
result = PASS
if has_error:
result = ERROR
msg = "Overlap check for InfraVLAN {} could not be determined because one or more VLAN pool blocks contain improper data or Error while fetching data.".format(infra_vlan)


return Result(result=result, msg=msg, headers=headers, data=data, unformatted_headers=unformatted_headers, unformatted_data=unformatted_data, recommended_action=recommended_action, doc_url=doc_url)


# ---- Script Execution ----


Expand Down Expand Up @@ -6877,7 +6963,8 @@ class CheckManager:
wred_affected_model_check,
n9k_c93180yc_fx3_switch_memory_check,
stale_dbgacEpgSummaryTask_check,

infravlan_overlap_access_policy_check,

]
ssh_checks = [
# General
Expand Down
10 changes: 9 additions & 1 deletion docs/docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ Items | Defect | This Script
[WRED with Affected FM Models][d35] | CSCwt50713 | :white_check_mark: | :no_entry_sign:
[N9K-C93180YC-FX3 Switch Memory Less Than 32GB][d36] | CSCwm42741 | :white_check_mark: | :no_entry_sign:
[Stale dbgacEpgSummaryTask Objects][d37] | CSCwt69100 | :white_check_mark: | :no_entry_sign:
[InfraVLAN Overlap in Access Policy VLAN Pools][d38] | CSCwt58626 | :white_check_mark: | :no_entry_sign:

[d1]: #ep-announce-compatibility
[d2]: #eventmgr-db-size-defect-susceptibility
Expand Down Expand Up @@ -244,6 +245,7 @@ Items | Defect | This Script
[d35]: #wred-with-affected-fm-models
[d36]: #n9k-c93180yc-fx3-switch-memory-less-than-32gb
[d37]: #stale-dbgacepgsummarytask-objects
[d38]: #infravlan-overlap-access-policy-check

## General Check Details

Expand Down Expand Up @@ -2846,6 +2848,12 @@ Affected versions: 6.1(5e) and below, or 6.2(1g).
Contact Cisco TAC for next steps. For more details, refer to the workaround in [CSCwt69100][75].


### Infravlan Overlap Access Policy Check

Due to the bug [CSCwt58626][77] , If Apic upgrade planned for target versions 6.1(3f), 6.1(3g), 6.1(4h), 6.1(5e) and 6.2(1g), be aware of fault F4701 being raised if the InfraVLAN overlaps with any user-configured VLAN pool in Access Policies. This also affects vlan pool created by NDO/MSO, VMM, Kubernetes. After the upgrade, domains associated with those VLAN pools cannot be linked to new EPGs, although existing EPGs continue to function.
Comment thread
monrog2 marked this conversation as resolved.

To avoid this issue, modify the user VLAN pool ranges so that the InfraVLAN does not overlap with any configured block, or select a non-impacted fixed version. After upgrading to a fixed version this fault and Restriction have been removed.

[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 @@ -2923,4 +2931,4 @@ Contact Cisco TAC for next steps. For more details, refer to the workaround in [
[74]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwm42741
[75]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt69100
[76]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt38698

[77]: https://bst.cloudapps.cisco.com/bugsearch/bug/CSCwt58626
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@
@pytest.mark.parametrize(
"icurl_outputs, cversion, tversion, expected_result, expected_data",
[

# tversion missing
({}, "5.2(7g)", None, script.MANUAL, []),
# cversion missing
({}, None, "5.2(7g)", script.MANUAL, []),
# cversion and tversion missing
({}, None, None, script.MANUAL, []),
# Current version is affected, Target version = 6.0(4c), valid data
(
{
Expand Down Expand Up @@ -158,6 +165,9 @@
],
)
def test_logic(run_check, mock_icurl, cversion, tversion, expected_result, expected_data):
result = run_check(cversion=script.AciVersion(cversion), tversion=script.AciVersion(tversion))
result = run_check(
cversion=script.AciVersion(cversion) if cversion else None,
tversion=script.AciVersion(tversion) if tversion else None,
)
assert result.result == expected_result
assert result.data == expected_data
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-3000]-to-[vlan-4094]",
"role": "external",
"from": "vlan-3000",
"to": "vlan-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-3001]-to-[vlan-4094]",
"role": "external",
"from": "",
"to": "vlan-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-10]-to-[vlan-20]",
"role": "external",
"from": "vlan-10",
"to": "vlan-20",
"dn": "uni/infra/vlanns-[vlan_pool3]-static/from-[vlan-10]-to-[vlan-20]"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-3000]-to-[vlan-4094]",
"role": "external",
"from": "vlan-3000",
"to": "vlan-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-3001]-to-[vlan-4094]",
"role": "external",
"from": "",
"to": "vlan-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-4000]-to-[vlan-4094]",
"role": "external",
"from": "vlan-4000",
"to": "vlan-4094",
"dn": "uni/infra/vlanns-[vlan_pool3]-static/from-[vlan-4000]-to-[vlan-4094]"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-200]-to-[vlan-300]",
"role": "external",
"from": "vlan-200",
"to": "vlan-300",
"dn": "uni/infra/vlanns-[vlan_pool1]-static/from-[vlan-200]-to-[vlan-300]"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-500]-to-[vlan-1000]",
"role": "external",
"from": "vlan-500",
"to": "vlan-1000",
"dn": "uni/infra/vlanns-[vlan_pool2]-static/from-[vlan-500]-to-[vlan-1000]"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-4000]-to-[vlan-4094]",
"role": "external",
"from": "vlan-4000",
"to": "vlan-4094",
"dn": "uni/infra/vlanpool/vlan-4000-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-400]-to-[vlan-4094]",
"role": "external",
"from": "vlan-400",
"to": "vlan-4094",
"dn": "uni/infra/vlanpool/vlan-400-4094"
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-100]-to-[vlan-4094]",
"role": "external",
"from": "vlan-100",
"to": "vlan-4094",
"dn": "uni/infra/vlanns-[vlan_pool1]-static/from-[vlan-100]-to-[vlan-4094]"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-4000]-to-[vlan-4094]",
"role": "external",
"from": "vlan-4000",
"to": "vlan-4094",
"dn": "uni/infra/vlanpool/vlan-4000-4094"
}
}
},
{
"fvnsEncapBlk": {
"attributes": {
"allocMode": "static",
"annotation": "orchestrator:aci-containers-controller",
"rn": "from-[vlan-400]-to-[vlan-4094]",
"role": "external",
"from": "vlan-400",
"to": "vlan-4094",
"dn": "uni/infra/vlanpool/vlan-400-4094"
}
}
}
]
Loading
Loading