Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
    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_CREATED
            report.job_id = result['id']
        else:
            report.state = AbstractVirtReport.STATE_FINISHED
        return result
Exemple #4
0
    def test_send_data_poll_async_429(self):
        # This test's that when a 429 is detected during async polling
        # we wait for the amount of time specified
        source_keys = ['source1', 'source2']
        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'

        guest1 = Guest('GUUID1', virt1.CONFIG_TYPE, Guest.STATE_RUNNING)
        guest2 = Guest('GUUID2', virt2.CONFIG_TYPE, Guest.STATE_RUNNING)
        assoc1 = {'hypervisors': [Hypervisor('hypervisor_id_1', [guest1])]}
        assoc2 = {'hypervisors': [Hypervisor('hypervisor_id_2', [guest2])]}
        report1 = HostGuestAssociationReport(config1, assoc1)
        report2 = HostGuestAssociationReport(config2, assoc2)

        datastore = {'source1': report1, 'source2': report2}
        data_to_send = {'source1': report1, 'source2': report2}
        config, d = self.create_fake_config('test', **self.default_config_args)
        error_to_throw = ManagerThrottleError(retry_after=62)

        manager = Mock()
        manager.hypervisorCheckIn = Mock(side_effect=[error_to_throw, report1])
        expected_wait_calls = [call(wait_time=error_to_throw.retry_after)]

        logger = Mock()
        terminate_event = Mock()
        interval = 10  # Arbitrary for this test
        options = Mock()
        options.print_ = False
        destination_thread = DestinationThread(logger,
                                               config,
                                               source_keys=source_keys,
                                               source=datastore,
                                               dest=manager,
                                               interval=interval,
                                               terminate_event=terminate_event,
                                               oneshot=False,
                                               options=self.options)
        destination_thread.wait = Mock()
        destination_thread.is_terminated = Mock(return_value=False)
        destination_thread.record_status = Mock()
        destination_thread._send_data(data_to_send)
        destination_thread.wait.assert_has_calls(expected_wait_calls)
Exemple #5
0
    def test_send_data_429_during_send_virt_guests(self):
        # Show that when a 429 is encountered during the sending of a
        # DomainListReport that we retry after waiting the appropriate
        # amount of time
        source_keys = ['source1']
        config1 = Config('source1', 'esx')
        virt1 = Mock()
        virt1.CONFIG_TYPE = 'esx'

        guest1 = Guest('GUUID1', virt1, Guest.STATE_RUNNING)
        report1 = DomainListReport(config1, [guest1],
                                   hypervisor_id='hypervisor_id_1')

        datastore = {'source1': report1}
        data_to_send = {'source1': report1}

        config = Mock()
        config.polling_interval = 10
        logger = Mock()

        error_to_throw = ManagerThrottleError(retry_after=21)

        manager = Mock()
        manager.sendVirtGuests = Mock(side_effect=[error_to_throw, report1])
        terminate_event = Mock()
        interval = 10
        options = Mock()
        options.print_ = False
        destination_thread = DestinationThread(logger,
                                               config,
                                               source_keys=source_keys,
                                               source=datastore,
                                               dest=manager,
                                               interval=interval,
                                               terminate_event=terminate_event,
                                               oneshot=True,
                                               options=options)
        destination_thread.wait = Mock()
        destination_thread._send_data(data_to_send)
        manager.sendVirtGuests.assert_has_calls([
            call(report1, options=destination_thread.options),
            call(report1, options=destination_thread.options)
        ])
        destination_thread.wait.assert_has_calls(
            [call(wait_time=error_to_throw.retry_after)])
 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)
Exemple #7
0
    def test_send_data_429_during_send_virt_guests(self):
        # Show that when a 429 is encountered during the sending of a
        # DomainListReport that we retry after waiting the appropriate
        # amount of time
        config, d = self.create_fake_config('test', **self.default_config_args)
        source_keys = ['source1']
        virt1 = Mock()
        virt1.CONFIG_TYPE = 'esx'

        guest1 = Guest('GUUID1', virt1.CONFIG_TYPE, Guest.STATE_RUNNING)
        report1 = DomainListReport(config, [guest1],
                                   hypervisor_id='hypervisor_id_1')

        datastore = {'source1': report1}
        data_to_send = {'source1': report1}

        logger = Mock()

        error_to_throw = ManagerThrottleError(retry_after=62)

        manager = Mock()
        manager.sendVirtGuests = Mock(side_effect=[error_to_throw, report1])
        terminate_event = Mock()
        interval = 10
        options = Mock()
        options.print_ = False
        destination_thread = DestinationThread(logger,
                                               config,
                                               source_keys=source_keys,
                                               source=datastore,
                                               dest=manager,
                                               interval=interval,
                                               terminate_event=terminate_event,
                                               oneshot=False,
                                               options=self.options)
        destination_thread.wait = Mock()
        destination_thread.record_status = Mock()
        destination_thread.is_terminated = Mock(return_value=False)
        destination_thread._send_data(data_to_send)
        manager.sendVirtGuests.assert_has_calls(
            [call(report1, options=destination_thread.options)])
        destination_thread.wait.assert_has_calls(
            [call(wait_time=error_to_throw.retry_after)])
Exemple #8
0
    def test_send_data_poll_hypervisor_async_result(self):
        # This test's that when we have an async result from the server,
        # we poll for the result

        # Setup the test data
        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'

        guest1 = Guest('GUUID1', virt1.CONFIG_TYPE, Guest.STATE_RUNNING)
        guest2 = Guest('GUUID2', virt2.CONFIG_TYPE, Guest.STATE_RUNNING)
        assoc1 = {'hypervisors': [Hypervisor('hypervisor_id_1', [guest1])]}
        assoc2 = {'hypervisors': [Hypervisor('hypervisor_id_2', [guest2])]}
        report1 = HostGuestAssociationReport(config1, assoc1)
        report2 = HostGuestAssociationReport(config2, assoc2)

        data_to_send = {'source1': report1, 'source2': report2}
        source_keys = ['source1', 'source2']
        batch_report1 = Mock()  # The "report" to check status
        batch_report1.state = AbstractVirtReport.STATE_CREATED
        datastore = {'source1': report1, 'source2': report2}
        manager = Mock()
        items = [
            ManagerThrottleError(),
            ManagerThrottleError(),
            ManagerThrottleError(), AbstractVirtReport.STATE_FINISHED
        ]
        manager.check_report_state = Mock(
            side_effect=self.check_report_state_closure(items))

        logger = Mock()
        config, d = self.create_fake_config('test', **self.default_config_args)
        terminate_event = Mock()
        interval = 10  # Arbitrary for this test
        options = Mock()
        options.print_ = False
        destination_thread = DestinationThread(logger,
                                               config,
                                               source_keys=source_keys,
                                               source=datastore,
                                               dest=manager,
                                               interval=interval,
                                               terminate_event=terminate_event,
                                               oneshot=False,
                                               options=self.options)
        # In this test we want to see that the wait method is called when we
        # expect and with what parameters we expect
        destination_thread.wait = Mock()
        destination_thread.is_terminated = Mock(return_value=False)
        destination_thread.check_report_status(batch_report1)
        # There should be three waits, one after the job is submitted with duration of
        # MinimumJobPollingInterval. The second and third with duration MinimumJobPollInterval * 2
        # (and all subsequent calls as demonstrated by the third wait)
        destination_thread.wait.assert_has_calls([
            call(wait_time=MinimumJobPollInterval),
            call(wait_time=MinimumJobPollInterval * 2),
            call(wait_time=MinimumJobPollInterval * 2)
        ])
Exemple #9
0
    def test_send_data_poll_async_429(self):
        # This test's that when a 429 is detected during async polling
        # we wait for the amount of time specified
        source_keys = ['source1', 'source2']
        config1 = Config('source1', 'esx')
        config2 = Config('source2', 'esx')
        virt1 = Mock()
        virt1.CONFIG_TYPE = 'esx'
        virt2 = Mock()
        virt2.CONFIG_TYPE = 'esx'

        guest1 = Guest('GUUID1', virt1, Guest.STATE_RUNNING)
        guest2 = Guest('GUUID2', virt2, Guest.STATE_RUNNING)
        assoc1 = {'hypervisors': [Hypervisor('hypervisor_id_1', [guest1])]}
        assoc2 = {'hypervisors': [Hypervisor('hypervisor_id_2', [guest2])]}
        report1 = HostGuestAssociationReport(config1, assoc1)
        report2 = HostGuestAssociationReport(config2, assoc2)

        datastore = {'source1': report1, 'source2': report2}
        data_to_send = {'source1': report1, 'source2': report2}
        config = Mock()
        config.polling_interval = 10
        error_to_throw = ManagerThrottleError(retry_after=20)

        manager = Mock()
        manager.hypervisorCheckIn.return_value = report1

        # A closure to allow us to have a function that "modifies" the given
        # report in a predictable way.
        # In this case I want to set the state of the report to STATE_FINISHED
        # after the first try

        def check_report_state_closure(items):
            item_iterator = iter(items)

            def mock_check_report_state(report):
                item = next(item_iterator)
                if isinstance(item, Exception):
                    raise item
                report.state = item
                return report

            return mock_check_report_state

        states = [error_to_throw, AbstractVirtReport.STATE_FINISHED]
        expected_wait_calls = [call(wait_time=error_to_throw.retry_after)]

        check_report_mock = check_report_state_closure(states)
        manager.check_report_state = Mock(side_effect=check_report_mock)
        logger = Mock()
        terminate_event = Mock()
        interval = 10  # Arbitrary for this test
        options = Mock()
        options.print_ = False
        destination_thread = DestinationThread(logger,
                                               config,
                                               source_keys=source_keys,
                                               source=datastore,
                                               dest=manager,
                                               interval=interval,
                                               terminate_event=terminate_event,
                                               oneshot=True,
                                               options=options)
        destination_thread.wait = Mock()
        destination_thread._send_data(data_to_send)
        destination_thread.wait.assert_has_calls(expected_wait_calls)
    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
Exemple #11
0
    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