From b401aa500f8d4a5f9691e08806579b704886b6f7 Mon Sep 17 00:00:00 2001 From: gmonroy Date: Mon, 29 Apr 2024 14:48:51 -0400 Subject: [PATCH 1/7] check maintUpgJob for image downloaded --- aci-preupgrade-validation-script.py | 28 ++++++++++++++----- .../maintUpgJob_not_downloaded.json | 1 + .../maintUpgJob_pre_downloaded.json | 16 +++++++++++ .../test_switch_bootflash_usage_check.py | 22 +++++++++++---- 4 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 tests/switch_bootflash_usage_check/maintUpgJob_not_downloaded.json create mode 100644 tests/switch_bootflash_usage_check/maintUpgJob_pre_downloaded.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 634b876..f29291d 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -984,7 +984,7 @@ def switch_group_guideline_check(index, total_checks, **kwargs): return result -def switch_bootflash_usage_check(index, total_checks, **kwargs): +def switch_bootflash_usage_check(index, total_checks, tversion, **kwargs): title = 'Switch Node /bootflash usage' result = FAIL_UF msg = '' @@ -992,13 +992,26 @@ def switch_bootflash_usage_check(index, total_checks, **kwargs): data = [] print_title(title, index, total_checks) - response_json = icurl('class', - 'eqptcapacityFSPartition.json?query-target-filter=eq(eqptcapacityFSPartition.path,"/bootflash")') - if not response_json: + partitions_api = 'eqptcapacityFSPartition.json' + partitions_api += '?query-target-filter=eq(eqptcapacityFSPartition.path,"/bootflash")' + + download_sts_api = 'maintUpgJob.json' + download_sts_api += '?query-target-filter=and(eq(maintUpgJob.dnldStatus,"downloaded")' + download_sts_api += ',eq(maintUpgJob.desiredVersion,"n9000-1{}"))'.format(tversion) + + partitions = icurl('class', partitions_api) + if not partitions: result = ERROR msg = 'bootflash objects not found' - for eqptcapacityFSPartition in response_json: + predownloaded_nodes = [] + download_sts = icurl('class', download_sts_api) + for maintUpgJob in download_sts: + dn = re.search(node_regex, maintUpgJob['maintUpgJob']['attributes']['dn']) + node = dn.group("node") + predownloaded_nodes.append(node) + + for eqptcapacityFSPartition in partitions: dn = re.search(node_regex, eqptcapacityFSPartition['eqptcapacityFSPartition']['attributes']['dn']) pod = dn.group("pod") node = dn.group("node") @@ -1006,11 +1019,12 @@ def switch_bootflash_usage_check(index, total_checks, **kwargs): used = int(eqptcapacityFSPartition['eqptcapacityFSPartition']['attributes']['used']) usage = (used / (avail + used)) * 100 - if usage >= 50: + if (usage >= 50) and (node not in predownloaded_nodes): data.append([pod, node, usage, "Over 50% usage! Contact Cisco TAC for Support"]) + if not data: result = PASS - msg = 'all below 50%' + msg = 'All below 50% or pre-downloaded' print_result(title, result, msg, headers, data) return result diff --git a/tests/switch_bootflash_usage_check/maintUpgJob_not_downloaded.json b/tests/switch_bootflash_usage_check/maintUpgJob_not_downloaded.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/tests/switch_bootflash_usage_check/maintUpgJob_not_downloaded.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/tests/switch_bootflash_usage_check/maintUpgJob_pre_downloaded.json b/tests/switch_bootflash_usage_check/maintUpgJob_pre_downloaded.json new file mode 100644 index 0000000..efc36e7 --- /dev/null +++ b/tests/switch_bootflash_usage_check/maintUpgJob_pre_downloaded.json @@ -0,0 +1,16 @@ +[ + { + "maintUpgJob": { + "attributes": { + "desiredVersion": "n9000-16.0(2h)", + "dn": "topology/pod-1/node-101/sys/fwstatuscont/upgjob", + "dnldPercent": "100", + "dnldStatus": "downloaded", + "startDate": "2023-11-16T10:15:22.894-08:00", + "status": "", + "upgradeStatus": "scheduled", + "upgradeStatusStr": "Scheduled" + } + } + } +] \ No newline at end of file diff --git a/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py b/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py index c69cb4d..9b3eebb 100644 --- a/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py +++ b/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py @@ -11,18 +11,30 @@ # icurl queries -partitions = 'eqptcapacityFSPartition.json?query-target-filter=eq(eqptcapacityFSPartition.path,"/bootflash")' +partitions = 'eqptcapacityFSPartition.json' +partitions += '?query-target-filter=eq(eqptcapacityFSPartition.path,"/bootflash")' +download_sts = 'maintUpgJob.json' +download_sts += '?query-target-filter=and(eq(maintUpgJob.dnldStatus,"downloaded")' +download_sts += ',eq(maintUpgJob.desiredVersion,"n9000-16.0(2h)"))' @pytest.mark.parametrize( - "icurl_outputs, expected_result", + "icurl_outputs, tversion, expected_result", [ ( - {partitions: read_data(dir, "eqptcapacityFSPartition_pos.json")}, + {partitions: read_data(dir, "eqptcapacityFSPartition_pos.json"), + download_sts: read_data(dir, "maintUpgJob_not_downloaded.json")}, + "6.0(2h)", script.FAIL_UF, ), + ( + {partitions: read_data(dir, "eqptcapacityFSPartition_pos.json"), + download_sts: read_data(dir, "maintUpgJob_pre_downloaded.json")}, + "6.0(2h)", + script.PASS, + ), ], ) -def test_logic(mock_icurl, expected_result): - result = script.switch_bootflash_usage_check(1, 1) +def test_logic(mock_icurl, tversion, expected_result): + result = script.switch_bootflash_usage_check(1, 1, script.AciVersion(tversion)) assert result == expected_result From 86fc7dcbc9f0c843d5a8a18ff3738cf6168e36bb Mon Sep 17 00:00:00 2001 From: gmonroy Date: Mon, 29 Apr 2024 15:07:41 -0400 Subject: [PATCH 2/7] catch older versions not having dnldStatus --- aci-preupgrade-validation-script.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index f29291d..30915a5 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -1005,7 +1005,11 @@ def switch_bootflash_usage_check(index, total_checks, tversion, **kwargs): msg = 'bootflash objects not found' predownloaded_nodes = [] - download_sts = icurl('class', download_sts_api) + try: + download_sts = icurl('class', download_sts_api) + except: + # Older versions don't have 'dnldStatus' param + download_sts = [] for maintUpgJob in download_sts: dn = re.search(node_regex, maintUpgJob['maintUpgJob']['attributes']['dn']) node = dn.group("node") From 723afb606389a7777cb032870d7880510e14dc09 Mon Sep 17 00:00:00 2001 From: gmonroy Date: Thu, 2 May 2024 10:29:58 -0400 Subject: [PATCH 3/7] new OldVerPropNotFound exception and usage --- aci-preupgrade-validation-script.py | 13 +++++++++++-- tests/conftest.py | 10 +++++++++- ...tition_pos.json => eqptcapacityFSPartition.json} | 0 .../maintUpgJob_old_ver_no_prop.json | 10 ++++++++++ .../test_switch_bootflash_usage_check.py | 10 ++++++++-- 5 files changed, 38 insertions(+), 5 deletions(-) rename tests/switch_bootflash_usage_check/{eqptcapacityFSPartition_pos.json => eqptcapacityFSPartition.json} (100%) create mode 100644 tests/switch_bootflash_usage_check/maintUpgJob_old_ver_no_prop.json diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 30915a5..2fc88cc 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -56,6 +56,11 @@ warnings.simplefilter(action='ignore', category=FutureWarning) +class OldVerPropNotFound(Exception): + """ Later versions of ACI can have class properties not found in older versions """ + pass + + class Connection(object): """ Object built primarily for executing commands on Cisco IOS/NXOS devices. The following @@ -613,7 +618,10 @@ def icurl(apitype, query): logging.debug('response: ' + str(response)) imdata = json.loads(response)['imdata'] if imdata and "error" in imdata[0].keys(): - raise Exception('API call failed! Check debug log') + if imdata and "not found in class" in imdata[0]['error']['attributes']['text']: + raise OldVerPropNotFound('cversion does not have requested property') + else: + raise Exception('API call failed! Check debug log') else: return imdata @@ -1007,9 +1015,10 @@ def switch_bootflash_usage_check(index, total_checks, tversion, **kwargs): predownloaded_nodes = [] try: download_sts = icurl('class', download_sts_api) - except: + except OldVerPropNotFound: # Older versions don't have 'dnldStatus' param download_sts = [] + for maintUpgJob in download_sts: dn = re.search(node_regex, maintUpgJob['maintUpgJob']['attributes']['dn']) node = dn.group("node") diff --git a/tests/conftest.py b/tests/conftest.py index 802a2c5..7c8de4b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -41,6 +41,14 @@ def mock_icurl(monkeypatch, icurl_outputs): def _mock_icurl(apitype, query): if icurl_outputs.get(query) is None: log.error("Query `%s` not found in test data", query) - return icurl_outputs.get(query, []) + + imdata = icurl_outputs.get(query, []) + if imdata and "error" in imdata[0].keys(): + if "not found in class" in imdata[0]['error']['attributes']['text']: + raise script.OldVerPropNotFound('cversion does not have requested property') + else: + raise Exception('API call failed! Check debug log') + else: + return imdata monkeypatch.setattr(script, "icurl", _mock_icurl) diff --git a/tests/switch_bootflash_usage_check/eqptcapacityFSPartition_pos.json b/tests/switch_bootflash_usage_check/eqptcapacityFSPartition.json similarity index 100% rename from tests/switch_bootflash_usage_check/eqptcapacityFSPartition_pos.json rename to tests/switch_bootflash_usage_check/eqptcapacityFSPartition.json diff --git a/tests/switch_bootflash_usage_check/maintUpgJob_old_ver_no_prop.json b/tests/switch_bootflash_usage_check/maintUpgJob_old_ver_no_prop.json new file mode 100644 index 0000000..9f74f58 --- /dev/null +++ b/tests/switch_bootflash_usage_check/maintUpgJob_old_ver_no_prop.json @@ -0,0 +1,10 @@ +[ + { + "error": { + "attributes": { + "code": "121", + "text": "Prop 'dnldStatus' not found in class 'maintUpgJob' property table" + } + } + } +] \ No newline at end of file diff --git a/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py b/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py index 9b3eebb..5b16064 100644 --- a/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py +++ b/tests/switch_bootflash_usage_check/test_switch_bootflash_usage_check.py @@ -22,17 +22,23 @@ "icurl_outputs, tversion, expected_result", [ ( - {partitions: read_data(dir, "eqptcapacityFSPartition_pos.json"), + {partitions: read_data(dir, "eqptcapacityFSPartition.json"), download_sts: read_data(dir, "maintUpgJob_not_downloaded.json")}, "6.0(2h)", script.FAIL_UF, ), ( - {partitions: read_data(dir, "eqptcapacityFSPartition_pos.json"), + {partitions: read_data(dir, "eqptcapacityFSPartition.json"), download_sts: read_data(dir, "maintUpgJob_pre_downloaded.json")}, "6.0(2h)", script.PASS, ), + ( + {partitions: read_data(dir, "eqptcapacityFSPartition.json"), + download_sts: read_data(dir, "maintUpgJob_old_ver_no_prop.json")}, + "6.0(2h)", + script.FAIL_UF, + ), ], ) def test_logic(mock_icurl, tversion, expected_result): From 964aaf127cae1225dea445769b5e3a82fe3c8e14 Mon Sep 17 00:00:00 2001 From: GM Date: Mon, 6 May 2024 09:10:55 -0400 Subject: [PATCH 4/7] Update aci-preupgrade-validation-script.py remove redundant check Co-authored-by: takishida <38262981+takishida@users.noreply.github.com> --- aci-preupgrade-validation-script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 2fc88cc..683039f 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -618,7 +618,7 @@ def icurl(apitype, query): logging.debug('response: ' + str(response)) imdata = json.loads(response)['imdata'] if imdata and "error" in imdata[0].keys(): - if imdata and "not found in class" in imdata[0]['error']['attributes']['text']: + if "not found in class" in imdata[0]['error']['attributes']['text']: raise OldVerPropNotFound('cversion does not have requested property') else: raise Exception('API call failed! Check debug log') From 2293146c099b0db854f4bb27bcff055a50f9581c Mon Sep 17 00:00:00 2001 From: GM Date: Mon, 6 May 2024 09:12:16 -0400 Subject: [PATCH 5/7] Update aci-preupgrade-validation-script.py remove .keys() usage for py2 Co-authored-by: takishida <38262981+takishida@users.noreply.github.com> --- aci-preupgrade-validation-script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 683039f..d962291 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -617,7 +617,7 @@ def icurl(apitype, query): response = subprocess.check_output(cmd) logging.debug('response: ' + str(response)) imdata = json.loads(response)['imdata'] - if imdata and "error" in imdata[0].keys(): + if imdata and "error" in imdata[0]: if "not found in class" in imdata[0]['error']['attributes']['text']: raise OldVerPropNotFound('cversion does not have requested property') else: From 02ef0002420858f2d2e66ea81361ef37a399dd3d Mon Sep 17 00:00:00 2001 From: GM Date: Mon, 6 May 2024 09:12:32 -0400 Subject: [PATCH 6/7] Update tests/conftest.py whitespace Co-authored-by: takishida <38262981+takishida@users.noreply.github.com> --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 7c8de4b..9d690b6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -44,7 +44,7 @@ def _mock_icurl(apitype, query): imdata = icurl_outputs.get(query, []) if imdata and "error" in imdata[0].keys(): - if "not found in class" in imdata[0]['error']['attributes']['text']: + if "not found in class" in imdata[0]['error']['attributes']['text']: raise script.OldVerPropNotFound('cversion does not have requested property') else: raise Exception('API call failed! Check debug log') From 8731e01398e4bad58418cd7e1b467ee728f9269f Mon Sep 17 00:00:00 2001 From: GM Date: Mon, 6 May 2024 09:13:23 -0400 Subject: [PATCH 7/7] Update tests/conftest.py remove .keys() use for py2 best practices Co-authored-by: takishida <38262981+takishida@users.noreply.github.com> --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9d690b6..3529ff1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -43,7 +43,7 @@ def _mock_icurl(apitype, query): log.error("Query `%s` not found in test data", query) imdata = icurl_outputs.get(query, []) - if imdata and "error" in imdata[0].keys(): + if imdata and "error" in imdata[0]: if "not found in class" in imdata[0]['error']['attributes']['text']: raise script.OldVerPropNotFound('cversion does not have requested property') else: