Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion aci-preupgrade-validation-script.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/validations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
20 changes: 19 additions & 1 deletion tests/checks/out_of_service_ports_check/ethpmPhysIf-pos.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"attributes": {
"dn": "topology/pod-1/node-103/sys/phys-[eth1/9]/phys",
"operSt": "up",
"usage": "blacklist,epg"
"usage": "blacklist"
}
}
},
Expand All @@ -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"
}
}
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading