def test_loopback_events(self): MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB) MockConfigDb.event_queue = [('NTP', 'global'), ('NTP_SERVER', '0.debian.pool.ntp.org'), ('LOOPBACK_INTERFACE', 'Loopback0|10.184.8.233/32')] daemon = hostcfgd.HostConfigDaemon() 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('systemctl restart ntp-config', shell=True), call( 'iptables -t mangle --append PREROUTING -p tcp --tcp-flags SYN SYN -d 10.184.8.233 -j TCPMSS --set-mss 1460', shell=True), call( 'iptables -t mangle --append POSTROUTING -p tcp --tcp-flags SYN SYN -s 10.184.8.233 -j TCPMSS --set-mss 1460', shell=True) ] mocked_subprocess.check_call.assert_has_calls(expected, any_order=True)
def test_caclmgrd_dhcp(self, test_name, test_data, fs): if not os.path.exists(DBCONFIG_PATH): fs.create_file(DBCONFIG_PATH) # fake database_config.json MockConfigDb.set_config_db(test_data["config_db"]) with mock.patch("caclmgrd.subprocess") as mocked_subprocess: popen_mock = mock.Mock() popen_attrs = test_data["popen_attributes"] popen_mock.configure_mock(**popen_attrs) mocked_subprocess.Popen.return_value = popen_mock call_rc = test_data["call_rc"] mocked_subprocess.call.return_value = call_rc mark = test_data["mark"] caclmgrd_daemon = caclmgrd.ControlPlaneAclManager("caclmgrd") mux_update = test_data["mux_update"] for key, data in mux_update: caclmgrd_daemon.update_dhcp_acl(key, '', data, mark) mocked_subprocess.call.assert_has_calls( test_data["expected_subprocess_calls"], any_order=False)
def test_hostcfgd_radius(self, test_name, test_data): """ Test RADIUS hostcfd daemon initialization Args: test_name(str): test name test_data(dict): test data which contains initial Config Db tables, and expected results Returns: None """ t_path = templates_path op_path = output_path + "/" + test_name sop_path = sample_output_path + "/" + test_name hostcfgd.PAM_AUTH_CONF_TEMPLATE = t_path + "/common-auth-sonic.j2" hostcfgd.NSS_TACPLUS_CONF_TEMPLATE = t_path + "/tacplus_nss.conf.j2" hostcfgd.NSS_RADIUS_CONF_TEMPLATE = t_path + "/radius_nss.conf.j2" hostcfgd.PAM_RADIUS_AUTH_CONF_TEMPLATE = t_path + "/pam_radius_auth.conf.j2" hostcfgd.PAM_AUTH_CONF = op_path + "/common-auth-sonic" hostcfgd.NSS_TACPLUS_CONF = op_path + "/tacplus_nss.conf" hostcfgd.NSS_RADIUS_CONF = op_path + "/radius_nss.conf" hostcfgd.NSS_CONF = op_path + "/nsswitch.conf" hostcfgd.ETC_PAMD_SSHD = op_path + "/sshd" hostcfgd.ETC_PAMD_LOGIN = op_path + "/login" hostcfgd.RADIUS_PAM_AUTH_CONF_DIR = op_path + "/" shutil.rmtree(op_path, ignore_errors=True) os.mkdir(op_path) shutil.copyfile(sop_path + "/sshd.old", op_path + "/sshd") shutil.copyfile(sop_path + "/login.old", op_path + "/login") MockConfigDb.set_config_db(test_data["config_db"]) host_config_daemon = hostcfgd.HostConfigDaemon() aaa = host_config_daemon.config_db.get_table('AAA') try: radius_global = host_config_daemon.config_db.get_table('RADIUS') except: radius_global = [] try: radius_server = \ host_config_daemon.config_db.get_table('RADIUS_SERVER') except: radius_server = [] host_config_daemon.aaacfg.load(aaa, [], [], radius_global, radius_server) dcmp = filecmp.dircmp(sop_path, op_path) diff_output = "" for name in dcmp.diff_files: diff_output += \ "Diff: file: {} expected: {} output: {}\n".format(\ name, dcmp.left, dcmp.right) diff_output += self.run_diff( dcmp.left + "/" + name,\ dcmp.right + "/" + name) self.assertTrue(len(diff_output) == 0, diff_output)
def test_hostcfgd(self, test_name, test_data, fs): """ Test hostcfd daemon initialization Args: test_name(str): test name test_data(dict): test data which contains initial Config Db tables, and expected results Returns: None """ fs.add_real_paths( swsscommon_package.__path__ ) # add real path of swsscommon for database_config.json fs.create_dir(hostcfgd.FeatureHandler.SYSTEMD_SYSTEM_DIR) MockConfigDb.set_config_db(test_data["config_db"]) with mock.patch("hostcfgd.subprocess") as mocked_subprocess: popen_mock = mock.Mock() attrs = test_data["popen_attributes"] popen_mock.configure_mock(**attrs) mocked_subprocess.Popen.return_value = popen_mock host_config_daemon = hostcfgd.HostConfigDaemon() host_config_daemon.feature_handler.update_all_features_config() assert self.__verify_table( MockConfigDb.get_config_db()["FEATURE"], test_data["expected_config_db"]["FEATURE"] ), "Test failed for test data: {0}".format(test_data) mocked_subprocess.check_call.assert_has_calls( test_data["expected_subprocess_calls"], any_order=True) self.__verify_fs(test_data["config_db"]["FEATURE"])
def check_config(self, test_name, test_data, config_name): t_path = templates_path op_path = output_path + "/" + test_name + "_" + config_name sop_path = sample_output_path + "/" + test_name + "_" + config_name hostcfgd.PAM_AUTH_CONF_TEMPLATE = t_path + "/common-auth-sonic.j2" hostcfgd.NSS_TACPLUS_CONF_TEMPLATE = t_path + "/tacplus_nss.conf.j2" hostcfgd.NSS_RADIUS_CONF_TEMPLATE = t_path + "/radius_nss.conf.j2" hostcfgd.PAM_RADIUS_AUTH_CONF_TEMPLATE = t_path + "/pam_radius_auth.conf.j2" hostcfgd.PAM_AUTH_CONF = op_path + "/common-auth-sonic" hostcfgd.NSS_TACPLUS_CONF = op_path + "/tacplus_nss.conf" hostcfgd.NSS_RADIUS_CONF = op_path + "/radius_nss.conf" hostcfgd.NSS_CONF = op_path + "/nsswitch.conf" hostcfgd.ETC_PAMD_SSHD = op_path + "/sshd" hostcfgd.ETC_PAMD_LOGIN = op_path + "/login" hostcfgd.RADIUS_PAM_AUTH_CONF_DIR = op_path + "/" shutil.rmtree(op_path, ignore_errors=True) os.mkdir(op_path) shutil.copyfile(sop_path + "/sshd.old", op_path + "/sshd") shutil.copyfile(sop_path + "/login.old", op_path + "/login") MockConfigDb.set_config_db(test_data[config_name]) host_config_daemon = hostcfgd.HostConfigDaemon() aaa = host_config_daemon.config_db.get_table('AAA') try: tacacs_global = host_config_daemon.config_db.get_table('TACPLUS') except: tacacs_global = [] try: tacacs_server = \ host_config_daemon.config_db.get_table('TACPLUS_SERVER') except: tacacs_server = [] host_config_daemon.aaacfg.load(aaa, tacacs_global, tacacs_server, [], []) dcmp = filecmp.dircmp(sop_path, op_path) diff_output = "" for name in dcmp.diff_files: diff_output += \ "Diff: file: {} expected: {} output: {}\n".format(\ name, dcmp.left, dcmp.right) diff_output += self.run_diff( dcmp.left + "/" + name,\ dcmp.right + "/" + name) self.assertTrue(len(diff_output) == 0, diff_output)
def test_sync_state_field(self, test_scenario_name, config_data, fs): """Tests the method `sync_state_field(...)` of `FeatureHandler` class. Args: test_secnario_name: A string indicates different testing scenario. config_data: A dictionary contains initial `CONFIG_DB` tables and expected results. Returns: Boolean value indicates whether test will pass or not. """ # add real path of sesscommon for database_config.json fs.add_real_paths(swsscommon_package.__path__) fs.create_dir(hostcfgd.FeatureHandler.SYSTEMD_SYSTEM_DIR) MockConfigDb.set_config_db(config_data['config_db']) feature_state_table_mock = mock.Mock() with mock.patch('hostcfgd.subprocess') as mocked_subprocess: 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'] feature_handler = hostcfgd.FeatureHandler( MockConfigDb(), feature_state_table_mock, device_config) feature_table = MockConfigDb.CONFIG_DB['FEATURE'] feature_handler.sync_state_field(feature_table) 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!" feature_table_state_db_calls = self.get_state_db_set_calls( feature_table) self.checks_systemd_config_file( config_data['config_db']['FEATURE']) 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'])
def test_hostcfgd_feature_handler(self, test_name, test_data, fs): """ Test feature config capability in the hostcfd Args: test_name(str): test name test_data(dict): test data which contains initial Config Db tables, and expected results Returns: None """ fs.add_real_paths( swsscommon_package.__path__ ) # add real path of swsscommon for database_config.json fs.create_dir(hostcfgd.FeatureHandler.SYSTEMD_SYSTEM_DIR) MockConfigDb.set_config_db(test_data['config_db']) feature_state_table_mock = mock.Mock() with mock.patch('hostcfgd.subprocess') as mocked_subprocess: popen_mock = mock.Mock() attrs = test_data['popen_attributes'] popen_mock.configure_mock(**attrs) mocked_subprocess.Popen.return_value = popen_mock # Initialize Feature Handler device_config = {} device_config['DEVICE_METADATA'] = MockConfigDb.CONFIG_DB[ 'DEVICE_METADATA'] feature_handler = hostcfgd.FeatureHandler( MockConfigDb(), feature_state_table_mock, device_config) # sync the state field and Handle Feature Updates features = MockConfigDb.CONFIG_DB['FEATURE'] feature_handler.sync_state_field(features) for key, fvs in features.items(): feature_handler.handle(key, 'SET', fvs) # Verify if the updates are properly updated assert self.__verify_table( MockConfigDb.get_config_db()['FEATURE'], feature_state_table_mock, test_data['expected_config_db']['FEATURE'] ), 'Test failed for test data: {0}'.format(test_data) mocked_subprocess.check_call.assert_has_calls( test_data['expected_subprocess_calls'], any_order=True) self.__verify_fs(test_data['config_db']['FEATURE'])
def test_caclmgrd_bfd(self, test_name, test_data, fs): if not os.path.exists(DBCONFIG_PATH): fs.create_file(DBCONFIG_PATH) # fake database_config.json MockConfigDb.set_config_db(test_data["config_db"]) with mock.patch("caclmgrd.subprocess") as mocked_subprocess: popen_mock = mock.Mock() popen_attrs = test_data["popen_attributes"] popen_mock.configure_mock(**popen_attrs) mocked_subprocess.Popen.return_value = popen_mock mocked_subprocess.PIPE = -1 call_rc = test_data["call_rc"] mocked_subprocess.call.return_value = call_rc caclmgrd_daemon = self.caclmgrd.ControlPlaneAclManager("caclmgrd") caclmgrd_daemon.allow_bfd_protocol('') mocked_subprocess.Popen.assert_has_calls( test_data["expected_subprocess_calls"], any_order=True)
def test_kdump_event(self): MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB) daemon = hostcfgd.HostConfigDaemon() daemon.register_callbacks() MockConfigDb.event_queue = [('KDUMP', 'config')] 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('sonic-kdump-config --disable', shell=True), call('sonic-kdump-config --num_dumps 3', shell=True), call( 'sonic-kdump-config --memory 0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M', shell=True) ] mocked_subprocess.check_call.assert_has_calls(expected, any_order=True)
def setUp(self): MockConfigDb.set_config_db(HOSTCFG_DAEMON_CFG_DB)
def check_config(self, test_name, test_data, config_name): t_path = templates_path op_path = output_path + "/" + test_name + "_" + config_name sop_path = sample_output_path + "/" + test_name + "_" + config_name sop_path_common = sample_output_path + "/" + test_name hostcfgd.PAM_PASSWORD_CONF_TEMPLATE = t_path + "/common-password.j2" hostcfgd.PAM_AUTH_CONF_TEMPLATE = t_path + "/common-auth-sonic.j2" hostcfgd.NSS_TACPLUS_CONF_TEMPLATE = t_path + "/tacplus_nss.conf.j2" hostcfgd.NSS_RADIUS_CONF_TEMPLATE = t_path + "/radius_nss.conf.j2" hostcfgd.PAM_RADIUS_AUTH_CONF_TEMPLATE = t_path + "/pam_radius_auth.conf.j2" hostcfgd.PAM_PASSWORD_CONF = op_path + "/common-password" hostcfgd.ETC_LOGIN_DEF = op_path + "/login.defs" hostcfgd.PAM_AUTH_CONF = op_path + "/common-auth-sonic" hostcfgd.NSS_TACPLUS_CONF = op_path + "/tacplus_nss.conf" hostcfgd.NSS_RADIUS_CONF = op_path + "/radius_nss.conf" hostcfgd.NSS_CONF = op_path + "/nsswitch.conf" hostcfgd.ETC_PAMD_SSHD = op_path + "/sshd" hostcfgd.ETC_PAMD_LOGIN = op_path + "/login" hostcfgd.RADIUS_PAM_AUTH_CONF_DIR = op_path + "/" shutil.rmtree(op_path, ignore_errors=True) os.mkdir(op_path) shutil.copyfile(sop_path_common + "/login.defs.old", op_path + "/login.defs") MockConfigDb.set_config_db(test_data[config_name]) host_config_daemon = hostcfgd.HostConfigDaemon() try: passwh_table = host_config_daemon.config_db.get_table( 'PASSW_HARDENING') except Exception as e: syslog.syslog( syslog.LOG_ERR, "failed: get_table 'PASSW_HARDENING', exception={}".format(e)) passwh_table = [] host_config_daemon.passwcfg.load(passwh_table) diff_output = "" files_to_compare = ['common-password'] # check output files exists for name in files_to_compare: if not os.path.isfile(sop_path + "/" + name): raise ValueError('filename: %s not exit' % (sop_path + "/" + name)) if not os.path.isfile(op_path + "/" + name): raise ValueError('filename: %s not exit' % (op_path + "/" + name)) # deep comparison match, mismatch, errors = filecmp.cmpfiles(sop_path, op_path, files_to_compare, shallow=False) if not match: for name in files_to_compare: diff_output += self.run_diff( sop_path + "/" + name,\ op_path + "/" + name).decode('utf-8') self.assertTrue(len(diff_output) == 0, diff_output) # compare age data in login.def file. out_passw_age_days = self.get_passw_days(op_path + "/login.defs", 'MAX_DAYS') sout_passw_age_days = self.get_passw_days(sop_path + "/login.defs", 'MAX_DAYS') out_passw_age_warn_days = self.get_passw_days(op_path + "/login.defs", 'WARN_DAYS') sout_passw_age_warn_days = self.get_passw_days( sop_path + "/login.defs", 'WARN_DAYS') self.assertEqual(out_passw_age_days, sout_passw_age_days) self.assertEqual(out_passw_age_warn_days, sout_passw_age_warn_days)