Skip to content

Commit b25f1e1

Browse files
authored
[generic-config-updater] Add caclrule validator (sonic-net#2103)
Add 1 sec sleep time to make sure caclmgrd does update What I did When GCU make change to control plane ACL_RULE, the iptables doen't change immediately. There is a delay because caclmgrd will update in 0.5 sec if no more update being made to config. So I add a caclrule validator to make sure the iptable is updated. How I did it When caclrule is being changed, add a 1sec sleep to make sure caclmgr does update. How to verify it Run sonic-utilities unit test
1 parent 968900c commit b25f1e1

File tree

5 files changed

+135
-6
lines changed

5 files changed

+135
-6
lines changed

generic_config_updater/change_applier.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def _services_validate(self, old_cfg, upd_cfg, keys):
107107

108108
for cmd in lst_cmds:
109109
ret = self._invoke_cmd(cmd, old_cfg, upd_cfg, keys)
110-
if ret:
110+
if not ret:
111111
log_error("service invoked: {} failed with ret={}".format(cmd, ret))
112112
return ret
113113
log_debug("service invoked: {}".format(cmd))

generic_config_updater/generic_config_updater.conf.json

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
},
4343
"VLAN": {
4444
"services_to_validate": [ "vlan-service" ]
45+
},
46+
"ACL_RULE": {
47+
"services_to_validate": [ "caclmgrd-service" ]
4548
}
4649
},
4750
"services": {
@@ -59,6 +62,9 @@
5962
},
6063
"vlan-service": {
6164
"validate_commands": [ "generic_config_updater.services_validator.vlan_validator" ]
65+
},
66+
"caclmgrd-service": {
67+
"validate_commands": [ "generic_config_updater.services_validator.caclmgrd_validator" ]
6268
}
6369
}
6470
}

generic_config_updater/services_validator.py

+27
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,30 @@ def vlan_validator(old_config, upd_config, keys):
7171
# No update to DHCP servers.
7272
return True
7373

74+
def caclmgrd_validator(old_config, upd_config, keys):
75+
old_acltable = old_config.get("ACL_TABLE", {})
76+
upd_acltable = upd_config.get("ACL_TABLE", {})
77+
78+
old_cacltable = [table for table, fields in old_acltable.items()
79+
if fields.get("type", "") == "CTRLPLANE"]
80+
upd_cacltable = [table for table, fields in upd_acltable.items()
81+
if fields.get("type", "") == "CTRLPLANE"]
82+
83+
old_aclrule = old_config.get("ACL_RULE", {})
84+
upd_aclrule = upd_config.get("ACL_RULE", {})
85+
86+
old_caclrule = [rule for rule in old_aclrule
87+
if rule.split("|")[0] in old_cacltable]
88+
upd_caclrule = [rule for rule in upd_aclrule
89+
if rule.split("|")[0] in upd_cacltable]
90+
91+
# Only sleep when cacl rule is changed as this will update iptable.
92+
for key in set(old_caclrule).union(set(upd_caclrule)):
93+
if (old_aclrule.get(key, {}) != upd_aclrule.get(key, {})):
94+
# caclmgrd will update in 0.5 sec when configuration stops,
95+
# we sleep 1 sec to make sure it does update.
96+
time.sleep(1)
97+
return True
98+
# No update to ACL_RULE.
99+
return True
100+

tests/generic_config_updater/change_applier_test.py

+3
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ def system_health(old_cfg, new_cfg, keys):
158158
if svcs != None:
159159
assert svc_name in svcs
160160
svcs.remove(svc_name)
161+
return True
161162

162163

163164
def _validate_keys(keys):
@@ -201,11 +202,13 @@ def _validate_svc(svc_name, old_cfg, new_cfg, keys):
201202
def acl_validate(old_cfg, new_cfg, keys):
202203
debug_print("acl_validate called")
203204
_validate_svc("acl_validate", old_cfg, new_cfg, keys)
205+
return True
204206

205207

206208
def vlan_validate(old_cfg, new_cfg, keys):
207209
debug_print("vlan_validate called")
208210
_validate_svc("vlan_validate", old_cfg, new_cfg, keys)
211+
return True
209212

210213

211214
class TestChangeApplier(unittest.TestCase):

tests/generic_config_updater/service_validator_test.py

+98-5
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
from collections import defaultdict
77
from unittest.mock import patch
88

9-
from generic_config_updater.services_validator import vlan_validator, rsyslog_validator
9+
from generic_config_updater.services_validator import vlan_validator, rsyslog_validator, caclmgrd_validator
1010
import generic_config_updater.gu_common
1111

1212

1313
# Mimics os.system call
1414
#
1515
os_system_calls = []
1616
os_system_call_index = 0
17+
time_sleep_calls = []
18+
time_sleep_call_index = 0
1719
msg = ""
1820

