Cherry-pick https://github.com/sonic-net/sonic-host-services/pull/19 into 202205 (#12869)
This commit is contained in:
parent
b8244b71dc
commit
72425c0ff5
@ -11,7 +11,7 @@ import signal
|
||||
import re
|
||||
import jinja2
|
||||
from sonic_py_common import device_info
|
||||
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table
|
||||
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table, SonicDBConfig
|
||||
|
||||
# FILE
|
||||
PAM_AUTH_CONF = "/etc/pam.d/common-auth-sonic"
|
||||
@ -199,6 +199,21 @@ class FeatureHandler(object):
|
||||
self._cached_config = {}
|
||||
self.is_multi_npu = device_info.is_multi_npu()
|
||||
self._device_running_config = device_info.get_device_runtime_metadata()
|
||||
self.ns_cfg_db = {}
|
||||
self.ns_feature_state_tbl = {}
|
||||
|
||||
# Initlaize Global config that loads all database*.json
|
||||
if self.is_multi_npu:
|
||||
SonicDBConfig.initializeGlobalConfig()
|
||||
namespaces = device_info.get_namespaces()
|
||||
for ns in namespaces:
|
||||
#Connect to ConfigDB in each namespace
|
||||
self.ns_cfg_db[ns] = ConfigDBConnector(namespace=ns)
|
||||
self.ns_cfg_db[ns].connect(wait_for_init=True, retry_on=True)
|
||||
|
||||
#Connect to stateDB in each namespace
|
||||
db_conn = DBConnector(STATE_DB, 0, False, ns);
|
||||
self.ns_feature_state_tbl[ns] = Table(db_conn, 'FEATURE')
|
||||
|
||||
def handler(self, feature_name, op, feature_cfg):
|
||||
if not feature_cfg:
|
||||
@ -246,7 +261,6 @@ class FeatureHandler(object):
|
||||
device_config = {}
|
||||
device_config.update(self._device_config)
|
||||
device_config.update(self._device_running_config)
|
||||
|
||||
feature = Feature(feature_name, feature_table[feature_name], device_config)
|
||||
|
||||
self._cached_config.setdefault(feature_name, feature)
|
||||
@ -333,6 +347,10 @@ class FeatureHandler(object):
|
||||
self.set_feature_state(feature, self.FEATURE_STATE_FAILED)
|
||||
return
|
||||
self._config_db.mod_entry('FEATURE', feature_config.name, {'has_per_asic_scope': str(feature_config.has_per_asic_scope)})
|
||||
|
||||
# sync has_per_asic_scope to CONFIG_DB in namespaces in multi-asic platform
|
||||
for ns, db in self.ns_cfg_db.items():
|
||||
db.mod_entry('FEATURE', feature_config.name, {'has_per_asic_scope': str(feature_config.has_per_asic_scope)})
|
||||
|
||||
def update_systemd_config(self, feature_config):
|
||||
"""Updates `Restart=` field in feature's systemd configuration file
|
||||
@ -459,9 +477,16 @@ class FeatureHandler(object):
|
||||
def resync_feature_state(self, feature):
|
||||
self._config_db.mod_entry('FEATURE', feature.name, {'state': feature.state})
|
||||
|
||||
# resync the feature state to CONFIG_DB in namespaces in multi-asic platform
|
||||
for ns, db in self.ns_cfg_db.items():
|
||||
db.mod_entry('FEATURE', feature.name, {'state': feature.state})
|
||||
|
||||
def set_feature_state(self, feature, state):
|
||||
self._feature_state_table.set(feature.name, [('state', state)])
|
||||
|
||||
# Update the feature state to STATE_DB in namespaces in multi-asic platform
|
||||
for ns, tbl in self.ns_feature_state_tbl.items():
|
||||
tbl.set(feature.name, [('state', state)])
|
||||
|
||||
class Iptables(object):
|
||||
def __init__(self):
|
||||
|
@ -57,5 +57,5 @@ class MockConfigDb(object):
|
||||
|
||||
|
||||
class MockDBConnector():
|
||||
def __init__(self, db, val):
|
||||
def __init__(self, db, val, tcpFlag=False, name=None):
|
||||
pass
|
||||
|
@ -27,7 +27,6 @@ hostcfgd.ConfigDBConnector = MockConfigDb
|
||||
hostcfgd.DBConnector = MockDBConnector
|
||||
hostcfgd.Table = mock.Mock()
|
||||
|
||||
|
||||
class TestFeatureHandler(TestCase):
|
||||
"""Test methods of `FeatureHandler` class.
|
||||
"""
|
||||
@ -126,39 +125,46 @@ class TestFeatureHandler(TestCase):
|
||||
with mock.patch("sonic_py_common.device_info.get_device_runtime_metadata", return_value=config_data['device_runtime_metadata']):
|
||||
with mock.patch("sonic_py_common.device_info.is_multi_npu", return_value=True if 'num_npu' in config_data else False):
|
||||
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):
|
||||
popen_mock = mock.Mock()
|
||||
attrs = config_data['popen_attributes']
|
||||
popen_mock.configure_mock(**attrs)
|
||||
mocked_subprocess.Popen.return_value = popen_mock
|
||||
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 []):
|
||||
popen_mock = mock.Mock()
|
||||
attrs = config_data['popen_attributes']
|
||||
popen_mock.configure_mock(**attrs)
|
||||
mocked_subprocess.Popen.return_value = popen_mock
|
||||
|
||||
device_config = {}
|
||||
device_config['DEVICE_METADATA'] = MockConfigDb.CONFIG_DB['DEVICE_METADATA']
|
||||
device_config.update(config_data['device_runtime_metadata'])
|
||||
device_config = {}
|
||||
device_config['DEVICE_METADATA'] = MockConfigDb.CONFIG_DB['DEVICE_METADATA']
|
||||
device_config.update(config_data['device_runtime_metadata'])
|
||||
|
||||
feature_handler = hostcfgd.FeatureHandler(MockConfigDb(), feature_state_table_mock, device_config)
|
||||
feature_handler = hostcfgd.FeatureHandler(MockConfigDb(), feature_state_table_mock, device_config)
|
||||
feature_table = MockConfigDb.CONFIG_DB['FEATURE']
|
||||
feature_handler.sync_state_field(feature_table)
|
||||
|
||||
feature_table = MockConfigDb.CONFIG_DB['FEATURE']
|
||||
feature_handler.sync_state_field(feature_table)
|
||||
feature_systemd_name_map = {}
|
||||
for feature_name in feature_table.keys():
|
||||
feature = hostcfgd.Feature(feature_name, feature_table[feature_name], device_config)
|
||||
feature_names, _ = feature_handler.get_multiasic_feature_instances(feature)
|
||||
feature_systemd_name_map[feature_name] = feature_names
|
||||
|
||||
feature_systemd_name_map = {}
|
||||
for feature_name in feature_table.keys():
|
||||
feature = hostcfgd.Feature(feature_name, feature_table[feature_name], device_config)
|
||||
feature_names, _ = feature_handler.get_multiasic_feature_instances(feature)
|
||||
feature_systemd_name_map[feature_name] = feature_names
|
||||
is_any_difference = self.checks_config_table(MockConfigDb.get_config_db()['FEATURE'],
|
||||
config_data['expected_config_db']['FEATURE'])
|
||||
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' is modified unexpectedly!"
|
||||
|
||||
is_any_difference = self.checks_config_table(MockConfigDb.get_config_db()['FEATURE'],
|
||||
config_data['expected_config_db']['FEATURE'])
|
||||
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' is modified unexpectedly!"
|
||||
if 'num_npu' in config_data:
|
||||
for ns in range(config_data['num_npu']):
|
||||
namespace = "asic{}".format(ns)
|
||||
is_any_difference = self.checks_config_table(feature_handler.ns_cfg_db[namespace].get_config_db()['FEATURE'],
|
||||
config_data['expected_config_db']['FEATURE'])
|
||||
assert is_any_difference, "'FEATURE' table in 'CONFIG_DB' in namespace {} is modified unexpectedly!".format(namespace)
|
||||
|
||||
feature_table_state_db_calls = self.get_state_db_set_calls(feature_table)
|
||||
feature_table_state_db_calls = self.get_state_db_set_calls(feature_table)
|
||||
|
||||
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
|
||||
mocked_subprocess.check_call.assert_has_calls(config_data['enable_feature_subprocess_calls'],
|
||||
any_order=True)
|
||||
mocked_subprocess.check_call.assert_has_calls(config_data['daemon_reload_subprocess_call'],
|
||||
any_order=True)
|
||||
feature_state_table_mock.set.assert_has_calls(feature_table_state_db_calls)
|
||||
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
|
||||
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
|
||||
mocked_subprocess.check_call.assert_has_calls(config_data['enable_feature_subprocess_calls'],
|
||||
any_order=True)
|
||||
mocked_subprocess.check_call.assert_has_calls(config_data['daemon_reload_subprocess_call'],
|
||||
any_order=True)
|
||||
feature_state_table_mock.set.assert_has_calls(feature_table_state_db_calls)
|
||||
self.checks_systemd_config_file(config_data['config_db']['FEATURE'], feature_systemd_name_map)
|
||||
|
||||
@parameterized.expand(HOSTCFGD_TEST_VECTOR)
|
||||
@patchfs
|
||||
|
@ -1030,6 +1030,141 @@ HOSTCFGD_TEST_VECTOR = [
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"Chassis_LineCard_VOQ_multinpu",
|
||||
{
|
||||
"num_npu": 2,
|
||||
"device_runtime_metadata": {
|
||||
"DEVICE_RUNTIME_METADATA": {
|
||||
"CHASSIS_METADATA": {
|
||||
"module_type": "linecard",
|
||||
"chassis_type": "voq"
|
||||
},
|
||||
"ETHERNET_PORTS_PRESENT":True,
|
||||
"MACSEC_SUPPORTED":True
|
||||
}
|
||||
},
|
||||
"config_db": {
|
||||
"DEVICE_METADATA": {
|
||||
"localhost": {
|
||||
"type": "SpineRouter",
|
||||
}
|
||||
},
|
||||
"KDUMP": {
|
||||
"config": {
|
||||
"enabled": "false",
|
||||
"num_dumps": "3",
|
||||
"memory": "0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M"
|
||||
}
|
||||
},
|
||||
"FEATURE": {
|
||||
"bgp": {
|
||||
"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 %}",
|
||||
"has_timer": "False",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"auto_restart": "enabled",
|
||||
"high_mem_alert": "disabled"
|
||||
},
|
||||
"teamd": {
|
||||
"state": "{% if not DEVICE_RUNTIME_METADATA['ETHERNET_PORTS_PRESENT'] %}disabled{% else %}enabled{% endif %}",
|
||||
"has_timer": "False",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"auto_restart": "enabled",
|
||||
"high_mem_alert": "disabled"
|
||||
},
|
||||
"lldp": {
|
||||
"state": "enabled",
|
||||
"has_timer": "False",
|
||||
"has_global_scope": "True",
|
||||
"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 %}",
|
||||
"auto_restart": "enabled",
|
||||
"high_mem_alert": "disabled"
|
||||
},
|
||||
"macsec": {
|
||||
"state": "{% if 'type' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['type'] == 'SpineRouter' and DEVICE_RUNTIME_METADATA['MACSEC_SUPPORTED'] %}enabled{% else %}disabled{% endif %}",
|
||||
"has_timer": "False",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"auto_restart": "enabled",
|
||||
"high_mem_alert": "disabled"
|
||||
}
|
||||
},
|
||||
},
|
||||
"expected_config_db": {
|
||||
"FEATURE": {
|
||||
"bgp": {
|
||||
"auto_restart": "enabled",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"has_timer": "False",
|
||||
"high_mem_alert": "disabled",
|
||||
"state": "enabled"
|
||||
},
|
||||
"teamd": {
|
||||
"auto_restart": "enabled",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"has_timer": "False",
|
||||
"high_mem_alert": "disabled",
|
||||
"state": "enabled"
|
||||
},
|
||||
"lldp": {
|
||||
"auto_restart": "enabled",
|
||||
"has_global_scope": "True",
|
||||
"has_per_asic_scope": "True",
|
||||
"has_timer": "False",
|
||||
"high_mem_alert": "disabled",
|
||||
"state": "enabled"
|
||||
},
|
||||
"macsec": {
|
||||
"auto_restart": "enabled",
|
||||
"has_global_scope": "False",
|
||||
"has_per_asic_scope": "True",
|
||||
"has_timer": "False",
|
||||
"high_mem_alert": "disabled",
|
||||
"state": "enabled"
|
||||
}
|
||||
},
|
||||
},
|
||||
"enable_feature_subprocess_calls": [
|
||||
call('sudo systemctl unmask bgp@0.service', shell=True),
|
||||
call('sudo systemctl enable bgp@0.service', shell=True),
|
||||
call('sudo systemctl start bgp@0.service', shell=True),
|
||||
call('sudo systemctl unmask bgp@1.service', shell=True),
|
||||
call('sudo systemctl enable bgp@1.service', shell=True),
|
||||
call('sudo systemctl start bgp@1.service', shell=True),
|
||||
call('sudo systemctl unmask teamd@0.service', shell=True),
|
||||
call('sudo systemctl enable teamd@0.service', shell=True),
|
||||
call('sudo systemctl start teamd@0.service', shell=True),
|
||||
call('sudo systemctl unmask teamd@1.service', shell=True),
|
||||
call('sudo systemctl enable teamd@1.service', shell=True),
|
||||
call('sudo systemctl start teamd@1.service', shell=True),
|
||||
call('sudo systemctl unmask lldp.service', shell=True),
|
||||
call('sudo systemctl enable lldp.service', shell=True),
|
||||
call('sudo systemctl start lldp.service', shell=True),
|
||||
call('sudo systemctl unmask lldp@0.service', shell=True),
|
||||
call('sudo systemctl enable lldp@0.service', shell=True),
|
||||
call('sudo systemctl start lldp@0.service', shell=True),
|
||||
call('sudo systemctl unmask lldp@1.service', shell=True),
|
||||
call('sudo systemctl enable lldp@1.service', shell=True),
|
||||
call('sudo systemctl start lldp@1.service', shell=True),
|
||||
call('sudo systemctl unmask macsec@0.service', shell=True),
|
||||
call('sudo systemctl enable macsec@0.service', shell=True),
|
||||
call('sudo systemctl start macsec@0.service', shell=True),
|
||||
call('sudo systemctl unmask macsec@1.service', shell=True),
|
||||
call('sudo systemctl enable macsec@1.service', shell=True),
|
||||
call('sudo systemctl start macsec@1.service', shell=True)
|
||||
],
|
||||
"daemon_reload_subprocess_call": [
|
||||
call("sudo systemctl daemon-reload", shell=True),
|
||||
],
|
||||
"popen_attributes": {
|
||||
'communicate.return_value': ('output', 'error')
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user