Skip to content

Commit

Permalink
[hostcfgd][dns] Subscribe to DNS_NAMESERVER table to react to static …
Browse files Browse the repository at this point in the history
…DNS configuration changes. (#49)

Changes are implemented according to sonic-net/SONiC#1262 HLD.
Implement unit tests for each method of DnsCfg class.
  • Loading branch information
oleksandrivantsiv authored Jun 22, 2023
1 parent 508d642 commit eab4a9e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 3 deletions.
23 changes: 22 additions & 1 deletion scripts/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,16 @@ class RSyslogCfg(object):
self.cache['config'] = rsyslog_config
self.cache['servers'] = rsyslog_servers


class DnsCfg:

def load(self, *args, **kwargs):
self.dns_update()

def dns_update(self, *args, **kwargs):
run_cmd(['systemctl', 'restart', 'resolv-config'], True, False)


class HostConfigDaemon:
def __init__(self):
self.state_db_conn = DBConnector(STATE_DB, 0)
Expand Down Expand Up @@ -1713,6 +1723,9 @@ class HostConfigDaemon:
# Initialize RSyslogCfg
self.rsyslogcfg = RSyslogCfg()

# Initialize DnsCfg
self.dnscfg = DnsCfg()

def load(self, init_data):
features = init_data['FEATURE']
aaa = init_data['AAA']
Expand All @@ -1730,7 +1743,7 @@ class HostConfigDaemon:
mgmt_vrf = init_data.get(swsscommon.CFG_MGMT_VRF_CONFIG_TABLE_NAME, {})
syslog_cfg = init_data.get(swsscommon.CFG_SYSLOG_CONFIG_TABLE_NAME, {})
syslog_srv = init_data.get(swsscommon.CFG_SYSLOG_SERVER_TABLE_NAME, {})

dns = init_data.get('DNS_NAMESERVER', {})

self.feature_handler.sync_state_field(features)
self.aaacfg.load(aaa, tacacs_global, tacacs_server, radius_global, radius_server)
Expand All @@ -1740,7 +1753,9 @@ class HostConfigDaemon:
self.passwcfg.load(passwh)
self.devmetacfg.load(dev_meta)
self.mgmtifacecfg.load(mgmt_ifc, mgmt_vrf)

self.rsyslogcfg.load(syslog_cfg, syslog_srv)
self.dnscfg.load(dns)

# Update AAA with the hostname
self.aaacfg.hostname_update(self.devmetacfg.hostname)
Expand Down Expand Up @@ -1856,6 +1871,10 @@ class HostConfigDaemon:
syslog.syslog(syslog.LOG_INFO, 'SYSLOG_CONFIG table handler...')
self.rsyslog_handler()

def dns_nameserver_handler(self, key, op, data):
syslog.syslog(syslog.LOG_INFO, 'DNS nameserver handler...')
self.dnscfg.dns_update(key, data)

def wait_till_system_init_done(self):
# No need to print the output in the log file so using the "--quiet"
# flag
Expand Down Expand Up @@ -1909,6 +1928,8 @@ class HostConfigDaemon:
self.config_db.subscribe(swsscommon.CFG_SYSLOG_SERVER_TABLE_NAME,
make_callback(self.rsyslog_server_handler))

self.config_db.subscribe('DNS_NAMESERVER', make_callback(self.dns_nameserver_handler))

syslog.syslog(syslog.LOG_INFO,
"Waiting for systemctl to finish initialization")
self.wait_till_system_init_done()
Expand Down
33 changes: 33 additions & 0 deletions tests/hostcfgd/hostcfgd_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,7 @@ def test_devicemeta_event(self):
daemon.aaacfg = mock.MagicMock()
daemon.iptables = mock.MagicMock()
daemon.passwcfg = mock.MagicMock()
daemon.dnscfg = mock.MagicMock()
daemon.load(HOSTCFG_DAEMON_INIT_CFG_DB)
daemon.register_callbacks()
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
Expand Down Expand Up @@ -644,6 +645,7 @@ def test_mgmtiface_event(self):
daemon.aaacfg = mock.MagicMock()
daemon.iptables = mock.MagicMock()
daemon.passwcfg = mock.MagicMock()
daemon.dnscfg = mock.MagicMock()
daemon.load(HOSTCFG_DAEMON_INIT_CFG_DB)
with mock.patch('hostcfgd.check_output_pipe') as mocked_check_output:
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
Expand All @@ -670,3 +672,34 @@ def test_mgmtiface_event(self):
call(['cat', '/proc/net/route'], ['grep', '-E', r"eth0\s+00000000\s+[0-9A-Z]+\s+[0-9]+\s+[0-9]+\s+[0-9]+\s+202"], ['wc', '-l'])
]
mocked_check_output.assert_has_calls(expected)

def test_dns_events(self):
MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
MockConfigDb.event_queue = [('DNS_NAMESERVER', '1.1.1.1')]
daemon = hostcfgd.HostConfigDaemon()
daemon.register_callbacks()
with mock.patch('hostcfgd.run_cmd') as mocked_run_cmd:
try:
daemon.start()
except TimeoutError:
pass
mocked_run_cmd.assert_has_calls([call(['systemctl', 'restart', 'resolv-config'], True, False)])


class TestDnsHandler:

@mock.patch('hostcfgd.run_cmd')
def test_dns_update(self, mock_run_cmd):
dns_cfg = hostcfgd.DnsCfg()
key = "1.1.1.1"
dns_cfg.dns_update(key, {})

mock_run_cmd.assert_has_calls([call(['systemctl', 'restart', 'resolv-config'], True, False)])

def test_load(self):
dns_cfg = hostcfgd.DnsCfg()
dns_cfg.dns_update = mock.MagicMock()

data = {}
dns_cfg.load(data)
dns_cfg.dns_update.assert_called()
8 changes: 6 additions & 2 deletions tests/hostcfgd/test_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -1185,7 +1185,8 @@
"MGMT_INTERFACE": {},
"MGMT_VRF_CONFIG": {},
"SYSLOG_CONFIG": {},
"SYSLOG_SERVER": {}
"SYSLOG_SERVER": {},
"DNS_NAMESERVER": {}
}


Expand Down Expand Up @@ -1261,5 +1262,8 @@
"vrf_global": {
'mgmtVrfEnabled': 'true'
}
}
},
"DNS_NAMESERVER": {
"1.1.1.1": {}
},
}

0 comments on commit eab4a9e

Please sign in to comment.