def test_per_config_options_encrypted(self, can_write): options = Mock() options.force_register = True can_write.return_value = True with tempfile.NamedTemporaryFile() as tmp: password.Password.KEYFILE = tmp.name config_dict = { "sat_server": "http://localhost:%s" % TEST_PORT, "sat_username": "******", "sat_encrypted_password": hexlify(password.Password.encrypt('password')), "type": "libvirt", } config = VirtConfigSection.from_dict(config_dict, 'test', None) config.validate() dests = DestinationToSourceMapper.parse_dests_from_dict( config._values) self.assertEqual(len(dests), 1) dest_info = dests.pop() s = Manager.fromInfo(self.logger, options, dest_info) self.assertTrue(isinstance(s, Satellite)) report = HostGuestAssociationReport(config, self.mapping) result = s.hypervisorCheckIn(report, options) self.assertTrue("failedUpdate" in result) self.assertTrue("created" in result) self.assertTrue("updated" in result)
def testCLIConfigOverridesDefaultDirectoryConfigs(self): cli_config_file_path = os.path.join(self.custom_config_dir, "my_file.conf") with open(cli_config_file_path, "w") as f: f.write(""" [valid_cli_section] server=5.5.5.5 username=admin1 password=password1 owner=owner1 rhsm_hostname=abc1 """) cli_dict = {'configs': [cli_config_file_path]} with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [valid_default_dir_section] server=1.2.3.4 username=admin password=password owner=owner rhsm_hostname=abc """) config_manager = DestinationToSourceMapper( init_config(cli_dict, config_dir=self.config_dir)) # There should be only one config, and that should be the one passed from the cli self.assertEqual(len(config_manager.configs), 1) config = config_manager.configs[0][1] self.assertEqual(config.name, "valid_cli_section") self.assertEqual(config["server"], "5.5.5.5") self.assertEqual(config["username"], "admin1") self.assertEqual(config["password"], "password1") self.assertEqual(config["owner"], "owner1") self.assertEqual(config["rhsm_hostname"], "abc1")
def test_read_hypervisor(self): with open(self.hypervisor_file, "w") as f: f.write(HYPERVISOR_JSON) with open(self.config_file, "w") as f: f.write(""" [test] type=fake is_hypervisor=true owner=taylor env=swift file=%s """ % self.hypervisor_file) effective_config = init_config({}, {}, config_dir=self.config_dir) manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(manager.configs), 1) virt = Virt.from_config(self.logger, manager.configs[0][1], None) self.assertEqual(type(virt), FakeVirt) mapping = virt.getHostGuestMapping() self.assertTrue("hypervisors" in mapping) hypervisors = mapping["hypervisors"] self.assertEqual(len(hypervisors), 1) hypervisor = hypervisors[0] self.assertEqual(type(hypervisor), Hypervisor) self.assertEqual(hypervisor.hypervisorId, "60527517-6284-7593-6AAB-75BF2A6375EF") self.assertEqual(len(hypervisor.guestIds), 1) guest = hypervisor.guestIds[0] self.assertEqual(guest.uuid, "07ED8178-95D5-4244-BC7D-582A54A48FF8") self.assertEqual(guest.state, 1)
def test_satellite_config_file(self): # Username and password are required for a valid sat5 destination with open(os.path.join(self.config_dir, "test.conf"), "w") as f: f.write(""" [test] type=libvirt sat_server=sat.example.com sat_username=sat_username sat_password=sat_password """) conf = parse_file(os.path.join(self.config_dir, "test.conf")) effective_config = EffectiveConfig() conf_values = conf.pop("test") effective_config["test"] = ConfigSection.from_dict( conf_values, "test", effective_config ) config_manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(config_manager.configs), 1) # There should only be one destination detected self.assertEqual(len(config_manager.dests), 1) # Which should be a Satellite5DestinationInfo dest_info = config_manager.dests.pop() self.assertTrue(isinstance(dest_info, Satellite5DestinationInfo), 'The destination info ' 'we got was not of the ' 'expected type') manager = Manager.fromInfo(self.logger, effective_config, dest_info) self.assertTrue(isinstance(manager, Satellite)) self.assertEqual(dest_info.sat_server, 'sat.example.com')
def testInvalidAndValidConfigs(self): valid_config_name = "valid_config" with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [%(valid_config_name)s] type=esx server=1.2.3.4 username=admin password=password owner=owner env=env rhsm_hostname=abc [invalid_missing_owner] type=esx server=1.2.3.4 username=admin password=password env=env rhsm_hostname=abc """ % {'valid_config_name': valid_config_name}) config_manager = DestinationToSourceMapper( init_config({}, {}, config_dir=self.config_dir)) # There should be only one config, and that should be the one that is valid self.assertEqual(len(config_manager.configs), 1) self.assertEqual(config_manager.configs[0][1].name, valid_config_name)
def test_many_sources_to_one_dest(self): # This tests that there can be multiple configs that specify to # report to the same destination config_1 = combine_dicts(TestReadingConfigs.source_options_1, TestReadingConfigs.dest_options_1) config_2 = combine_dicts(TestReadingConfigs.source_options_2, TestReadingConfigs.dest_options_1) expected_dest = Satellite6DestinationInfo( **TestReadingConfigs.dest_options_1) expected_mapping = { expected_dest: [config_1['name'], config_2['name']] } with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write( TestReadingConfigs.dict_to_ini(config_1) + TestReadingConfigs.dict_to_ini(config_2)) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(manager.dests, set([expected_dest])) self.assertEqual(manager.sources, set([config_1['name'], config_2['name']])) self.assertEqual(manager.dest_to_sources_map, expected_mapping)
def testLineContinuationInConfig(self): """ Test that when a config line that starts with space or tab, it is treated as a continuation of the previous line. :return: """ with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [test1] type=esx server=http://1.2.3.4 value username=admin password=password owner=root env=staging filter_hosts=abc.efg.com """) manager = DestinationToSourceMapper( init_config({}, {}, config_dir=self.config_dir)) self.assertEqual(len(manager.configs), 1) config = manager.configs[0][1] self.assertEqual(config.name, "test1") self.assertEqual(config["server"], 'http://1.2.3.4\nvalue') self.assertEqual(config["env"], 'staging\nfilter_hosts=abc.efg.com')
def test_staus(self): with open(self.hypervisor_file, "w") as f: f.write(NON_HYPERVISOR_JSON) with open(self.config_file, "w") as f: f.write(f""" [test] type=fake is_hypervisor=false file={self.hypervisor_file}""") effective_config = init_config({}, config_dir=self.config_dir) manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(manager.configs), 1) self.fake = Virt.from_config(self.logger, manager.configs[0][1], None) self.fake.status = True self.fake._send_data = Mock() self.run_once() self.fake._send_data.assert_called_once_with(data_to_send=ANY) self.assertTrue( isinstance( self.fake._send_data.mock_calls[0].kwargs['data_to_send'], StatusReport)) self.assertEqual( self.fake._send_data.mock_calls[0].kwargs['data_to_send']. data['source']['server'], None)
def test_one_source_to_many_dests(self): # This tests that there can be one source that specifies # information for different destinations and that the correct mapping # is created. config_1 = combine_dicts(TestReadingConfigs.source_options_1, TestReadingConfigs.dest_options_1) # NOTE: virt-who today does not support config sections having the same # name. Hence the only way to have one source go to multiple # destinations (without new config options) is to have two sections # with the same information but different section names config_options_2 = TestReadingConfigs.source_options_1.copy() config_options_2['name'] = 'test2' config_2 = combine_dicts(config_options_2, TestReadingConfigs.dest_options_2) expected_dest_1 = Satellite6DestinationInfo( **TestReadingConfigs.dest_options_1) expected_dest_2 = Satellite6DestinationInfo( **TestReadingConfigs.dest_options_2) expected_mapping = { expected_dest_1: [config_1['name']], expected_dest_2: [config_2['name']] # config_2['name'] == # config_1['name'] } with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write( TestReadingConfigs.dict_to_ini(config_1) + TestReadingConfigs.dict_to_ini(config_2)) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(manager.dest_to_sources_map, expected_mapping)
def testLibvirtConfig(self): with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [test1] type=libvirt server=1.2.3.4 username=admin password=password owner=root env=staging """) manager = DestinationToSourceMapper( init_config({}, {}, config_dir=self.config_dir)) self.assertEqual(len(manager.configs), 1) config = manager.configs[0][1] self.assertEqual(config.name, "test1") self.assertEqual(config["type"], "libvirt") # The following server value is different than what is provided above as it has been # processed by the libvirt config section validation. # TODO decouple this from the libvirt config section (for testing only) self.assertEqual(config["server"], "qemu+ssh://[email protected]/system?no_tty=1") self.assertEqual(config["username"], "admin") self.assertEqual(config["password"], "password") self.assertEqual(config["owner"], "root") self.assertEqual(config["env"], "staging")
def test_sm_config_override(self, initConfig, HTTPSConnection, RhsmProxyHTTPSConnection): """Test if overriding options from rhsm.conf works.""" conn = MagicMock() conn.getresponse.return_value.status = 200 conn.getresponse.return_value.read.return_value = '{"result": "ok"}' HTTPSConnection.return_value = conn RhsmProxyHTTPSConnection.return_value = conn def config_get(section, key): return { 'server/proxy_hostname': 'proxy.server.test', 'rhsm/consumerCertDir': '', 'server/hostname': 'server.test', 'server/port': '8081', 'server/prefix': 'old_prefix', }.get('%s/%s' % (section, key), None) initConfig.return_value.get.side_effect = config_get config_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, config_dir) with open(os.path.join(config_dir, "test.conf"), "w") as f: f.write(""" [test] type=libvirt owner=owner env=env rhsm_hostname=host rhsm_port=8080 rhsm_prefix=/prefix rhsm_proxy_hostname= rhsm_proxy_port=8443 rhsm_insecure=1 rhsm_username=user rhsm_password=passwd """) conf = parse_file(os.path.join(config_dir, "test.conf")) effective_config = EffectiveConfig() conf_values = conf.pop("test") effective_config["test"] = VirtConfigSection.from_dict( conf_values, "test", effective_config) config_manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(config_manager.configs), 1) config = config_manager.configs[0] manager = Manager.fromOptions(self.logger, Mock(), config) self.assertTrue(isinstance(manager, SubscriptionManager)) self.assertEqual(config.rhsm_hostname, 'host') self.assertEqual(config.rhsm_port, '8080') manager._connect(config) self.assertFalse(RhsmProxyHTTPSConnection.called, "It shouldn't use proxy") self.assertTrue(HTTPSConnection.called) conn.request.assert_called_with('GET', '/prefix/status/', body=ANY, headers=ANY)
def testCLIConfigOverridesGeneralConfigFileButStillReadsItsGlobalAndDefaultsSections( self): cli_config_file_path = os.path.join(self.custom_config_dir, "my_file.conf") with open(cli_config_file_path, "w") as f: f.write(""" [valid_cli_section] server=5.5.5.5 username=admin1 password=password1 owner=owner1 env=env1 rhsm_hostname=abc1 """) cli_dict = {'configs': [cli_config_file_path]} # alter the main conf file constant temporarily: virtwho.config.VW_GENERAL_CONF_PATH = os.path.join( self.general_config_file_dir, "virt-who.conf") with open(virtwho.config.VW_GENERAL_CONF_PATH, "w") as f: f.write(""" [global] interval=100 log_file=rhsm45.log [defaults] hypervisor_id=hostname [valid_default_main_conf_file_section] server=1.2.3.4 username=admin password=password owner=owner env=env rhsm_hostname=abc """) config_manager = DestinationToSourceMapper( init_config({}, cli_dict, config_dir=self.config_dir)) # There should be only one config, and that should be the one passed from the cli self.assertEqual(len(config_manager.configs), 1) config = config_manager.configs[0][1] self.assertEqual(config.name, "valid_cli_section") self.assertEqual(config["server"], "5.5.5.5") self.assertEqual(config["username"], "admin1") self.assertEqual(config["password"], "password1") self.assertEqual(config["owner"], "owner1") self.assertEqual(config["env"], "env1") self.assertEqual(config["rhsm_hostname"], "abc1") # Also, check that the default section values from the VW_GENERAL_CONF_PATH file are still read # (and used when any of the keys are missing in the virt config) self.assertEqual(config["hypervisor_id"], "hostname") # Additionally, the global section from the VW_GENERAL_CONF_PATH file should be read in self.assertEqual(config_manager.effective_config["global"]["log_file"], "rhsm45.log") self.assertEqual(config_manager.effective_config["global"]["interval"], 100)
def test_sm_config_cmd(self): os.environ = {} sys.argv = ["virt-who", "--sam", "--libvirt"] logger, effective_config = parse_options() config_manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(config_manager.configs), 1) config = dict(config_manager.configs)[VW_ENV_CLI_SECTION_NAME] manager = Manager.from_config(self.logger, config) self.assertTrue(isinstance(manager, SubscriptionManager))
def test_invalid_config(self): with open(os.path.join(self.config_dir, "test.conf"), "w") as f: f.write(""" Malformed configuration file """) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) # If there is a config file but it is bad, then no config is returned self.assertEqual(len(manager.configs), 0)
def test_one_source_to_one_dest(self): config_1 = combine_dicts(TestReadingConfigs.source_options_1, TestReadingConfigs.dest_options_1) expected_dest_1 = Satellite6DestinationInfo( **TestReadingConfigs.dest_options_1) expected_mapping = {expected_dest_1: [config_1['name']]} with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(TestReadingConfigs.dict_to_ini(config_1)) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(manager.dest_to_sources_map, expected_mapping)
def test_invalid_config(self): with open(os.path.join(self.config_dir, "test.conf"), "w") as f: f.write(""" Malformed configuration file """) manager = DestinationToSourceMapper( init_config({}, {}, config_dir=self.config_dir)) # If there are only invalid configurations specified, and nothing has been specified via # the command line or ENV then we should use the default # TODO Remove the default hard-coded behaviour, and allow virt-who to output a # configuration that will cause it to behave equivalently self.assertEqual(len(manager.configs), 1) self.assertEqual(manager.configs[0][0], VW_ENV_CLI_SECTION_NAME)
def __init__(self, logger, options): """ Executor class provides bridge between virtualization supervisor and Subscription Manager. logger - logger instance options - options for virt-who, parsed from command line arguments """ self.logger = logger self.options = options self.terminate_event = Event() self.virts = [] self.destinations = [] # Queue for getting events from virt backends self.datastore = Datastore() self.reloading = False self.dest_to_source_mapper = DestinationToSourceMapper(options) for name, config in self.dest_to_source_mapper.configs: logger.info("Using config named '%s'" % name)
def testMissingOwnerOption(self): with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [test1] type=esx server=1.2.3.4 username=admin password=password rhsm_hostname=abc """) # Instantiating the DestinationToSourceMapper with an invalid config should not fail # instead we expect that the list of configs managed by the DestinationToSourceMapper does not # include the invalid one config_manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) # There should be no configs parsed successfully, therefore the list of configs should # be empty self.assertEqual(len(config_manager.configs), 0) def testEmptySectionName(self): with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [] type=esx server=1.2.3.4 username=admin password=password rhsm_hostname=abc """) # Instantiating the DestinationToSourceMapper with an invalid config should not fail # instead we expect that the list of configs managed by the DestinationToSourceMapper does not # include the invalid one config_manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) # There should be no configs parsed successfully, therefore the list of configs should # be empty self.assertEqual(len(config_manager.configs), 0)
def testNoOptionsConfig(self): with open(os.path.join(self.config_dir, "test.conf"), "w") as f: f.write(""" [test] type=esx """) # Instantiating the DestinationToSourceMapper with an invalid config should not fail # instead we expect that the list of configs managed by the DestinationToSourceMapper does not # include the invalid one config_manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) # There should be no configs parsed successfully, therefore the list of configs should # be empty self.assertEqual(len(config_manager.configs), 0)
def testFilterHostNew(self): with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [test1] type=esx server=1.2.3.4 username=admin password=password owner=root filter_hosts=12345 """) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(len(manager.configs), 1) self.assertEqual(manager.configs[0][1]["filter_hosts"], ['12345'])
def testInvisibleConfigFile(self): with open(os.path.join(self.config_dir, ".test1.conf"), "w") as f: f.write(""" [test1] type=libvirt server=1.2.3.4 username=admin password=password owner=root """) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertTrue( "test1" not in [name for (name, config) in manager.configs], "Hidden config file shouldn't be read")
def test_satellite_config_cmd(self): os.environ = {} sys.argv = ["virt-who", "--satellite", "--satellite-server=sat.example.com", "--satellite-username=username", "--satellite-password=password", "--libvirt"] logger, effective_config = parse_options() config_manager = DestinationToSourceMapper(effective_config) # Again there should only be one config parsed out (and one dest) self.assertEqual(len(config_manager.configs), 1) self.assertEqual(len(config_manager.dests), 1) dest_info = config_manager.dests.pop() self.assertTrue(isinstance(dest_info, Satellite5DestinationInfo)) manager = Manager.fromInfo(self.logger, effective_config, dest_info) self.assertTrue(isinstance(manager, Satellite))
def test_unreadable_config(self): filename = os.path.join(self.config_dir, "test.conf") with open(filename, "w") as f: f.write(""" [test] type=esx server=1.2.3.4 username=admin password=password owner=root """) os.chmod(filename, 0) manager = DestinationToSourceMapper( init_config({}, {}, config_dir=self.config_dir)) # There should be at least one 'env/cmdline' section self.assertEqual(len(manager.configs), 1)
def test_unreadable_config(self): filename = os.path.join(self.config_dir, "test.conf") with open(filename, "w") as f: f.write(""" [test] type=esx server=1.2.3.4 username=admin password=password owner=root """) os.chmod(filename, 0) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) # If there is a config file but it is bad, then no config is returned self.assertEqual(len(manager.configs), 0)
def testEsxDisableSimplifiedVim(self): with open(os.path.join(self.config_dir, "test1.conf"), "w") as f: f.write(""" [test1] type=esx server=1.2.3.4 username=admin password=password owner=root simplified_vim=false """) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(len(manager.configs), 1) _, config = manager.configs[0] self.assertFalse(config['simplified_vim'])
def test_config_duplicate_keys(self): filename = os.path.join(self.config_dir, "test.conf") with open(filename, "w") as f: f.write(""" [test] type=esx server=1.2.3.4 username=admin password=password owner=root owner=tester """) manager = DestinationToSourceMapper( init_config({}, config_dir=self.config_dir)) self.assertEqual(len(manager.configs), 1) self.assertEqual(manager.configs[0][1]['owner'], 'tester')
def filter_hosts(self, filter_something, filter_type=''): config_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, config_dir) with open(os.path.join(config_dir, "test.conf"), "w") as f: f.write(""" [test] type=esx server=does.not.exist username=username password=password owner=owner env=env {filter_something} {filter_type} """.format(filter_something=filter_something, filter_type=filter_type)) conf = parse_file(os.path.join(config_dir, "test.conf")) test_conf_values = conf.pop('test') effective_config = EffectiveConfig() effective_config['test'] = VirtConfigSection.from_dict( test_conf_values, 'test', effective_config) effective_config.validate() config_manager = DestinationToSourceMapper(effective_config) self.assertEqual(len(config_manager.configs), 1) config = config_manager.configs[0][1] included_hypervisor = Hypervisor('12345', guestIds=[ Guest('guest-2', xvirt.CONFIG_TYPE, Guest.STATE_RUNNING), ]) excluded_hypervisor = Hypervisor('00000', guestIds=[ Guest('guest-1', xvirt.CONFIG_TYPE, Guest.STATE_RUNNING), ]) assoc = { 'hypervisors': [ excluded_hypervisor, included_hypervisor, ] } report = HostGuestAssociationReport(config, assoc) assert report.association == {'hypervisors': [included_hypervisor]}
def test_read_hypervisor_from_non_hypervisor(self): with open(self.hypervisor_file, "w") as f: f.write(NON_HYPERVISOR_JSON) with open(self.config_file, "w") as f: f.write(""" [test] type=fake is_hypervisor=true owner=covfefe file=%s """ % self.hypervisor_file) effective_config = init_config({}, config_dir=self.config_dir) DestinationToSourceMapper(effective_config) # The 'test' section is not valid here (as the json provided will not work with # the is_hypervisor value set to true) self.assertNotIn('test', effective_config)
def test_sm_config_file(self): config_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, config_dir) with open(os.path.join(config_dir, "test.conf"), "w") as f: f.write(""" [test] type=libvirt owner=owner env=env rhsm_hostname=host rhsm_port=8080 rhsm_prefix=prefix rhsm_proxy_hostname=proxy_host rhsm_proxy_port=9090 rhsm_proxy_user=proxy_user rhsm_proxy_password=proxy_password rhsm_insecure=1 rhsm_username=user rhsm_password=passwd rhsm_no_proxy=filter """) config_manager = DestinationToSourceMapper( init_config({}, {}, config_dir=config_dir)) self.assertEqual(len(config_manager.configs), 1) config = dict(config_manager.configs)["test"] manager = Manager.from_config(self.logger, config) self.assertTrue(isinstance(manager, SubscriptionManager)) self.assertEqual(config['rhsm_hostname'], 'host') self.assertEqual(config['rhsm_port'], '8080') manager._connect(config) self.sm.connection.assert_called_with( username='******', password='******', host='host', ssl_port=8080, handler='prefix', proxy_hostname='proxy_host', proxy_port='9090', proxy_user='******', proxy_password='******', no_proxy='filter', insecure='1', correlation_id=manager.correlation_id)
def test_satellite_config_env(self): os.environ = { "VIRTWHO_SATELLITE": '1', "VIRTWHO_SATELLITE_SERVER": 'sat.example.com', "VIRTWHO_SATELLITE_USERNAME": '******', "VIRTWHO_SATELLITE_PASSWORD": '******', "VIRTWHO_LIBVIRT": '1' } sys.argv = ["virt-who"] logger, effective_config = parse_options() config_manager = DestinationToSourceMapper(effective_config) # Again there should only be one config parsed out (and one dest) self.assertEqual(len(config_manager.configs), 1) self.assertEqual(len(config_manager.dests), 1) dest_info = config_manager.dests.pop() self.assertTrue(isinstance(dest_info, Satellite5DestinationInfo)) manager = Manager.fromInfo(self.logger, effective_config, dest_info) self.assertTrue(isinstance(manager, Satellite))
def __init__(self, logger, options): """ Executor class provides bridge between virtualization supervisor and Subscription Manager. logger - logger instance options - options for virt-who, parsed from command line arguments """ self.logger = logger self.options = options self.terminate_event = Event() self.virts = [] self.destinations = [] # Queue for getting events from virt backends self.datastore = Datastore() self.reloading = False self.dest_to_source_mapper = DestinationToSourceMapper(options) for name, config in self.dest_to_source_mapper.configs: logger.info("Using config named '%s'" % name)
def test_per_config_options_encrypted(self, can_write): options = Mock() options.force_register = True can_write.return_value = True with tempfile.NamedTemporaryFile() as tmp: password.Password.KEYFILE = tmp.name config_dict = { "sat_server": "http://localhost:%s" % TEST_PORT, "sat_username": "******", "sat_encrypted_password": hexlify(password.Password.encrypt('password')), "type": "libvirt", } config = VirtConfigSection.from_dict(config_dict, 'test', None) config.validate() dests = DestinationToSourceMapper.parse_dests_from_dict(config._values) self.assertEqual(len(dests), 1) dest_info = dests.pop() s = Manager.fromInfo(self.logger, options, dest_info) self.assertTrue(isinstance(s, Satellite)) report = HostGuestAssociationReport(config, self.mapping) result = s.hypervisorCheckIn(report, options) self.assertTrue("failedUpdate" in result) self.assertTrue("created" in result) self.assertTrue("updated" in result)
class Executor(object): def __init__(self, logger, options): """ Executor class provides bridge between virtualization supervisor and Subscription Manager. logger - logger instance options - options for virt-who, parsed from command line arguments """ self.logger = logger self.options = options self.terminate_event = Event() self.virts = [] self.destinations = [] # Queue for getting events from virt backends self.datastore = Datastore() self.reloading = False self.dest_to_source_mapper = DestinationToSourceMapper(options) for name, config in self.dest_to_source_mapper.configs: logger.info("Using config named '%s'" % name) def _create_virt_backends(self): """ Create virts list with virt backend threads """ virts = [] for name, config in self.dest_to_source_mapper.configs: try: virt = Virt.from_config(self.logger, config, self.datastore, terminate_event=self.terminate_event, interval=self.options[VW_GLOBAL]['interval'], oneshot=self.options[VW_GLOBAL]['oneshot']) except Exception as e: self.logger.error('Unable to use configuration "%s": %s', name, str(e)) continue virts.append(virt) return virts def _create_destinations(self): """Populate self.destinations with a list of list with them @param reset: Whether to kill existing destinations or not, defaults to false @type: bool """ dests = [] for info in self.dest_to_source_mapper.dests: # Dests should already include all destinations we want created # at this time. This method will make no assumptions of creating # defaults of any kind. source_keys = self.dest_to_source_mapper.dest_to_sources_map[info] info.name = "destination_%s" % hash(info) logger = log.getLogger(name=info.name) manager = Manager.fromInfo(logger, self.options, info) dest_class = info_to_destination_class[type(info)] dest = dest_class(config=info, logger=logger, source_keys=source_keys, options=self.options, source=self.datastore, dest=manager, terminate_event=self.terminate_event, interval=self.options[VW_GLOBAL]['interval'], oneshot=self.options[VW_GLOBAL]['oneshot']) dests.append(dest) return dests @staticmethod def wait_on_threads(threads, max_wait_time=None, kill_on_timeout=False): """ Wait for each of the threads in the list to be terminated @param threads: A list of IntervalThread objects to wait on @type threads: list @param max_wait_time: An optional max amount of seconds to wait @type max_wait_time: int @param kill_on_timeout: An optional arg that, if truthy and max_wait_time is defined and exceeded, cause this method to attempt to terminate and join the threads given it. @type kill_on_timeout: bool @return: A list of threads that have not quit yet. Without a max_wait_time this list is always empty (or we are stuck waiting). With a max_wait_time this list will include those threads that have not quit yet. @rtype: list """ delta_time = 1.0 total_waited = 0 threads_not_terminated = list(threads) while len(threads_not_terminated) > 0: if max_wait_time is not None and total_waited > max_wait_time: if kill_on_timeout: Executor.terminate_threads(threads_not_terminated) return [] return threads_not_terminated for thread in threads_not_terminated: if thread.is_terminated(): threads_not_terminated.remove(thread) if not threads_not_terminated: break time.sleep(delta_time) if max_wait_time is not None: total_waited += 1 * 1.0/delta_time return threads_not_terminated @staticmethod def terminate_threads(threads): for thread in threads: thread.stop() if thread.ident: thread.join() def run_oneshot(self): # Start all sources self.virts = self._create_virt_backends() if len(self.virts) == 0: err = "virt-who can't be started: no suitable virt backend found" self.logger.error(err) raise ExitRequest(code=1, message=err) self.destinations = self._create_destinations() if len(self.destinations) == 0: err = "virt-who can't be started: no suitable destinations found" self.logger.error(err) raise ExitRequest(code=1, message=err) for thread in self.virts: thread.start() Executor.wait_on_threads(self.virts) if self.options[VW_GLOBAL]['print']: to_print = {} for source in self.dest_to_source_mapper.sources: try: report = self.datastore.get(source) config = report.config to_print[config.name] = report except KeyError: self.logger.info('Unable to retrieve report for source ' '\"%s\" for printing' % source) return to_print for thread in self.destinations: thread.start() Executor.wait_on_threads(self.destinations) def run(self): self.logger.debug("Starting infinite loop with %d seconds interval", self.options[VW_GLOBAL]['interval']) # Need to update the dest to source mapping of the dest_to_source_mapper object # here because of the way that main reads the config from the command # line # TODO: Update dests to source map on addition or removal of configs self.dest_to_source_mapper.update_dest_to_source_map() # Start all sources self.virts = self._create_virt_backends() if len(self.virts) == 0: err = "virt-who can't be started: no suitable virt backend found" self.logger.error(err) raise ExitRequest(code=1, message=err) self.destinations = self._create_destinations() if len(self.destinations) == 0: err = "virt-who can't be started: no suitable destinations found" self.logger.error(err) raise ExitRequest(code=1, message=err) for thread in self.virts: thread.start() for thread in self.destinations: thread.start() # Interruptibly wait on the other threads to be terminated self.wait_on_threads(self.destinations) raise ExitRequest(code=0) def stop_threads(self): self.terminate_event.set() self.terminate_threads(self.virts) self.terminate_threads(self.destinations) def terminate(self): self.logger.debug("virt-who is shutting down") self.stop_threads() self.virts = [] self.destinations = [] self.datastore = None def reload(self): """ Causes all threads to be terminated in preparation for running again """ self.stop_threads() self.terminate_event.clear() self.datastore = Datastore()