def hypervisorHeartbeat(self, config, options=None): """ Send heart beat to candlepin server :param config: reference on configuration :param options: other options """ if options: named_options = NamedOptions() for key, value in options['global'].items(): setattr(named_options, key, value) else: named_options = None try: connection = self._connect(config) result = connection.hypervisorHeartbeat(config['owner'], named_options) except BadStatusLine: raise ManagerError("Communication with subscription manager interrupted") except rhsm_connection.RateLimitExceededException as e: raise ManagerThrottleError(e.retry_after) except rhsm_connection.GoneException: raise ManagerError("Communication with subscription manager failed: consumer no longer exists") except rhsm_connection.ConnectionException as e: if hasattr(e, 'code'): raise ManagerError("Communication with subscription manager failed with code %d: %s" % (e.code, str(e))) raise ManagerError("Communication with subscription manager failed: %s" % str(e)) return result
def hypervisorCheckIn(self, report, options=None): """ Send hosts to guests mapping to subscription manager. """ connection = self._connect(report.config) is_async = self._is_rhsm_server_async(report, connection) serialized_mapping = self._hypervisor_mapping(report, is_async, connection) self.logger.debug( "Host-to-guest mapping being sent to '{owner}': {mapping}".format( owner=report.config['owner'], mapping=json.dumps(serialized_mapping, indent=4))) # All subclasses of ConfigSection use dictionary like notation, # but RHSM uses attribute like notation if options: named_options = NamedOptions() for key, value in options['global'].items(): setattr(named_options, key, value) else: named_options = None try: try: result = self.connection.hypervisorCheckIn( report.config['owner'], report.config['env'], serialized_mapping, options=named_options) # pylint:disable=unexpected-keyword-arg except TypeError: # This is temporary workaround until the options parameter gets implemented # in python-rhsm self.logger.debug( "hypervisorCheckIn method in python-rhsm doesn't understand options parameter, ignoring" ) result = self.connection.hypervisorCheckIn( report.config['owner'], report.config['env'], serialized_mapping) except BadStatusLine: raise ManagerError( "Communication with subscription manager interrupted") except rhsm_connection.RateLimitExceededException as e: raise ManagerThrottleError(e.retry_after) except rhsm_connection.GoneException: raise ManagerError( "Communication with subscription manager failed: consumer no longer exists" ) except rhsm_connection.ConnectionException as e: if hasattr(e, 'code'): raise ManagerError( "Communication with subscription manager failed with code %d: %s" % (e.code, str(e))) raise ManagerError( "Communication with subscription manager failed: %s" % str(e)) if is_async is True: report.state = AbstractVirtReport.STATE_PROCESSING report.job_id = result['id'] else: report.state = AbstractVirtReport.STATE_FINISHED return result
def check_report_state(self, report): # BZ 1554228 job_id = str(report.job_id) self._connect(report.config) self.logger.debug('Checking status of job %s', job_id) try: result = self.connection.getJob(job_id) except BadStatusLine: raise ManagerError("Communication with subscription manager interrupted") except rhsm_connection.RateLimitExceededException as e: raise ManagerThrottleError(e.retry_after) except rhsm_connection.ConnectionException as e: if hasattr(e, 'code'): raise ManagerError("Communication with subscription manager failed with code %d: %s" % (e.code, str(e))) raise ManagerError("Communication with subscription manager failed: %s" % str(e)) state = STATE_MAPPING.get(result['state'], AbstractVirtReport.STATE_FAILED) report.state = state if state not in (AbstractVirtReport.STATE_FINISHED, AbstractVirtReport.STATE_CANCELED, AbstractVirtReport.STATE_FAILED): self.logger.debug('Job %s not finished', job_id) else: # log completed job status result_data = result.get('resultData', {}) if not result_data: self.logger.warning("Job status report without resultData: %s", result) return if isinstance(result_data, string_types): self.logger.warning("Job status report encountered the following error: %s", result_data) return for fail in result_data.get('failedUpdate', []): self.logger.error("Error during update list of guests: %s", str(fail)) self.logger.debug("Number of mappings unchanged: %d", len(result_data.get('unchanged', []))) self.logger.info("Mapping for config \"%s\" updated", report.config.name)
def sendVirtGuests(self, report, options=None): """ Update consumer facts with info about virtual guests. `guests` is a list of `Guest` instances (or it children). """ guests = report.guests self._connect(report.config) # Sort the list guests.sort(key=lambda item: item.uuid) serialized_guests = [guest.toDict() for guest in guests] self.logger.info('Sending update in guests lists for config ' '"%s": %d guests found', report.config.name, len(guests)) self.logger.debug("Domain info: %s", json.dumps(serialized_guests, indent=4)) # Send list of guest uuids to the server try: self.connection.updateConsumer(self.uuid(), guest_uuids=serialized_guests, hypervisor_id=report.hypervisor_id) except rhsm_connection.GoneException: raise ManagerError("Communication with subscription manager failed: consumer no longer exists") except rhsm_connection.RateLimitExceededException as e: raise ManagerThrottleError(e.retry_after) report.state = AbstractVirtReport.STATE_FINISHED
def check_report_state(self, report): job_id = report.job_id self._connect(report.config) self.logger.debug('Checking status of job %s', job_id) try: result = self.connection.getJob(job_id) except BadStatusLine: raise ManagerError( "Communication with subscription manager interrupted") except rhsm_connection.ConnectionException as e: if hasattr(e, 'code'): raise ManagerError( "Communication with subscription manager failed with code %d: %s" % (e.code, str(e))) raise ManagerError( "Communication with subscription manager failed: %s" % str(e)) state = STATE_MAPPING.get(result['state'], AbstractVirtReport.STATE_FAILED) report.state = state if state not in (AbstractVirtReport.STATE_FINISHED, AbstractVirtReport.STATE_CANCELED, AbstractVirtReport.STATE_FAILED): self.logger.debug('Job %s not finished', job_id) else: # log completed job status resultData = result.get('resultData', {}) if not resultData: self.logger.warning("Job status report without resultData: %s", result) return for fail in resultData.get('failedUpdate', []): self.logger.error("Error during update list of guests: %s", str(fail)) for updated in resultData.get('updated', []): guests = [x['guestId'] for x in updated['guestIds']] self.logger.debug("Updated host %s with guests: [%s]", updated['uuid'], ", ".join(guests)) for created in resultData.get('created', []): guests = [x['guestId'] for x in created['guestIds']] self.logger.debug("Created host: %s with guests: [%s]", created['uuid'], ", ".join(guests)) self.logger.debug("Number of mappings unchanged: %d", len(resultData.get('unchanged', []))) self.logger.info("Mapping for config \"%s\" updated", report.config.name)
def _check_owner_lib(self, kwargs, config): """ Try to check values of env and owner. These values has to be equal to values obtained from Satellite server. :param kwargs: dictionary possibly containing valid username and password used for connection to rhsm :param config: Configuration of virt-who :return: None """ if config is None: return # Check 'owner' and 'env' only in situation, when these values # are set and rhsm_username and rhsm_password are not set if 'username' not in kwargs and 'password' not in kwargs and \ 'owner' in config.keys() and 'env' in config.keys(): pass else: return uuid = self.uuid() consumer = self.connection.getConsumer(uuid) if 'environment' in consumer: environment = consumer['environment'] else: return if environment: environment_name = environment['name'] owner = self.connection.getOwner(uuid) owner_id = owner['key'] if config['owner'] != owner_id: raise ManagerError( "Cannot send data to: %s, because owner from configuration: %s is different" % (owner_id, config['owner']) ) if config['env'] != environment_name: raise ManagerError( "Cannot send data to: %s, because Satellite env: %s differs from configuration: %s" % (owner_id, environment_name, config['env']) )
def test_send_check_status_heartbeat_call_failure(self): # This tests that reports of the right type are batched into one # and that the hypervisorCheckIn method of the destination is called # with the right parameters config1, d1 = self.create_fake_config('source1', **self.default_config_args) config2, d2 = self.create_fake_config('source2', **self.default_config_args) virt1 = Mock() virt1.CONFIG_TYPE = 'esx' virt2 = Mock() virt2.CONFIG_TYPE = 'esx' report1 = StatusReport(config1) report2 = StatusReport(config2) data_to_send = {'source1': report1, 'source2': report2} source_keys = ['source1', 'source2'] report1 = Mock() report2 = Mock() report1.hash = "report1_hash" report2.hash = "report2_hash" datastore = {'source1': report1, 'source2': report2} manager = Mock() options = Mock() options.print_ = False manager.hypervisorHeartbeat = Mock( side_effect=ManagerError("cannot connect to destination")) manager.hypervisorCheckIn = Mock() logger = Mock() config, d = self.create_fake_config('test', **self.default_config_args) config.owner = 'test_owner' terminate_event = Mock() interval = 10 # Arbitrary for this test destination_thread = DestinationThread(logger, config, source_keys=source_keys, source=datastore, dest=manager, interval=interval, terminate_event=terminate_event, oneshot=True, status=True, options=self.options) destination_thread._send_data(data_to_send) for source_key, report in data_to_send.items(): self.assertEqual( report.data['destination']['message'], "Error during status connection: cannot connect to destination." )
def _connect(self, config=None): """ Connect to the subscription-manager. """ kwargs = { 'host': self.rhsm_config.get('server', 'hostname'), 'ssl_port': int(self.rhsm_config.get('server', 'port')), 'handler': self.rhsm_config.get('server', 'prefix'), 'proxy_hostname': self.rhsm_config.get('server', 'proxy_hostname'), 'proxy_port': self.rhsm_config.get('server', 'proxy_port'), 'proxy_user': self.rhsm_config.get('server', 'proxy_user'), 'proxy_password': self.rhsm_config.get('server', 'proxy_password'), 'no_proxy': self.rhsm_config.get('server', 'no_proxy'), 'insecure': self.rhsm_config.get('server', 'insecure') } kwargs_to_config = { 'host': 'rhsm_hostname', 'ssl_port': 'rhsm_port', 'handler': 'rhsm_prefix', 'proxy_hostname': 'rhsm_proxy_hostname', 'proxy_port': 'rhsm_proxy_port', 'proxy_user': '******', 'proxy_password': '******', 'no_proxy': 'rhsm_no_proxy', 'insecure': 'rhsm_insecure' } rhsm_username = None rhsm_password = None if config: try: rhsm_username = config['rhsm_username'] rhsm_password = config['rhsm_password'] except KeyError: pass if rhsm_username == NotSetSentinel: rhsm_username = None if rhsm_password == NotSetSentinel: rhsm_password = None # Testing for None is necessary, it might be an empty string for key, value in kwargs.items(): try: from_config = config[kwargs_to_config[key]] if from_config != NotSetSentinel and from_config is \ not None: if key == 'ssl_port': from_config = int(from_config) kwargs[key] = from_config except KeyError: continue if rhsm_username and rhsm_password: self.logger.debug("Authenticating with RHSM username %s", rhsm_username) kwargs['username'] = rhsm_username kwargs['password'] = rhsm_password else: self.logger.debug("Authenticating with certificate: %s", self.cert_file) if not os.access(self.cert_file, os.R_OK): raise SubscriptionManagerUnregisteredError( "Unable to read certificate, system is not registered or you are not root") kwargs['cert_file'] = self.cert_file kwargs['key_file'] = self.key_file self.logger.info("X-Correlation-ID: %s", self.correlation_id) if self.correlation_id: kwargs['correlation_id'] = self.correlation_id self.connection = rhsm_connection.UEPConnection(**kwargs) # add version to user_agent header on connection BZ 1844506 self.connection.conn.user_agent += " " + parser.get_version().replace(" ", "/") try: if not self.connection.ping()['result']: raise SubscriptionManagerError( "Unable to obtain status from server, UEPConnection is likely not usable." ) except rhsm_connection.RateLimitExceededException as e: raise ManagerThrottleError(e.retry_after) except BadStatusLine: raise ManagerError("Communication with subscription manager interrupted") return self.connection
def _connect(self, config=None): """ Connect to the subscription-manager. """ kwargs = { 'host': self.rhsm_config.get('server', 'hostname'), 'ssl_port': int(self.rhsm_config.get('server', 'port')), 'handler': self.rhsm_config.get('server', 'prefix'), 'proxy_hostname': self.rhsm_config.get('server', 'proxy_hostname'), 'proxy_port': self.rhsm_config.get('server', 'proxy_port'), 'proxy_user': self.rhsm_config.get('server', 'proxy_user'), 'proxy_password': self.rhsm_config.get('server', 'proxy_password'), 'insecure': self.rhsm_config.get('server', 'insecure') } rhsm_username = None rhsm_password = None if config: rhsm_username = config.rhsm_username rhsm_password = config.rhsm_password # Testing for None is necessary, it might be an empty string if config.rhsm_hostname is not None: kwargs['host'] = config.rhsm_hostname if config.rhsm_port is not None: kwargs['ssl_port'] = int(config.rhsm_port) if config.rhsm_prefix is not None: kwargs['handler'] = config.rhsm_prefix if config.rhsm_proxy_hostname is not None: kwargs['proxy_hostname'] = config.rhsm_proxy_hostname if config.rhsm_proxy_port is not None: kwargs['proxy_port'] = config.rhsm_proxy_port if config.rhsm_proxy_user is not None: kwargs['proxy_user'] = config.rhsm_proxy_user if config.rhsm_proxy_password is not None: kwargs['proxy_password'] = config.rhsm_proxy_password if config.rhsm_insecure is not None: kwargs['insecure'] = config.rhsm_insecure if rhsm_username and rhsm_password: self.logger.debug("Authenticating with RHSM username %s", rhsm_username) kwargs['username'] = rhsm_username kwargs['password'] = rhsm_password else: self.logger.debug("Authenticating with certificate: %s", self.cert_file) if not os.access(self.cert_file, os.R_OK): raise SubscriptionManagerUnregisteredError( "Unable to read certificate, system is not registered or you are not root" ) kwargs['cert_file'] = self.cert_file kwargs['key_file'] = self.key_file self.connection = rhsm_connection.UEPConnection(**kwargs) try: if not self.connection.ping()['result']: raise SubscriptionManagerError( "Unable to obtain status from server, UEPConnection is likely not usable." ) except BadStatusLine: raise ManagerError( "Communication with subscription manager interrupted")
def hypervisorCheckIn(self, report, options=None): """ Send hosts to guests mapping to subscription manager. """ mapping = report.association serialized_mapping = {} self._connect(report.config) self.logger.debug( "Checking if server has capability 'hypervisor_async'") is_async = hasattr( self.connection, 'has_capability' ) and self.connection.has_capability('hypervisors_async') if is_async and os.environ.get('VIRTWHO_DISABLE_ASYNC', '').lower() in ['1', 'yes', 'true']: self.logger.info( "Async reports are supported but explicitly disabled") is_async = False if is_async: self.logger.debug("Server has capability 'hypervisors_async'") # Transform the mapping into the async version serialized_mapping = { 'hypervisors': [h.toDict() for h in mapping['hypervisors']] } else: self.logger.debug( "Server does not have 'hypervisors_async' capability") # Reformat the data from the mapping to make it fit with # the old api. for hypervisor in mapping['hypervisors']: guests = [g.toDict() for g in hypervisor.guestIds] serialized_mapping[hypervisor.hypervisorId] = guests hypervisor_count = len(mapping['hypervisors']) guest_count = sum( len(hypervisor.guestIds) for hypervisor in mapping['hypervisors']) self.logger.info( 'Sending update in hosts-to-guests mapping for config ' '"%s": %d hypervisors and %d guests found', report.config.name, hypervisor_count, guest_count) self.logger.debug("Host-to-guest mapping: %s", json.dumps(serialized_mapping, indent=4)) try: try: result = self.connection.hypervisorCheckIn(report.config.owner, report.config.env, serialized_mapping, options=options) # pylint:disable=unexpected-keyword-arg except TypeError: # This is temporary workaround until the options parameter gets implemented # in python-rhsm self.logger.debug( "hypervisorCheckIn method in python-rhsm doesn't understand options parameter, ignoring" ) result = self.connection.hypervisorCheckIn( report.config.owner, report.config.env, serialized_mapping) except BadStatusLine: raise ManagerError( "Communication with subscription manager interrupted") except rhsm_connection.RateLimitExceededException as e: retry_after = int( getattr(e, 'headers', {}).get('Retry-After', '60')) raise ManagerThrottleError(retry_after) except rhsm_connection.GoneException: raise ManagerError( "Communication with subscription manager failed: consumer no longer exists" ) except rhsm_connection.ConnectionException as e: if hasattr(e, 'code'): raise ManagerError( "Communication with subscription manager failed with code %d: %s" % (e.code, str(e))) raise ManagerError( "Communication with subscription manager failed: %s" % str(e)) if is_async is True: report.state = AbstractVirtReport.STATE_PROCESSING report.job_id = result['id'] else: report.state = AbstractVirtReport.STATE_FINISHED return result
def _connect(self, config=None): """ Connect to the subscription-manager. """ kwargs = { 'host': self.rhsm_config.get('server', 'hostname'), 'ssl_port': int(self.rhsm_config.get('server', 'port')), 'handler': self.rhsm_config.get('server', 'prefix'), 'proxy_hostname': self.rhsm_config.get('server', 'proxy_hostname'), 'proxy_port': self.rhsm_config.get('server', 'proxy_port'), 'proxy_user': self.rhsm_config.get('server', 'proxy_user'), 'proxy_password': self.rhsm_config.get('server', 'proxy_password'), 'insecure': self.rhsm_config.get('server', 'insecure') } kwargs_to_config = { 'host': 'rhsm_hostname', 'ssl_port': 'rhsm_port', 'handler': 'rhsm_prefix', 'proxy_hostname': 'rhsm_proxy_hostname', 'proxy_port': 'rhsm_proxy_port', 'proxy_user': '******', 'proxy_password': '******', 'insecure': 'rhsm_insecure' } rhsm_username = None rhsm_password = None if config: try: rhsm_username = config['rhsm_username'] rhsm_password = config['rhsm_password'] except KeyError: pass if rhsm_username == NotSetSentinel: rhsm_username = None if rhsm_password == NotSetSentinel: rhsm_password = None # Testing for None is necessary, it might be an empty string for key, value in kwargs.iteritems(): try: from_config = config[kwargs_to_config[key]] if from_config is not NotSetSentinel and from_config is \ not None: if key is 'ssl_port': from_config = int(from_config) kwargs[key] = from_config except KeyError: continue if rhsm_username and rhsm_password: self.logger.debug("Authenticating with RHSM username %s", rhsm_username) kwargs['username'] = rhsm_username kwargs['password'] = rhsm_password else: self.logger.debug("Authenticating with certificate: %s", self.cert_file) if not os.access(self.cert_file, os.R_OK): raise SubscriptionManagerUnregisteredError( "Unable to read certificate, system is not registered or you are not root" ) kwargs['cert_file'] = self.cert_file kwargs['key_file'] = self.key_file self.connection = rhsm_connection.UEPConnection(**kwargs) try: if not self.connection.ping()['result']: raise SubscriptionManagerError( "Unable to obtain status from server, UEPConnection is likely not usable." ) except BadStatusLine: raise ManagerError( "Communication with subscription manager interrupted")