Skip to content

Commit 6eac2d3

Browse files
authored
Merge pull request #19 from judyjoseph/macsec_feature_enable
Update hostcfgd to get the macsec capability and support and update feature state in config/state DB in namespaces for multi-asic.
2 parents bc8698d + 31c6108 commit 6eac2d3

File tree

4 files changed

+203
-37
lines changed

4 files changed

+203
-37
lines changed

scripts/hostcfgd

+27-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import signal
1111
import re
1212
import jinja2
1313
from sonic_py_common import device_info
14-
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table
14+
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table, SonicDBConfig
1515
from swsscommon import swsscommon
1616

1717
# FILE
@@ -200,6 +200,21 @@ class FeatureHandler(object):
200200
self._cached_config = {}
201201
self.is_multi_npu = device_info.is_multi_npu()
202202
self._device_running_config = device_info.get_device_runtime_metadata()
203+
self.ns_cfg_db = {}
204+
self.ns_feature_state_tbl = {}
205+
206+
# Initlaize Global config that loads all database*.json
207+
if self.is_multi_npu:
208+
SonicDBConfig.initializeGlobalConfig()
209+
namespaces = device_info.get_namespaces()
210+
for ns in namespaces:
211+
#Connect to ConfigDB in each namespace
212+
self.ns_cfg_db[ns] = ConfigDBConnector(namespace=ns)
213+
self.ns_cfg_db[ns].connect(wait_for_init=True, retry_on=True)
214+
215+
#Connect to stateDB in each namespace
216+
db_conn = DBConnector(STATE_DB, 0, False, ns);
217+
self.ns_feature_state_tbl[ns] = Table(db_conn, 'FEATURE')
203218

204219
def handler(self, feature_name, op, feature_cfg):
205220
if not feature_cfg:
@@ -247,7 +262,6 @@ class FeatureHandler(object):
247262
device_config = {}
248263
device_config.update(self._device_config)
249264
device_config.update(self._device_running_config)
250-
251265
feature = Feature(feature_name, feature_table[feature_name], device_config)
252266

253267
self._cached_config.setdefault(feature_name, feature)
@@ -334,6 +348,10 @@ class FeatureHandler(object):
334348
self.set_feature_state(feature, self.FEATURE_STATE_FAILED)
335349
return
336350
self._config_db.mod_entry('FEATURE', feature_config.name, {'has_per_asic_scope': str(feature_config.has_per_asic_scope)})
351+
352+
# sync has_per_asic_scope to CONFIG_DB in namespaces in multi-asic platform
353+
for ns, db in self.ns_cfg_db.items():
354+
db.mod_entry('FEATURE', feature_config.name, {'has_per_asic_scope': str(feature_config.has_per_asic_scope)})
337355