1921
def mock_os_system_call(cmd):
@@ -26,6 +28,15 @@ def mock_os_system_call(cmd):
2628
assert cmd == entry["cmd"], msg
2729
return entry["rc"]
2830

31+
def mock_time_sleep_call(sleep_time):
32+
global time_sleep_calls, time_sleep_call_index
33+
34+
assert time_sleep_call_index < len(time_sleep_calls)
35+
entry = time_sleep_calls[time_sleep_call_index]
36+
time_sleep_call_index += 1
37+
38+
assert sleep_time == entry["sleep_time"], msg
39+
2940

3041
test_data = [
3142
{ "old": {}, "upd": {}, "cmd": "" },
@@ -60,6 +71,77 @@ def mock_os_system_call(cmd):
6071
}
6172
]
6273

74+
test_caclrule = [
75+
{ "old": {}, "upd": {}, "sleep_time": 0 },
76+
{
77+
"old": {
78+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
79+
"ACL_RULE": { "XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" } }
80+
},
81+
"upd": {
82+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
83+
"ACL_RULE": { "XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" } }
84+
},
85+
"sleep_time": 0
86+
},
87+
{
88+
"old": {
89+
"ACL_TABLE": {
90+
"XXX": { "type": "CTRLPLANE" },
91+
"YYY": { "type": "L3" }
92+
},
93+
"ACL_RULE": {
94+
"XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" },
95+
"YYY|RULE_1": { "SRC_IP": "192.168.1.10/32" }
96+
}
97+
},
98+
"upd": {
99+
"ACL_TABLE": {
100+
"XXX": { "type": "CTRLPLANE" }
101+
},
102+
"ACL_RULE": {
103+
"XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" }
104+
}
105+
},
106+
"sleep_time": 0
107+
},
108+
{
109+
"old": {
110+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
111+
"ACL_RULE": { "XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" } }
112+
},
113+
"upd": {
114+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
115+
"ACL_RULE": { "XXX|RULE_1": { "SRC_IP": "11.11.11.11/16" } }
116+
},
117+
"sleep_time": 1
118+
},
119+
{
120+
"old": {
121+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
122+
"ACL_RULE": {
123+
"XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" }
124+
}
125+
},
126+
"upd": {
127+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
128+
"ACL_RULE": {
129+
"XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" },
130+
"XXX|RULE_2": { "SRC_IP": "12.12.12.12/16" }
131+
}
132+
},
133+
"sleep_time": 1
134+
},
135+
{
136+
"old": {
137+
"ACL_TABLE": { "XXX": { "type": "CTRLPLANE" } },
138+
"ACL_RULE": { "XXX|RULE_1": { "SRC_IP": "10.10.10.10/16" } }
139+
},
140+
"upd": {},
141+
"sleep_time": 1
142+
},
143+
]
144+
63145
test_rsyslog_fail = [
64146
# Fail the calls, to get the entire fail path calls invoked
65147
#
@@ -70,17 +152,14 @@ def mock_os_system_call(cmd):
70152
{ "cmd": "systemctl restart rsyslog", "rc": 1 }, # restart again; fails
71153
]
72154

73-
74155
class TestServiceValidator(unittest.TestCase):
75156

76157
@patch("generic_config_updater.change_applier.os.system")
77-
def test_change_apply(self, mock_os_sys):
78-
global os_system_expected_cmd
158+
def test_change_apply_os_system(self, mock_os_sys):
79159
global os_system_calls, os_system_call_index
80160

81161
mock_os_sys.side_effect = mock_os_system_call
82162

83-
i = 0
84163
for entry in test_data:
85164
if entry["cmd"]:
86165
os_system_calls.append({"cmd": entry["cmd"], "rc": 0 })
@@ -89,6 +168,7 @@ def test_change_apply(self, mock_os_sys):
89168
vlan_validator(entry["old"], entry["upd"], None)
90169

91170

171+
92172
# Test failure case
93173
#
94174
os_system_calls = test_rsyslog_fail
@@ -97,3 +177,16 @@ def test_change_apply(self, mock_os_sys):
97177
rc = rsyslog_validator("", "", "")
98178
assert not rc, "rsyslog_validator expected to fail"
99179

180+
@patch("generic_config_updater.services_validator.time.sleep")
181+
def test_change_apply_time_sleep(self, mock_time_sleep):
182+
global time_sleep_calls, time_sleep_call_index
183+
184+
mock_time_sleep.side_effect = mock_time_sleep_call
185+
186+
for entry in test_caclrule:
187+
if entry["sleep_time"]:
188+
time_sleep_calls.append({"sleep_time": entry["sleep_time"]})
189+
msg = "case failed: {}".format(str(entry))
190+
191+
caclmgrd_validator(entry["old"], entry["upd"], None)
192+

0 commit comments

Comments
 (0)