-
Notifications
You must be signed in to change notification settings - Fork 49
Added APIC OOB connectivity checks for CSCwu91693 #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4.2.0-dev
Are you sure you want to change the base?
Changes from all commits
b0bea57
f954a9a
eeb6f10
730be06
6f76f21
eed66f0
beb65a2
a4d7b2e
cd07487
aee58d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6797,6 +6797,88 @@ def infravlan_overlap_access_policy_check(tversion, **kwargs): | |
| 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) | ||
|
|
||
|
|
||
| @check_wrapper(check_title="APIC OOB Connectivity check") | ||
| def apic_oob_connectivity_check(cversion, tversion, **kwargs): | ||
| result = PASS | ||
| headers = ["Node ID", "OOB IP", "Port", "Status"] | ||
| recommended_action = "Restore OOB management connectivity between all APICs and ensure the required HTTPS ports are reachable across the OOB network." | ||
| doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#apic-oob-connectivity' | ||
|
|
||
| def get_apic_oob_connectivity(apic_id_ip, port): | ||
| data = [] | ||
| has_error = False | ||
|
|
||
| for apic in apic_id_ip: | ||
| attrs = apic['topSystem']['attributes'] | ||
| node_id = attrs.get('id', '') | ||
|
|
||
| if attrs.get('oobMgmtAddr', '0.0.0.0') != '0.0.0.0': | ||
| ip = attrs.get('oobMgmtAddr') | ||
| elif attrs.get('oobMgmtAddr6', '::') not in ('', '::', '0:0:0:0:0:0:0:0'): | ||
| ip = attrs.get('oobMgmtAddr6') | ||
| else: | ||
|
Comment on lines
+6817
to
+6819
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. curl --max-time 5 -k -s https://[2001:db8:abc:1::12]:443 -- make sure you use proper format for ipv6. please check why pytest is noyt handling this.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated. |
||
| continue | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Do not skip a controller that has no usable OOB address. Skipping it allows the new upgrade-blocking validation to return |
||
|
|
||
| try: | ||
| ip_formatted = '[{}]'.format(ip) if ':' in ip else ip | ||
| with open(os.devnull, 'wb') as devnull: | ||
| if subprocess.call( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Verify that this probe topology satisfies APIC-to-APIC reachability. This runs every curl from only the APIC executing the script. That proves one source can reach each OOB address, not that every upgrade-fanout source can reach every peer. Please document and validate the product guarantee that the executing APIC is the sole relevant fanout source, or perform the supported remote checks needed to cover every required source-to-peer path. Without that guarantee, the check can pass while another APIC-to-APIC path is broken. |
||
| ['curl', '--max-time', '5', '-k', '-s', '-o', os.devnull, | ||
| 'https://{}:{}'.format(ip_formatted, port)], | ||
| stderr=devnull | ||
| ) != 0: | ||
| data.append([node_id, ip, port, "Unreachable"]) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Low] Keep result-table payload values string-normalized. Append |
||
| except Exception as e: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Low] Consider avoiding Using if subprocess.call(
['curl', '--max-time', '5', '-k', '-s', '-o', '/dev/null',
'https://{}:{}'.format(ip_formatted, port)],
stderr=subprocess.DEVNULL
) != 0:This is a minor suggestion and not blocking. |
||
| log.error("Exception checking OOB connectivity for node %s: %s", node_id, e) | ||
| data.append([node_id, ip, port, "Error"]) | ||
| has_error = True | ||
| continue | ||
|
|
||
| return data, has_error | ||
|
|
||
| if not tversion: | ||
| return Result(result=MANUAL, msg=TVER_MISSING) | ||
|
|
||
| if tversion.older_than("6.0(2a)"): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Reconcile this applicability gate with the defect contract. The check definition says |
||
| return Result(result=NA, msg=VER_NOT_AFFECTED) | ||
|
|
||
| apic_id_ip = icurl('class', 'topSystem.json?query-target-filter=eq(topSystem.role,"controller")') | ||
| if not apic_id_ip: | ||
| return Result(result=NA, msg="No APIC controller nodes found.") | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Empty or incomplete required inventory must fail closed.
|
||
|
|
||
| data = [] | ||
| has_error = False | ||
|
|
||
| # Default port check: APIC bootx uses port 443 from 6.0(2) | ||
| default_data, default_error = get_apic_oob_connectivity(apic_id_ip, 443) | ||
| data.extend(default_data) | ||
| if default_error: | ||
| has_error = True | ||
|
|
||
| # Custom HTTPS port check: upgrade fanout uses commHttps port from 6.2(1) | ||
| if not cversion.older_than("6.2(1g)"): | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Enforce both custom-port version conditions. The defined upgrade-fanout logic applies the custom HTTPS port only when both current and target releases are at or above the applicable 6.2 boundary. This branch checks only |
||
| port = 443 | ||
| commHttps = icurl('class', 'commHttps.json') | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Blocking] Resolve the effective A class query may return default and non-default communication policies, so selecting |
||
| if commHttps: | ||
| try: | ||
| port = int(commHttps[0]['commHttps']['attributes'].get('port', 443)) | ||
| except (ValueError, KeyError): | ||
| log.warning("Could not read commHttps port") | ||
| return Result(result=ERROR, msg="Could not read https port id from commHttps MO.") | ||
|
|
||
| if port != 443: # Port 443 already covered by default port check above | ||
| custom_data, custom_error = get_apic_oob_connectivity(apic_id_ip, port) | ||
| data.extend(custom_data) | ||
| if custom_error: | ||
| has_error = True | ||
|
|
||
| if has_error: | ||
| result = ERROR | ||
| elif data: | ||
| result = FAIL_UF | ||
| return Result(result=result, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url) | ||
|
|
||
|
|
||
| # ---- Script Execution ---- | ||
|
|
||
|
|
||
|
|
@@ -6973,7 +7055,7 @@ class CheckManager: | |
| n9k_c93180yc_fx3_switch_memory_check, | ||
| stale_dbgacEpgSummaryTask_check, | ||
| infravlan_overlap_access_policy_check, | ||
|
|
||
| apic_oob_connectivity_check, | ||
| ] | ||
| ssh_checks = [ | ||
| # General | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| [ | ||
| { | ||
| "commHttps": { | ||
| "attributes": { | ||
| "port": "8443" | ||
| } | ||
| } | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| [ | ||
| { | ||
| "commHttps": { | ||
| "attributes": { | ||
| "port": "443" | ||
| } | ||
| } | ||
| } | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| [{"commHttps": {"attributes": {"port": "invalid"}}}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[High] Parse controller objects independently so malformed inventory does not erase valid evidence.
Direct indexing here lets one malformed object escape to the wrapper, which replaces the whole result with a generic
ERRORand discards any unreachable controllers already collected. Validate each object's shape, preserve valid failure rows, and report malformed entries throughunformatted_dataor an error indication. Add a mixed valid-plus-malformed fixture.