Skip to content

Commit 91c1bfc

Browse files
[cherry pick] #9523 Fix PR #9312 for KeyError and AttributeError in 202305 (#9592)
* cherry pick #9523
1 parent 97436ab commit 91c1bfc

File tree

5 files changed

+150
-139
lines changed

5 files changed

+150
-139
lines changed

tests/cacl/test_cacl_function.py

Lines changed: 77 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import logging
33
from tests.common.helpers.assertions import pytest_assert
44
from tests.common.helpers.snmp_helpers import get_snmp_facts
5+
from tests.common.utilities import get_data_acl, recover_acl_rule
56

67
try:
78
import ntplib
@@ -19,10 +20,11 @@
1920
SONIC_SSH_REGEX = 'OpenSSH_[\\w\\.]+ Debian'
2021

2122

22-
def test_cacl_function(duthosts, enum_rand_one_per_hwsku_hostname, localhost, creds, recover_acl_rule):
23+
def test_cacl_function(duthosts, enum_rand_one_per_hwsku_hostname, localhost, creds):
2324
"""Test control plane ACL functionality on a SONiC device"""
2425

2526
duthost = duthosts[enum_rand_one_per_hwsku_hostname]
27+
data_acl = get_data_acl(duthost)
2628
dut_mgmt_ip = duthost.mgmt_ip
2729

2830
# Start an NTP client
@@ -46,76 +48,79 @@ def test_cacl_function(duthosts, enum_rand_one_per_hwsku_hostname, localhost, cr
4648
ntp_client.request(dut_mgmt_ip)
4749
except ntplib.NTPException:
4850
pytest.fail("NTP did timed out when expected to succeed!")
49-
50-
# Copy config_service_acls.sh to the DuT (this also implicitly verifies we can successfully SSH to the DuT)
51-
duthost.copy(src="scripts/config_service_acls.sh", dest="/tmp/config_service_acls.sh", mode="0755")
52-
53-
# We run the config_service_acls.sh script in the background because it
54-
# will install ACL rules which will only allow control plane traffic
55-
# to an unused IP range. Thus, if it works properly, it will sever our
56-
# SSH session, but we don't want the script itself to get killed,
57-
# because it is also responsible for resetting the control plane ACLs
58-
# back to their previous, working state
59-
duthost.shell("nohup /tmp/config_service_acls.sh < /dev/null > /dev/null 2>&1 &")
60-
61-
# Wait until we are unable to SSH into the DuT
62-
res = localhost.wait_for(host=dut_mgmt_ip,
63-
port=SONIC_SSH_PORT,
64-
state='stopped',
65-
search_regex=SONIC_SSH_REGEX,
66-
delay=30,
67-
timeout=40,
68-
module_ignore_errors=True)
69-
70-
pytest_assert(not res.is_failed, "SSH port did not stop. {}".format(res.get('msg', '')))
71-
72-
# Try to SSH back into the DuT, it should time out
73-
res = localhost.wait_for(host=dut_mgmt_ip,
74-
port=SONIC_SSH_PORT,
75-
state='started',
76-
search_regex=SONIC_SSH_REGEX,
77-
delay=0,
78-
timeout=10,
51+
try:
52+
# Copy config_service_acls.sh to the DuT (this also implicitly verifies we can successfully SSH to the DuT)
53+
duthost.copy(src="scripts/config_service_acls.sh", dest="/tmp/config_service_acls.sh", mode="0755")
54+
55+
# We run the config_service_acls.sh script in the background because it
56+
# will install ACL rules which will only allow control plane traffic
57+
# to an unused IP range. Thus, if it works properly, it will sever our
58+
# SSH session, but we don't want the script itself to get killed,
59+
# because it is also responsible for resetting the control plane ACLs
60+
# back to their previous, working state
61+
duthost.shell("nohup /tmp/config_service_acls.sh < /dev/null > /dev/null 2>&1 &")
62+
63+
# Wait until we are unable to SSH into the DuT
64+
res = localhost.wait_for(host=dut_mgmt_ip,
65+
port=SONIC_SSH_PORT,
66+
state='stopped',
67+
search_regex=SONIC_SSH_REGEX,
68+
delay=30,
69+
timeout=40,
70+
module_ignore_errors=True)
71+
72+
pytest_assert(not res.is_failed, "SSH port did not stop. {}".format(res.get('msg', '')))
73+
74+
# Try to SSH back into the DuT, it should time out
75+
res = localhost.wait_for(host=dut_mgmt_ip,
76+
port=SONIC_SSH_PORT,
77+
state='started',
78+
search_regex=SONIC_SSH_REGEX,
79+
delay=0,
80+
timeout=10,
81+
module_ignore_errors=True)
82+
83+
pytest_assert(res.is_failed, "SSH did not timeout when expected. {}".format(res.get('msg', '')))
84+
85+
# Ensure we CANNOT gather basic SNMP facts from the device
86+
res = get_snmp_facts(localhost, host=dut_mgmt_ip, version='v2c', community=creds['snmp_rocommunity'],
7987
module_ignore_errors=True)
8088

81-
pytest_assert(res.is_failed, "SSH did not timeout when expected. {}".format(res.get('msg', '')))
82-
83-
# Ensure we CANNOT gather basic SNMP facts from the device
84-
res = get_snmp_facts(localhost, host=dut_mgmt_ip, version='v2c', community=creds['snmp_rocommunity'],
85-
module_ignore_errors=True)
86-
87-
pytest_assert('ansible_facts' not in res and "No SNMP response received before timeout" in res.get('msg', ''))
88-
89-
# Ensure we cannot send an NTP request to the DUT
90-
if NTPLIB_INSTALLED:
91-
try:
92-
ntp_client.request(dut_mgmt_ip)
93-
pytest.fail("NTP did not time out when expected")
94-
except ntplib.NTPException:
95-
pass
96-
97-
# Wait until the original service ACLs are reinstated and the SSH port on the
98-
# DUT is open to us once again. Note that the timeout here should be set sufficiently
99-
# long enough to allow config_service_acls.sh to reset the ACLs to their original
100-
# configuration.
101-
res = localhost.wait_for(host=dut_mgmt_ip,
102-
port=SONIC_SSH_PORT,
103-
state='started',
104-
search_regex=SONIC_SSH_REGEX,
105-
delay=0,
106-
timeout=90,
107-
module_ignore_errors=True)
108-
109-
pytest_assert(not res.is_failed, "SSH did not start working when expected. {}".format(res.get('msg', '')))
110-
111-
# Delete config_service_acls.sh from the DuT
112-
duthost.file(path="/tmp/config_service_acls.sh", state="absent")
113-
114-
# Ensure we can gather basic SNMP facts from the device once again. Should fail on timeout
115-
get_snmp_facts(localhost,
116-
host=dut_mgmt_ip,
117-
version="v2c",
118-
community=creds['snmp_rocommunity'],
119-
wait=True,
120-
timeout=120,
121-
interval=20)
89+
pytest_assert('ansible_facts' not in res and "No SNMP response received before timeout" in res.get('msg', ''))
90+
91+
# Ensure we cannot send an NTP request to the DUT
92+
if NTPLIB_INSTALLED:
93+
try:
94+
ntp_client.request(dut_mgmt_ip)
95+
pytest.fail("NTP did not time out when expected")
96+
except ntplib.NTPException:
97+
pass
98+
99+
# Wait until the original service ACLs are reinstated and the SSH port on the
100+
# DUT is open to us once again. Note that the timeout here should be set sufficiently
101+
# long enough to allow config_service_acls.sh to reset the ACLs to their original
102+
# configuration.
103+
res = localhost.wait_for(host=dut_mgmt_ip,
104+
port=SONIC_SSH_PORT,
105+
state='started',
106+
search_regex=SONIC_SSH_REGEX,
107+
delay=0,
108+
timeout=90,
109+
module_ignore_errors=True)
110+
111+
pytest_assert(not res.is_failed, "SSH did not start working when expected. {}".format(res.get('msg', '')))
112+
113+
# Delete config_service_acls.sh from the DuT
114+
duthost.file(path="/tmp/config_service_acls.sh", state="absent")
115+
116+
# Ensure we can gather basic SNMP facts from the device once again. Should fail on timeout
117+
get_snmp_facts(localhost,
118+
host=dut_mgmt_ip,
119+
version="v2c",
120+
community=creds['snmp_rocommunity'],
121+
wait=True,
122+
timeout=120,
123+
interval=20)
124+
finally:
125+
if data_acl:
126+
recover_acl_rule(duthost, data_acl)

tests/common/utilities.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import threading
1616
import time
1717
import traceback
18+
import copy
19+
import tempfile
1820
from io import StringIO
1921
from ast import literal_eval
2022

@@ -936,3 +938,40 @@ def delete_running_config(config_entry, duthost, is_json=True):
936938
duthost.copy(src=config_entry, dest="/tmp/del_config_entry.json")
937939
duthost.shell("configlet -d -j {}".format("/tmp/del_config_entry.json"))
938940
duthost.shell("rm -f {}".format("/tmp/del_config_entry.json"))
941+
942+
943+
def get_data_acl(duthost):
944+
acl_facts = duthost.acl_facts()["ansible_facts"]["ansible_acl_facts"]
945+
pre_acl_rules = acl_facts.get("DATAACL", {}).get("rules", None)
946+
return pre_acl_rules
947+
948+
949+
def recover_acl_rule(duthost, data_acl):
950+
base_dir = os.path.dirname(os.path.realpath(__file__))
951+
template_dir = os.path.join(base_dir, "templates")
952+
acl_rules_template = "default_acl_rules.json"
953+
dut_tmp_dir = "/tmp"
954+
dut_conf_file_path = os.path.join(dut_tmp_dir, acl_rules_template)
955+
956+
for key, value in data_acl.items():
957+
if key != "DEFAULT_RULE":
958+
seq_id = key.split('_')[1]
959+
acl_config = json.loads(open(os.path.join(template_dir, acl_rules_template)).read())
960+
acl_entry_template = \
961+
acl_config["acl"]["acl-sets"]["acl-set"]["dataacl"]["acl-entries"]["acl-entry"]["1"]
962+
acl_entry_config = acl_config["acl"]["acl-sets"]["acl-set"]["dataacl"]["acl-entries"]["acl-entry"]
963+
964+
acl_entry_config[seq_id] = copy.deepcopy(acl_entry_template)
965+
acl_entry_config[seq_id]["config"]["sequence-id"] = seq_id
966+
acl_entry_config[seq_id]["l2"]["config"]["ethertype"] = value["ETHER_TYPE"]
967+
acl_entry_config[seq_id]["l2"]["config"]["vlan_id"] = value["VLAN_ID"]
968+
acl_entry_config[seq_id]["input_interface"]["interface_ref"]["config"]["interface"] = value["IN_PORTS"]
969+
970+
with tempfile.NamedTemporaryFile(suffix=".json", prefix="acl_config", mode="w") as fp:
971+
json.dump(acl_config, fp)
972+
fp.flush()
973+
logger.info("Generating config for ACL rule, ACL table - DATAACL")
974+
duthost.template(src=fp.name, dest=dut_conf_file_path, force=True)
975+
976+
logger.info("Applying {}".format(dut_conf_file_path))
977+
duthost.command("acl-loader update full {}".format(dut_conf_file_path))

tests/conftest.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import getpass
66
import random
77
import re
8-
import tempfile
98

109
import pytest
1110
import yaml
@@ -2257,43 +2256,3 @@ def format_failure(port, failure):
22572256
# HACK: We are using set_do_not_care_scapy but it will be deprecated.
22582257
if not hasattr(Mask, "set_do_not_care_scapy"):
22592258
Mask.set_do_not_care_scapy = Mask.set_do_not_care_packet
2260-
2261-
2262-
@pytest.fixture(scope="module")
2263-
def recover_acl_rule(duthosts, enum_rand_one_per_hwsku_hostname):
2264-
duthost = duthosts[enum_rand_one_per_hwsku_hostname]
2265-
2266-
base_dir = os.path.dirname(os.path.realpath(__file__))
2267-
template_dir = os.path.join(base_dir, "common/templates")
2268-
acl_rules_template = "default_acl_rules.json"
2269-
2270-
dut_tmp_dir = "/tmp"
2271-
dut_conf_file_path = os.path.join(dut_tmp_dir, acl_rules_template)
2272-
2273-
pre_acl_rules = duthost.acl_facts()["ansible_facts"]["ansible_acl_facts"]["DATAACL"]["rules"]
2274-
2275-
yield
2276-
2277-
if pre_acl_rules:
2278-
for key, value in pre_acl_rules.items():
2279-
if key != "DEFAULT_RULE":
2280-
seq_id = key.split('_')[1]
2281-
acl_config = json.loads(open(os.path.join(template_dir, acl_rules_template)).read())
2282-
acl_entry_template = \
2283-
acl_config["acl"]["acl-sets"]["acl-set"]["dataacl"]["acl-entries"]["acl-entry"]["1"]
2284-
acl_entry_config = acl_config["acl"]["acl-sets"]["acl-set"]["dataacl"]["acl-entries"]["acl-entry"]
2285-
2286-
acl_entry_config[seq_id] = copy.deepcopy(acl_entry_template)
2287-
acl_entry_config[seq_id]["config"]["sequence-id"] = seq_id
2288-
acl_entry_config[seq_id]["l2"]["config"]["ethertype"] = value["ETHER_TYPE"]
2289-
acl_entry_config[seq_id]["l2"]["config"]["vlan_id"] = value["VLAN_ID"]
2290-
acl_entry_config[seq_id]["input_interface"]["interface_ref"]["config"]["interface"] = value["IN_PORTS"]
2291-
2292-
with tempfile.NamedTemporaryFile(suffix=".json", prefix="acl_config", mode="w") as fp:
2293-
json.dump(acl_config, fp)
2294-
fp.flush()
2295-
logger.info("Generating config for ACL rule, ACL table - DATAACL")
2296-
duthost.template(src=fp.name, dest=dut_conf_file_path, force=True)
2297-
2298-
logger.info("Applying {}".format(dut_conf_file_path))
2299-
duthost.command("acl-loader update full {}".format(dut_conf_file_path))

tests/crm/conftest.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from test_crm import RESTORE_CMDS
88
from tests.common.helpers.crm import CRM_POLLING_INTERVAL
99
from tests.common.errors import RunAnsibleModuleFail
10+
from tests.common.utilities import recover_acl_rule
1011

1112
logger = logging.getLogger(__name__)
1213

@@ -53,7 +54,10 @@ def pytest_runtest_teardown(item, nextitem):
5354
for cmd in RESTORE_CMDS[test_name]:
5455
logger.info(cmd)
5556
try:
56-
dut.shell(cmd)
57+
if isinstance(cmd, dict):
58+
recover_acl_rule(dut, cmd["data_acl"])
59+
else:
60+
dut.shell(cmd)
5761
except RunAnsibleModuleFail as err:
5862
failures.append("Failure during command execution '{command}':\n{error}"
5963
.format(command=cmd, error=str(err)))

tests/crm/test_crm.py

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
EXPECT_CLEAR, THR_VERIFY_CMDS
1717
from tests.common.fixtures.duthost_utils import disable_route_checker # noqa F401
1818
from tests.common.fixtures.duthost_utils import disable_fdb_aging # noqa F401
19-
from tests.common.utilities import wait_until
19+
from tests.common.utilities import wait_until, get_data_acl
2020

2121

2222
pytestmark = [
@@ -861,36 +861,40 @@ def recreate_acl_table(duthost, ports):
861861

862862

863863
def test_acl_entry(duthosts, enum_rand_one_per_hwsku_frontend_hostname, enum_frontend_asic_index,
864-
collector, tbinfo, recover_acl_rule):
864+
collector, tbinfo):
865865
duthost = duthosts[enum_rand_one_per_hwsku_frontend_hostname]
866+
data_acl = get_data_acl(duthost)
866867
asichost = duthost.asic_instance(enum_frontend_asic_index)
867868
asic_collector = collector[asichost.asic_index]
868-
869-
if duthost.facts["asic_type"] == "marvell":
870-
# Remove DATA ACL Table and add it again with ports in same port group
871-
mg_facts = duthost.get_extended_minigraph_facts(tbinfo)
872-
tmp_ports = sorted(mg_facts["minigraph_ports"], key=lambda x: int(x[8:]))
873-
for i in range(4):
874-
if i == 0:
875-
ports = ",".join(tmp_ports[17:19])
876-
elif i == 1:
877-
ports = ",".join(tmp_ports[24:26])
878-
elif i == 2:
879-
ports = ",".join([tmp_ports[20], tmp_ports[25]])
880-
recreate_acl_table(duthost, ports)
869+
try:
870+
if duthost.facts["asic_type"] == "marvell":
871+
# Remove DATA ACL Table and add it again with ports in same port group
872+
mg_facts = duthost.get_extended_minigraph_facts(tbinfo)
873+
tmp_ports = sorted(mg_facts["minigraph_ports"], key=lambda x: int(x[8:]))
874+
for i in range(4):
875+
if i == 0:
876+
ports = ",".join(tmp_ports[17:19])
877+
elif i == 1:
878+
ports = ",".join(tmp_ports[24:26])
879+
elif i == 2:
880+
ports = ",".join([tmp_ports[20], tmp_ports[25]])
881+
recreate_acl_table(duthost, ports)
882+
verify_acl_crm_stats(duthost, asichost, enum_rand_one_per_hwsku_frontend_hostname,
883+
enum_frontend_asic_index, asic_collector, tbinfo)
884+
# Rebind DATA ACL at end to recover original config
885+
recreate_acl_table(duthost, ports)
886+
apply_acl_config(duthost, asichost, "test_acl_entry", asic_collector)
887+
duthost.command("acl-loader delete")
888+
else:
881889
verify_acl_crm_stats(duthost, asichost, enum_rand_one_per_hwsku_frontend_hostname,
882890
enum_frontend_asic_index, asic_collector, tbinfo)
883-
# Rebind DATA ACL at end to recover original config
884-
recreate_acl_table(duthost, ports)
885-
apply_acl_config(duthost, asichost, "test_acl_entry", asic_collector)
886-
duthost.command("acl-loader delete")
887-
else:
888-
verify_acl_crm_stats(duthost, asichost, enum_rand_one_per_hwsku_frontend_hostname,
889-
enum_frontend_asic_index, asic_collector, tbinfo)
890891

891-
pytest_assert(crm_stats_checker,
892-
"\"crm_stats_acl_entry_used\" counter was not decremented or "
893-
"\"crm_stats_acl_entry_available\" counter was not incremented")
892+
pytest_assert(crm_stats_checker,
893+
"\"crm_stats_acl_entry_used\" counter was not decremented or "
894+
"\"crm_stats_acl_entry_available\" counter was not incremented")
895+
finally:
896+
if data_acl:
897+
RESTORE_CMDS["test_acl_entry"].append({"data_acl": data_acl})
894898

895899

896900
def verify_acl_crm_stats(duthost, asichost, enum_rand_one_per_hwsku_frontend_hostname,

0 commit comments

Comments
 (0)