Skip to content

Commit cc27740

Browse files
committed
merge master
2 parents 9586a76 + 22104d7 commit cc27740

5 files changed

Lines changed: 54 additions & 27 deletions

File tree

aci-preupgrade-validation-script.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import os
3636
import re
3737

38-
SCRIPT_VERSION = "v2.6.0"
38+
SCRIPT_VERSION = "v3.0.0"
3939
# result constants
4040
DONE = 'DONE'
4141
PASS = 'PASS'
@@ -951,13 +951,14 @@ def craftData(column, rows):
951951
if not (isinstance(rows, list) and isinstance(column, list)):
952952
raise TypeError("Rows and column must be lists.")
953953
data = []
954-
for i in range(len(rows)):
954+
c_len = len(column)
955+
for row_entry in range(len(rows)):
956+
r_len = len(rows[row_entry])
957+
if r_len != c_len:
958+
raise ValueError("Row length ({}), data: {} does not match column length ({}).".format(r_len, rows[row_entry], c_len))
955959
entry = {}
956-
for j in range(len(column)):
957-
if j < len(rows[i]):
958-
entry[column[j]] = rows[i][j]
959-
else:
960-
entry[column[j]] = None
960+
for col_pos in range(c_len):
961+
entry[column[col_pos]] = rows[row_entry][col_pos]
961962
data.append(entry)
962963
return data
963964

@@ -1648,7 +1649,7 @@ def switch_group_guideline_check(**kwargs):
16481649
def switch_bootflash_usage_check(tversion, **kwargs):
16491650
result = FAIL_UF
16501651
msg = ''
1651-
headers = ["Pod-ID", "Node-ID", "Utilization", "Alert"]
1652+
headers = ["Pod-ID", "Node-ID", "Utilization"]
16521653
data = []
16531654
recommended_action = "Over 50% usage! Contact Cisco TAC for Support"
16541655
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#switch-node-bootflash-usage"
@@ -1746,9 +1747,9 @@ def l3out_mtu_check(**kwargs):
17461747
@check_wrapper(check_title="L3 Port Config (F0467 port-configured-as-l2)")
17471748
def port_configured_as_l2_check(**kwargs):
17481749
result = FAIL_O
1749-
headers = ['Fault', 'Tenant', 'L3Out', 'Node', 'Path', 'Recommended Action']
1750+
headers = ['Fault', 'Tenant', 'L3Out', 'Node', 'Path']
17501751
data = []
1751-
unformatted_headers = ['Fault', 'Fault DN', 'Recommended Action']
1752+
unformatted_headers = ['Fault', 'Fault DN']
17521753
unformatted_data = []
17531754
recommended_action = 'Resolve the conflict by removing this config or other configs using this port as L2'
17541755
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#l2l3-port-config"
@@ -2005,7 +2006,7 @@ def bd_subnet_overlap_check(**kwargs):
20052006
result = FAIL_O
20062007
headers = ["Fault", "Pod", "Node", "VRF", "Interface", "Address"]
20072008
data = []
2008-
unformatted_headers = ['Fault', 'Fault DN', 'Recommended Action']
2009+
unformatted_headers = ['Fault', 'Fault DN']
20092010
unformatted_data = []
20102011
recommended_action = 'Resolve the conflict by removing BD subnets causing the overlap'
20112012
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#bd-subnets"
@@ -2167,7 +2168,7 @@ def apic_ssd_check(cversion, username, password, **kwargs):
21672168
result = FAIL_UF
21682169
headers = ["Pod", "Node", "Storage Unit", "% lifetime remaining", "Recommended Action"]
21692170
data = []
2170-
unformatted_headers = ["Pod", "Node", "Storage Unit", "% lifetime remaining", "Recommended Action"]
2171+
unformatted_headers = ["Fault", "Fault DN", "% lifetime remaining", "Recommended Action"]
21712172
unformatted_data = []
21722173
recommended_action = "Contact TAC for replacement"
21732174
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#apic-ssd-health"
@@ -2200,15 +2201,15 @@ def apic_ssd_check(cversion, username, password, **kwargs):
22002201
c.log = LOG_FILE
22012202
c.connect()
22022203
except Exception as e:
2203-
data.append([attr['id'], attr['name'], '-', '-', '-', str(e)])
2204+
data.append([attr['id'], attr['name'], '-', '-', str(e)])
22042205
print_result(node_title, ERROR)
22052206
has_error = True
22062207
continue
22072208
try:
22082209
c.cmd(
22092210
'grep -oE "SSD Wearout Indicator is [0-9]+" /var/log/dme/log/svc_ifc_ae.bin.log | tail -1')
22102211
except Exception as e:
2211-
data.append([attr['id'], attr['name'], '-', '-', '-', str(e)])
2212+
data.append([attr['id'], attr['name'], '-', '-', str(e)])
22122213
print_result(node_title, ERROR)
22132214
has_error = True
22142215
continue
@@ -2226,7 +2227,6 @@ def apic_ssd_check(cversion, username, password, **kwargs):
22262227
print_result(node_title, DONE)
22272228
else:
22282229
headers = ["Fault", "Pod", "Node", "Storage Unit", "% lifetime remaining", "Recommended Action"]
2229-
unformatted_headers = ["Fault", "Fault DN", "% lifetime remaining", "Recommended Action"]
22302230
for faultInst in faultInsts:
22312231
dn_array = re.search(dn_regex, faultInst['faultInst']['attributes']['dn'])
22322232
lifetime_remaining = "<5%"
@@ -2860,7 +2860,7 @@ def apic_version_md5_check(tversion, username, password, **kwargs):
28602860
c.log = LOG_FILE
28612861
c.connect()
28622862
except Exception as e:
2863-
data.append([apic_name, '-', '-', str(e), '-'])
2863+
data.append([apic_name, '-', '-', str(e)])
28642864
print_result(node_title, ERROR)
28652865
has_error = True
28662866
continue
@@ -2870,7 +2870,7 @@ def apic_version_md5_check(tversion, username, password, **kwargs):
28702870
tversion.dot_version)
28712871
except Exception as e:
28722872
data.append([apic_name, '-', '-',
2873-
'ls command via ssh failed due to:{}'.format(str(e)), '-'])
2873+
'ls command via ssh failed due to:{}'.format(str(e))])
28742874
print_result(node_title, ERROR)
28752875
has_error = True
28762876
continue
@@ -2884,7 +2884,7 @@ def apic_version_md5_check(tversion, username, password, **kwargs):
28842884
tversion.dot_version)
28852885
except Exception as e:
28862886
data.append([apic_name, str(tversion), '-',
2887-
'failed to check md5sum via ssh due to:{}'.format(str(e)), '-'])
2887+
'failed to check md5sum via ssh due to:{}'.format(str(e))])
28882888
print_result(node_title, ERROR)
28892889
has_error = True
28902890
continue
@@ -2923,7 +2923,7 @@ def apic_version_md5_check(tversion, username, password, **kwargs):
29232923
def standby_apic_disk_space_check(**kwargs):
29242924
result = FAIL_UF
29252925
msg = ''
2926-
headers = ['SN', 'OOB', 'Mount Point', 'Current Usage %']
2926+
headers = ['SN', 'OOB', 'Mount Point', 'Current Usage %', 'Details']
29272927
data = []
29282928
recommended_action = 'Contact Cisco TAC'
29292929
doc_url = "https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#standby-apic-disk-space-usage"
@@ -2962,7 +2962,7 @@ def standby_apic_disk_space_check(**kwargs):
29622962
directory = fs.group(1)
29632963
usage = fs.group(5)
29642964
if int(usage) >= threshold:
2965-
data.append([stb['mbSn'], stb['oobIpAddr'], directory, usage])
2965+
data.append([stb['mbSn'], stb['oobIpAddr'], directory, usage, '-'])
29662966
if not infraSnNodes:
29672967
result = NA
29682968
msg = 'No standby APIC found'
@@ -3143,6 +3143,9 @@ def cimc_compatibilty_check(tversion, **kwargs):
31433143
compat_lookup_dn = "uni/fabric/compcat-default/ctlrfw-apic-" + tversion.simple_version + \
31443144
"/rssuppHw-[uni/fabric/compcat-default/ctlrhw-" + model + "].json"
31453145
compatMo = icurl('mo', compat_lookup_dn)
3146+
if not compatMo:
3147+
msg = "No compatibility information found for {}/{}".format(model, tversion.simple_version)
3148+
return Result(result=MANUAL, msg=msg, headers=headers, data=data, recommended_action=recommended_action, doc_url=doc_url)
31463149
recommended_cimc = compatMo[0]['compatRsSuppHw']['attributes']['cimcVersion']
31473150
warning = ""
31483151
if compatMo and recommended_cimc:
@@ -4905,7 +4908,7 @@ def standby_sup_sync_check(cversion, tversion, **kwargs):
49054908
@check_wrapper(check_title='Equipment Disk Limits Exceeded')
49064909
def equipment_disk_limits_exceeded(**kwargs):
49074910
result = PASS
4908-
headers = ['Pod', 'Node', 'Code', '%', 'Description',]
4911+
headers = ['Pod', 'Node', 'Code', '%', 'Description']
49094912
data = []
49104913
unformatted_headers = ['Fault DN', '%', 'Recommended Action']
49114914
unformatted_data = []
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[]

tests/cimc_compatibilty_check/test_cimc_compatibilty_check.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
# icurl queries
14-
eqptCh_api = 'eqptCh.json?query-target-filter=wcard(eqptCh.descr,"APIC")'
14+
eqptCh_api = 'eqptCh.json?query-target-filter=wcard(eqptCh.descr,"APIC")'
1515

1616
compatRsSuppHwL2_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.0(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicl2].json'
1717
compatRsSuppHwM1_api = 'uni/fabric/compcat-default/ctlrfw-apic-6.0(5)/rssuppHw-[uni/fabric/compcat-default/ctlrhw-apicm1].json'
@@ -40,6 +40,14 @@
4040
"6.0(5a)",
4141
script.PASS,
4242
),
43+
# Seen in QA testing where version + model does not have catalog entry
44+
(
45+
{eqptCh_api: read_data(dir, "eqptCh_newver.json"),
46+
compatRsSuppHwL2_api: read_data(dir, "compatRsSuppHw_605_L2.json"),
47+
compatRsSuppHwM1_api: read_data(dir, "compatRsSuppHw_empty.json")},
48+
"6.0(5a)",
49+
script.MANUAL,
50+
),
4351
],
4452
)
4553
def test_logic(mock_icurl, tversion, expected_result):

tests/test_AciResult.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
"critical",
145145
"failed"
146146
),
147-
# Check 9: FAIL_O
147+
# Check 9: FAIL_O unformatted only
148148
(
149149
"fake_func_name_FAIL_O_unformatted_only_test",
150150
"FAIL_O Unformatted only",
@@ -204,4 +204,19 @@ def test_invalid_headers_or_data(headers, data):
204204
synth.craftData(
205205
column=headers,
206206
rows=data,
207-
)
207+
)
208+
209+
@pytest.mark.parametrize(
210+
"headers, data",
211+
[
212+
(["col1", "col2"], [["row1"], ["row2"]]), # Rows are shorter
213+
(["col1"], [["row1", "row2"], ["row3", "row4"]]), # columns are shorter
214+
]
215+
)
216+
def test_mismatched_lengths(headers, data):
217+
with pytest.raises(ValueError):
218+
synth = script.AciResult("func_name", "Check Title", "A Description")
219+
synth.craftData(
220+
column=headers,
221+
rows=data,
222+
)

tests/test_run_checks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
script = importlib.import_module("aci-preupgrade-validation-script")
77
AciVersion = script.AciVersion
88
JSON_DIR = script.JSON_DIR
9-
ApicResult = script.AciResult
9+
AciResult = script.AciResult
1010
Result = script.Result
1111
check_wrapper = script.check_wrapper
1212

@@ -162,10 +162,10 @@ def test_run_checks(capsys, caplog):
162162
else:
163163
assert data["failureDetails"]["failType"] == ""
164164
# failureDetails.data
165-
assert data["failureDetails"]["data"] == ApicResult.craftData(
165+
assert data["failureDetails"]["data"] == AciResult.craftData(
166166
others.get("headers", []), others.get("data", [])
167167
)
168-
assert data["failureDetails"]["unformatted_data"] == ApicResult.craftData(
168+
assert data["failureDetails"]["unformatted_data"] == AciResult.craftData(
169169
others.get("unformatted_headers", []), others.get("unformatted_data", [])
170170
)
171171
# other fields

0 commit comments

Comments
 (0)