diff --git a/aci-preupgrade-validation-script.py b/aci-preupgrade-validation-script.py index 5e79f56e..0ef3986b 100644 --- a/aci-preupgrade-validation-script.py +++ b/aci-preupgrade-validation-script.py @@ -5550,7 +5550,11 @@ def out_of_service_ports_check(**kwargs): doc_url = 'https://datacenter.github.io/ACI-Pre-Upgrade-Validation-Script/validations/#out-of-service-ports' ethpmPhysIf_api = 'ethpmPhysIf.json' - ethpmPhysIf_api += '?query-target-filter=and(eq(ethpmPhysIf.operSt,"2"),bw(ethpmPhysIf.usage,"32","34"))' + ethpmPhysIf_api += ( + '?query-target-filter=and(eq(ethpmPhysIf.operSt,"2"),' + 'or(eq(ethpmPhysIf.usage,"32"),eq(ethpmPhysIf.usage,"34"),' + 'eq(ethpmPhysIf.usage,"36"),eq(ethpmPhysIf.usage,"292")))' + ) ethpmPhysIf = icurl('class', ethpmPhysIf_api) diff --git a/docs/docs/validations.md b/docs/docs/validations.md index f7886811..68c72422 100644 --- a/docs/docs/validations.md +++ b/docs/docs/validations.md @@ -2242,7 +2242,7 @@ This check will look for configured Pre-shared keys (PSK) within your APIC clust ### Out-of-Service Ports -Any Port that has been disabled via policy creates a `fabricRsOosPath` object and marks the ports usage as `blacklist`, or `blacklist,epg` if policy was applied to it. `fabricRsOosPath` objects can be found within the UI at the "Fabric" > "Disabled Interfaces and Decommissioned Switches" view. +Any access/downlink or fabric port that has been disabled via policy creates a `fabricRsOosPath` object. The check covers operationally up ports with the `blacklist`, `blacklist,epg`, `blacklist,fabric`, or `blacklist,fabric,fabric-ext` usage. `fabricRsOosPath` objects can be found within the UI at the "Fabric" > "Disabled Interfaces and Decommissioned Switches" view. While generally not recommended, there are policy bypass methods to bring up ports which are out-of-service via policy. The problem arises from the ports active state deviating from ports configured policy, and this fact generally remains undetected as policy was bypassed. If an event occurs which causes Switch Nodes to receive and reprogram policy from the APICs, the configured out-of-service policy will bring the out-of-service ports down, as expected. diff --git a/tests/checks/out_of_service_ports_check/ethpmPhysIf-pos.json b/tests/checks/out_of_service_ports_check/ethpmPhysIf-pos.json index 2ca30264..f3c3f784 100644 --- a/tests/checks/out_of_service_ports_check/ethpmPhysIf-pos.json +++ b/tests/checks/out_of_service_ports_check/ethpmPhysIf-pos.json @@ -4,7 +4,7 @@ "attributes": { "dn": "topology/pod-1/node-103/sys/phys-[eth1/9]/phys", "operSt": "up", - "usage": "blacklist,epg" + "usage": "blacklist" } } }, @@ -16,5 +16,23 @@ "usage": "blacklist,epg" } } + }, + { + "ethpmPhysIf": { + "attributes": { + "dn": "topology/pod-1/node-105/sys/phys-[eth1/49]/phys", + "operSt": "up", + "usage": "blacklist,fabric" + } + } + }, + { + "ethpmPhysIf": { + "attributes": { + "dn": "topology/pod-1/node-105/sys/phys-[eth1/50]/phys", + "operSt": "up", + "usage": "blacklist,fabric,fabric-ext" + } + } } ] \ No newline at end of file diff --git a/tests/checks/out_of_service_ports_check/test_out_of_service_ports_check.py b/tests/checks/out_of_service_ports_check/test_out_of_service_ports_check.py index 4296eeec..21b6d5ab 100644 --- a/tests/checks/out_of_service_ports_check/test_out_of_service_ports_check.py +++ b/tests/checks/out_of_service_ports_check/test_out_of_service_ports_check.py @@ -11,27 +11,52 @@ test_function = "out_of_service_ports_check" -# operst: '1' = 'up' -# usage: '32' = 'blacklist', '2' = 'epg'. '34'= 'blacklist,epg' +# operSt: '2' = 'up' +# usage: '32' = 'blacklist', '34' = 'blacklist,epg', +# '36' = 'blacklist,fabric', '292' = 'blacklist,fabric,fabric-ext' ethpmPhysIf_api = 'ethpmPhysIf.json' -ethpmPhysIf_api += '?query-target-filter=and(eq(ethpmPhysIf.operSt,"2"),bw(ethpmPhysIf.usage,"32","34"))' +ethpmPhysIf_api += ( + '?query-target-filter=and(eq(ethpmPhysIf.operSt,"2"),' + 'or(eq(ethpmPhysIf.usage,"32"),eq(ethpmPhysIf.usage,"34"),' + 'eq(ethpmPhysIf.usage,"36"),eq(ethpmPhysIf.usage,"292")))' +) @pytest.mark.parametrize( - "icurl_outputs, expected_result", + "icurl_outputs, expected_result, expected_usages", [ ( - # Two 'up' ports flagged with 'blacklist,epg' + # Four 'up' access and fabric ports with supported blacklist masks {ethpmPhysIf_api: read_data(dir, "ethpmPhysIf-pos.json")}, script.FAIL_O, + [ + "blacklist", + "blacklist,epg", + "blacklist,fabric", + "blacklist,fabric,fabric-ext", + ], ), ( # 0 ports returned {ethpmPhysIf_api: read_data(dir, "ethpmPhysIf-neg.json")}, script.PASS, + [], ) ], ) -def test_logic(run_check, mock_icurl, expected_result): +def test_logic(run_check, mock_icurl, expected_result, expected_usages): result = run_check() assert result.result == expected_result + assert [row[4] for row in result.data] == expected_usages + + +@pytest.mark.parametrize("usage_mask", ["32", "34", "36", "292"]) +def test_requested_usage_masks_are_queried(usage_mask): + usage_filter = 'eq(ethpmPhysIf.usage,"{}")'.format(usage_mask) + assert usage_filter in ethpmPhysIf_api + + +@pytest.mark.parametrize("usage_mask", ["31", "33", "35", "37", "291", "293"]) +def test_unrelated_usage_masks_are_not_queried(usage_mask): + usage_filter = 'eq(ethpmPhysIf.usage,"{}")'.format(usage_mask) + assert usage_filter not in ethpmPhysIf_api