Skip to content

Commit

Permalink
[Clock] Update system timezone via ConfigDB (#57)
Browse files Browse the repository at this point in the history
This PR brings functionality that allows us to update the system timezone by writing to the timezone field of the DEVICE_METADATA table of ConfigDB.
The clock CLI implemented in #2793 uses that functionality as the backend.

Signed-off-by: Yevhen Fastiuk <yfastiuk@nvidia.com>
  • Loading branch information
fastiuk authored Jun 2, 2023
1 parent b90277e commit 7e6b5a4
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 26 deletions.
34 changes: 34 additions & 0 deletions scripts/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -1449,12 +1449,16 @@ class DeviceMetaCfg(object):

def __init__(self):
self.hostname = ''
self.timezone = None

def load(self, dev_meta={}):
# Get hostname initial
self.hostname = dev_meta.get('localhost', {}).get('hostname', '')
syslog.syslog(syslog.LOG_DEBUG, f'Initial hostname: {self.hostname}')

# Load appropriate config
self.timezone = dev_meta.get('localhost', {}).get('timezone')

def hostname_update(self, data):
"""
Apply hostname handler.
Expand Down Expand Up @@ -1485,6 +1489,35 @@ class DeviceMetaCfg(object):
return
run_cmd(['sudo', 'monit', 'reload'])

def timezone_update(self, data):
"""
Apply timezone handler.
Run the following command in Linux: timedatectl set-timezone <timezone>
Args:
data: Read table's key's data.
"""
new_timezone = data.get('timezone')
syslog.syslog(syslog.LOG_DEBUG,
f'DeviceMetaCfg: timezone update to {new_timezone}')

if new_timezone is None:
syslog.syslog(syslog.LOG_DEBUG,
f'DeviceMetaCfg: Recieved empty timezone')
return

if new_timezone == self.timezone:
syslog.syslog(syslog.LOG_DEBUG,
f'DeviceMetaCfg: No change in timezone')
return

# run command will print out log error in case of error
run_cmd(['timedatectl', 'set-timezone', new_timezone])
self.timezone = new_timezone

run_cmd(['systemctl', 'restart', 'rsyslog'], True, False)
syslog.syslog(syslog.LOG_INFO, 'DeviceMetaCfg: Restart rsyslog after '
'changing timezone')

class MgmtIfaceCfg(object):
"""
MgmtIfaceCfg Config Daemon
Expand Down Expand Up @@ -1824,6 +1857,7 @@ class HostConfigDaemon:
def device_metadata_handler(self, key, op, data):
syslog.syslog(syslog.LOG_INFO, 'DeviceMeta handler...')
self.devmetacfg.hostname_update(data)
self.devmetacfg.timezone_update(data)

def syslog_handler(self, key, op, data):
self.syslogcfg.syslog_update(data)
Expand Down
53 changes: 29 additions & 24 deletions tests/hostcfgd/hostcfgd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,15 @@ def test_loopback_update(self):
class TestHostcfgdDaemon(TestCase):

def setUp(self):
self.get_dev_meta = mock.patch(
'sonic_py_common.device_info.get_device_runtime_metadata',
return_value={'DEVICE_RUNTIME_METADATA': {}})
self.get_dev_meta.start()
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)

def tearDown(self):
MockConfigDb.CONFIG_DB = {}
self.get_dev_meta.stop()

@patchfs
def test_feature_events(self, fs):
Expand Down Expand Up @@ -564,6 +569,7 @@ def test_devicemeta_event(self):
"""
Test handling DEVICE_METADATA events.
1) Hostname reload
1) Timezone reload
"""
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
MockConfigDb.event_queue = [(swsscommon.CFG_DEVICE_METADATA_TABLE_NAME,
Expand All @@ -575,19 +581,16 @@ def test_devicemeta_event(self):
daemon.load(HOSTCFG_DAEMON_INIT_CFG_DB)
daemon.register_callbacks()
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
popen_mock = mock.Mock()
attrs = {'communicate.return_value': ('output', 'error')}
popen_mock.configure_mock(**attrs)
mocked_subprocess.Popen.return_value = popen_mock

try:
daemon.start()
except TimeoutError:
pass

expected = [
call(['sudo', 'service', 'hostname-config', 'restart']),
call(['sudo', 'monit', 'reload'])
call(['sudo', 'monit', 'reload']),
call(['timedatectl', 'set-timezone', 'Europe/Kyiv']),
call(['systemctl', 'restart', 'rsyslog']),
]
mocked_subprocess.check_call.assert_has_calls(expected,
any_order=True)
Expand All @@ -597,31 +600,33 @@ def test_devicemeta_event(self):
original_syslog = hostcfgd.syslog
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
with mock.patch('hostcfgd.syslog') as mocked_syslog:
mocked_syslog.LOG_ERR = original_syslog.LOG_ERR
try:
daemon.start()
except TimeoutError:
pass
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
mocked_syslog.LOG_ERR = original_syslog.LOG_ERR
try:
daemon.start()
except TimeoutError:
pass

expected = [
call(original_syslog.LOG_ERR, 'Hostname was not updated: Empty not allowed')
]
mocked_syslog.syslog.assert_has_calls(expected)
expected = [
call(original_syslog.LOG_ERR, 'Hostname was not updated: Empty not allowed')
]
mocked_syslog.syslog.assert_has_calls(expected)

daemon.devmetacfg.hostname = "SameHostName"
HOSTCFG_DAEMON_CFG_DB["DEVICE_METADATA"]["localhost"]["hostname"] = daemon.devmetacfg.hostname
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
with mock.patch('hostcfgd.syslog') as mocked_syslog:
mocked_syslog.LOG_INFO = original_syslog.LOG_INFO
try:
daemon.start()
except TimeoutError:
pass
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
mocked_syslog.LOG_INFO = original_syslog.LOG_INFO
try:
daemon.start()
except TimeoutError:
pass

expected = [
call(original_syslog.LOG_INFO, 'Hostname was not updated: Already set up with the same name: SameHostName')
]
mocked_syslog.syslog.assert_has_calls(expected)
expected = [
call(original_syslog.LOG_INFO, 'Hostname was not updated: Already set up with the same name: SameHostName')
]
mocked_syslog.syslog.assert_has_calls(expected)

def test_mgmtiface_event(self):
"""
Expand Down
6 changes: 4 additions & 2 deletions tests/hostcfgd/test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,8 @@
"LOOPBACK_INTERFACE": {},
"DEVICE_METADATA": {
"localhost": {
"hostname": "old-hostname"
"hostname": "old-hostname",
"timezone": "Etc/UTC"
}
},
"MGMT_INTERFACE": {},
Expand Down Expand Up @@ -1247,7 +1248,8 @@
"localhost": {
"subtype": "DualToR",
"type": "ToRRouter",
"hostname": "SomeNewHostname"
"hostname": "SomeNewHostname",
"timezone": "Europe/Kyiv"
}
},
"MGMT_INTERFACE": {
Expand Down

0 comments on commit 7e6b5a4

Please sign in to comment.