338356
def update_systemd_config(self, feature_config):
339357
"""Updates `Restart=` field in feature's systemd configuration file
@@ -460,9 +478,16 @@ class FeatureHandler(object):
460478
def resync_feature_state(self, feature):
461479
self._config_db.mod_entry('FEATURE', feature.name, {'state': feature.state})
462480

481+
# resync the feature state to CONFIG_DB in namespaces in multi-asic platform
482+
for ns, db in self.ns_cfg_db.items():
483+
db.mod_entry('FEATURE', feature.name, {'state': feature.state})
484+
463485
def set_feature_state(self, feature, state):
464486
self._feature_state_table.set(feature.name, [('state', state)])
465487

488+
# Update the feature state to STATE_DB in namespaces in multi-asic platform
489+
for ns, tbl in self.ns_feature_state_tbl.items():
490+
tbl.set(feature.name, [('state', state)])
466491

467492
class Iptables(object):
468493
def __init__(self):

tests/common/mock_configdb.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ def listen(self, init_data_handler=None):
5757

5858

5959
class MockDBConnector():
60-
def __init__(self, db, val):
60+
def __init__(self, db, val, tcpFlag=False, name=None):
6161
pass

tests/hostcfgd/hostcfgd_test.py

+40-34
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
hostcfgd.DBConnector = MockDBConnector
2929
hostcfgd.Table = mock.Mock()
3030

31-
3231
class TestFeatureHandler(TestCase):
3332
"""Test methods of `FeatureHandler` class.
3433
"""
@@ -127,39 +126,46 @@ def test_sync_state_field(self, test_scenario_name, config_data, fs):
127126
with mock.patch("sonic_py_common.device_info.get_device_runtime_metadata", return_value=config_data['device_runtime_metadata']):
128127
with mock.patch("sonic_py_common.device_info.is_multi_npu", return_value=True if 'num_npu' in config_data else False):
129128
with mock.patch("sonic_py_common.device_info.get_num_npus", return_value=config_data['num_npu'] if 'num_npu' in config_data else 1):
130-
popen_mock = mock.Mock()
131-
attrs = config_data['popen_attributes']
132-
popen_mock.configure_mock(**attrs)
133-
mocked_subprocess.Popen.return_value = popen_mock
134-
135-
device_config = {}
136-
device_config['DEVICE_METADATA'] = MockConfigDb.CONFIG_DB['DEVICE_METADATA']
137-
device_config.update(config_data['device_runtime_metadata'])
138-
139-
feature_handler = hostcfgd.FeatureHandler(MockConfigDb(), feature_state_table_mock, device_config)
140-
141-
feature_table = MockConfigDb.CONFIG_DB['FEATURE']
142-
feature_handler.sync_state_field(feature_table)
143-
144-
feature_systemd_name_map = {}
145-
for feature_name in feature_table.keys():
146-
feature = hostcfgd.Feature(feature_name, feature_table[feature_name], device_config)
147-
feature_names, _ = feature_handler.get_multiasic_feature_instances(feature)
148-
feature_systemd_name_map[feature_name] = feature_names
149-
150-
is_any_difference = self.checks_config_table(MockConfigDb.get_config_db()['FEATURE'],
151-
config_data['expected_config_db']['FEATURE'])
152-
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' is modified unexpectedly!"
153-
154-
feature_table_state_db_calls = self.get_state_db_set_calls(feature_table)
155-
156-
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
157-
mocked_subprocess.check_call.assert_has_calls(config_data['enable_feature_subprocess_calls'],
158-
any_order=True)
159-
mocked_subprocess.check_call.assert_has_calls(config_data['daemon_reload_subprocess_call'],
160-
any_order=True)
161-
feature_state_table_mock.set.assert_has_calls(feature_table_state_db_calls)
162-
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
129+
with mock.patch("sonic_py_common.device_info.get_namespaces", return_value=["asic{}".format(a) for a in range(config_data['num_npu'])] if 'num_npu' in config_data else []):
130+
popen_mock = mock.Mock()
131+
attrs = config_data['popen_attributes']
132+
popen_mock.configure_mock(**attrs)
133+
mocked_subprocess.Popen.return_value = popen_mock
134+
135+
device_config = {}
136+
device_config['DEVICE_METADATA'] = MockConfigDb.CONFIG_DB['DEVICE_METADATA']
137+
device_config.update(config_data['device_runtime_metadata'])
138+
139+
feature_handler = hostcfgd.FeatureHandler(MockConfigDb(), feature_state_table_mock, device_config)
140+
feature_table = MockConfigDb.CONFIG_DB['FEATURE']
141+
feature_handler.sync_state_field(feature_table)
142+
143+
feature_systemd_name_map = {}
144+
for feature_name in feature_table.keys():
145+
feature = hostcfgd.Feature(feature_name, feature_table[feature_name], device_config)
146+
feature_names, _ = feature_handler.get_multiasic_feature_instances(feature)
147+
feature_systemd_name_map[feature_name] = feature_names
148+
149+
is_any_difference = self.checks_config_table(MockConfigDb.get_config_db()['FEATURE'],
150+
config_data['expected_config_db']['FEATURE'])
151+
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' is modified unexpectedly!"
152+
153+
if 'num_npu' in config_data:
154+
for ns in range(config_data['num_npu']):
155+
namespace = "asic{}".format(ns)
156+
is_any_difference = self.checks_config_table(feature_handler.ns_cfg_db[namespace].get_config_db()['FEATURE'],
157+
config_data['expected_config_db']['FEATURE'])
158+
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' in namespace {} is modified unexpectedly!".format(namespace)
159+
160+
feature_table_state_db_calls = self.get_state_db_set_calls(feature_table)
161+
162+
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
163+
mocked_subprocess.check_call.assert_has_calls(config_data['enable_feature_subprocess_calls'],
164+
any_order=True)
165+
mocked_subprocess.check_call.assert_has_calls(config_data['daemon_reload_subprocess_call'],
166+
any_order=True)
167+
feature_state_table_mock.set.assert_has_calls(feature_table_state_db_calls)
168+
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
163169

164170
@parameterized.expand(HOSTCFGD_TEST_VECTOR)
165171
@patchfs

tests/hostcfgd/test_vectors.py

+135
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,141 @@
10301030
},
10311031
},
10321032
],
1033+
[
1034+
"Chassis_LineCard_VOQ_multinpu",
1035+
{
1036+
"num_npu": 2,
1037+
"device_runtime_metadata": {
1038+
"DEVICE_RUNTIME_METADATA": {
1039+
"CHASSIS_METADATA": {
1040+
"module_type": "linecard",
1041+
"chassis_type": "voq"
1042+
},
1043+
"ETHERNET_PORTS_PRESENT":True,
1044+
"MACSEC_SUPPORTED":True
1045+
}
1046+
},
1047+
"config_db": {
1048+
"DEVICE_METADATA": {
1049+
"localhost": {
1050+
"type": "SpineRouter",
1051+
}
1052+
},
1053+
"KDUMP": {
1054+
"config": {
1055+
"enabled": "false",
1056+
"num_dumps": "3",
1057+
"memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M"
1058+
}
1059+
},
1060+
"FEATURE": {
1061+
"bgp": {
1062+
"state": "{% if not DEVICE_RUNTIME_METADATA['ETHERNET_PORTS_PRESENT'] or ('CHASSIS_METADATA' in DEVICE_RUNTIME_METADATA and DEVICE_RUNTIME_METADATA['CHASSIS_METADATA']['module_type'] in ['supervisor']) %}disabled{% else %}enabled{% endif %}",
1063+
"has_timer": "False",
1064+
"has_global_scope": "False",
1065+
"has_per_asic_scope": "True",
1066+
"auto_restart": "enabled",
1067+
"high_mem_alert": "disabled"
1068+
},
1069+
"teamd": {
1070+
"state": "{% if not DEVICE_RUNTIME_METADATA['ETHERNET_PORTS_PRESENT'] %}disabled{% else %}enabled{% endif %}",
1071+
"has_timer": "False",
1072+
"has_global_scope": "False",
1073+
"has_per_asic_scope": "True",
1074+
"auto_restart": "enabled",
1075+
"high_mem_alert": "disabled"
1076+
},
1077+
"lldp": {
1078+
"state": "enabled",
1079+
"has_timer": "False",
1080+
"has_global_scope": "True",
1081+
"has_per_asic_scope": "{% if not DEVICE_RUNTIME_METADATA['ETHERNET_PORTS_PRESENT'] or ('CHASSIS_METADATA' in DEVICE_RUNTIME_METADATA and DEVICE_RUNTIME_METADATA['CHASSIS_METADATA']['module_type'] in ['supervisor']) %}False{% else %}True{% endif %}",
1082+
"auto_restart": "enabled",
1083+
"high_mem_alert": "disabled"
1084+
},
1085+
"macsec": {
1086+
"state": "{% if 'type' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and DEVICE_RUNTIME_METADATA['MACSEC_SUPPORTED'] %}enabled{% else %}disabled{% endif %}",
1087+
"has_timer": "False",
1088+
"has_global_scope": "False",
1089+
"has_per_asic_scope": "True",
1090+
"auto_restart": "enabled",
1091+
"high_mem_alert": "disabled"
1092+
}
1093+
},
1094+
},
1095+
"expected_config_db": {
1096+
"FEATURE": {
1097+
"bgp": {
1098+
"auto_restart": "enabled",
1099+
"has_global_scope": "False",
1100+
"has_per_asic_scope": "True",
1101+
"has_timer": "False",
1102+
"high_mem_alert": "disabled",
1103+
"state": "enabled"
1104+
},
1105+
"teamd": {
1106+
"auto_restart": "enabled",
1107+
"has_global_scope": "False",
1108+
"has_per_asic_scope": "True",
1109+
"has_timer": "False",
1110+
"high_mem_alert": "disabled",
1111+
"state": "enabled"
1112+
},
1113+
"lldp": {
1114+
"auto_restart": "enabled",
1115+
"has_global_scope": "True",
1116+
"has_per_asic_scope": "True",
1117+
"has_timer": "False",
1118+
"high_mem_alert": "disabled",
1119+
"state": "enabled"
1120+
},
1121+
"macsec": {
1122+
"auto_restart": "enabled",
1123+
"has_global_scope": "False",
1124+
"has_per_asic_scope": "True",
1125+
"has_timer": "False",
1126+
"high_mem_alert": "disabled",
1127+
"state": "enabled"
1128+
}
1129+
},
1130+
},
1131+
"enable_feature_subprocess_calls": [
1132+
call('sudo systemctl unmask [email protected]', shell=True),
1133+
call('sudo systemctl enable [email protected]', shell=True),
1134+
call('sudo systemctl start [email protected]', shell=True),
1135+
call('sudo systemctl unmask [email protected]', shell=True),
1136+
call('sudo systemctl enable [email protected]', shell=True),
1137+
call('sudo systemctl start [email protected]', shell=True),
1138+
call('sudo systemctl unmask [email protected]', shell=True),
1139+
call('sudo systemctl enable [email protected]', shell=True),
1140+
call('sudo systemctl start [email protected]', shell=True),
1141+
call('sudo systemctl unmask [email protected]', shell=True),
1142+
call('sudo systemctl enable [email protected]', shell=True),
1143+
call('sudo systemctl start [email protected]', shell=True),
1144+
call('sudo systemctl unmask lldp.service', shell=True),
1145+
call('sudo systemctl enable lldp.service', shell=True),
1146+
call('sudo systemctl start lldp.service', shell=True),
1147+
call('sudo systemctl unmask [email protected]', shell=True),
1148+
call('sudo systemctl enable [email protected]', shell=True),
1149+
call('sudo systemctl start [email protected]', shell=True),
1150+
call('sudo systemctl unmask [email protected]', shell=True),
1151+
call('sudo systemctl enable [email protected]', shell=True),
1152+
call('sudo systemctl start [email protected]', shell=True),
1153+
call('sudo systemctl unmask [email protected]', shell=True),
1154+
call('sudo systemctl enable [email protected]', shell=True),
1155+
call('sudo systemctl start [email protected]', shell=True),
1156+
call('sudo systemctl unmask [email protected]', shell=True),
1157+
call('sudo systemctl enable [email protected]', shell=True),
1158+
call('sudo systemctl start [email protected]', shell=True)
1159+
],
1160+
"daemon_reload_subprocess_call": [
1161+
call("sudo systemctl daemon-reload", shell=True),
1162+
],
1163+
"popen_attributes": {
1164+
'communicate.return_value': ('output', 'error')
1165+
},
1166+
},
1167+
]
10331168

10341169
]
10351170

0 commit comments

Comments
 (0)