def wait(self,
             allocation_id,
             timeout=0,
             poll_interval=1,
             poll_delay_function=None,
             os_ironic_api_version=None,
             global_request_id=None):
        """Wait for the Allocation to become active.

        :param timeout: timeout in seconds, no timeout if 0.
        :param poll_interval: interval in seconds between polls.
        :param poll_delay_function: function to use to wait between polls
            (defaults to time.sleep). Should take one argument - delay time
            in seconds. Any exceptions raised inside it will abort the wait.
        :param os_ironic_api_version: String version (e.g. "1.35") to use for
            the request.  If not specified, the client's default is used.
        :param global_request_id: String containing global request ID header
            value (in form "req-<UUID>") to use for the request.
        :return: updated :class:`Allocation` object.
        :raises: StateTransitionFailed if allocation reaches the error state.
        :raises: StateTransitionTimeout on timeout.
        """
        timeout_msg = _('Allocation %(allocation)s failed to become active '
                        'in %(timeout)s seconds') % {
                            'allocation': allocation_id,
                            'timeout': timeout
                        }
        for _count in utils.poll(timeout, poll_interval, poll_delay_function,
                                 timeout_msg):
            allocation = self.get(allocation_id,
                                  os_ironic_api_version=os_ironic_api_version,
                                  global_request_id=global_request_id)
            if allocation.state == 'error':
                raise exc.StateTransitionFailed(
                    _('Allocation %(allocation)s failed: %(error)s') % {
                        'allocation': allocation_id,
                        'error': allocation.last_error
                    })
            elif allocation.state == 'active':
                return allocation

            LOG.debug(
                'Still waiting for allocation %(allocation)s to become '
                'active, the current state is %(actual)s', {
                    'allocation': allocation_id,
                    'actual': allocation.state
                })
Exemple #2
0
    def wait(self,
             allocation_id,
             timeout=0,
             poll_interval=1,
             poll_delay_function=None):
        """Wait for the Allocation to become active.

        :param timeout: timeout in seconds, no timeout if 0.
        :param poll_interval: interval in seconds between polls.
        :param poll_delay_function: function to use to wait between polls
            (defaults to time.sleep). Should take one argument - delay time
            in seconds. Any exceptions raised inside it will abort the wait.
        :return: updated :class:`Allocation` object.
        :raises: StateTransitionFailed if allocation reaches the error state.
        :raises: StateTransitionTimeout on timeout.
        """
        timeout_msg = _('Allocation %(allocation)s failed to become active '
                        'in %(timeout)s seconds') % {
                            'allocation': allocation_id,
                            'timeout': timeout
                        }
        for _count in utils.poll(timeout, poll_interval, poll_delay_function,
                                 timeout_msg):
            allocation = self.get(allocation_id)
            if allocation.state == 'error':
                raise exc.StateTransitionFailed(
                    _('Allocation %(allocation)s failed: %(error)s') % {
                        'allocation': allocation_id,
                        'error': allocation.last_error
                    })
            elif allocation.state == 'active':
                return allocation

            LOG.debug(
                'Still waiting for allocation %(allocation)s to become '
                'active, the current state is %(actual)s', {
                    'allocation': allocation_id,
                    'actual': allocation.state
                })
    def wait_for_provision_state(self,
                                 node_ident,
                                 expected_state,
                                 timeout=0,
                                 poll_interval=_DEFAULT_POLL_INTERVAL,
                                 poll_delay_function=None,
                                 fail_on_unexpected_state=True):
        """Helper function to wait for a node to reach a given state.

        Polls Ironic API in a loop until node gets to a requested state.

        Fails in the following cases:
        * Timeout (if provided) is reached
        * Node's last_error gets set to a non-empty value
        * Unexpected stable state is reached and fail_on_unexpected_state is on
        * Error state is reached (if it's not equal to expected_state)

        :param node_ident: node UUID or name
        :param expected_state: expected final provision state
        :param timeout: timeout in seconds, no timeout if 0
        :param poll_interval: interval in seconds between 2 poll
        :param poll_delay_function: function to use to wait between polls
            (defaults to time.sleep). Should take one argument - delay time
            in seconds. Any exceptions raised inside it will abort the wait.
        :param fail_on_unexpected_state: whether to fail if the nodes
            reaches a different stable state.
        :raises: StateTransitionFailed if node reached an error state
        :raises: StateTransitionTimeout on timeout
        """
        if not isinstance(timeout, (int, float)) or timeout < 0:
            raise ValueError(_('Timeout must be a non-negative number'))

        threshold = time.time() + timeout
        expected_state = expected_state.lower()
        poll_delay_function = (time.sleep if poll_delay_function is None else
                               poll_delay_function)
        if not callable(poll_delay_function):
            raise TypeError(_('poll_delay_function must be callable'))

        # TODO(dtantsur): use version negotiation to request API 1.8 and use
        # the "fields" argument to reduce amount of data sent.
        while not timeout or time.time() < threshold:
            node = self.get(node_ident)
            if node.provision_state == expected_state:
                LOG.debug('Node %(node)s reached provision state %(state)s', {
                    'node': node_ident,
                    'state': expected_state
                })
                return

            # Note that if expected_state == 'error' we still succeed
            if (node.last_error or node.provision_state == 'error'
                    or node.provision_state.endswith(' failed')):
                raise exc.StateTransitionFailed(
                    _('Node %(node)s failed to reach state %(state)s. '
                      'It\'s in state %(actual)s, and has error: %(error)s') %
                    {
                        'node': node_ident,
                        'state': expected_state,
                        'actual': node.provision_state,
                        'error': node.last_error
                    })

            if fail_on_unexpected_state and not node.target_provision_state:
                raise exc.StateTransitionFailed(
                    _('Node %(node)s failed to reach state %(state)s. '
                      'It\'s in unexpected stable state %(actual)s') % {
                          'node': node_ident,
                          'state': expected_state,
                          'actual': node.provision_state
                      })

            LOG.debug(
                'Still waiting for node %(node)s to reach state '
                '%(state)s, the current state is %(actual)s', {
                    'node': node_ident,
                    'state': expected_state,
                    'actual': node.provision_state
                })
            poll_delay_function(poll_interval)

        raise exc.StateTransitionTimeout(
            _('Node %(node)s failed to reach state %(state)s in '
              '%(timeout)s seconds') % {
                  'node': node_ident,
                  'state': expected_state,
                  'timeout': timeout
              })
Exemple #4
0
    def wait_for_provision_state(self,
                                 node_ident,
                                 expected_state,
                                 timeout=0,
                                 poll_interval=_DEFAULT_POLL_INTERVAL,
                                 poll_delay_function=None,
                                 fail_on_unexpected_state=True,
                                 os_ironic_api_version=None,
                                 global_request_id=None):
        """Helper function to wait for a node to reach a given state.

        Polls Ironic API in a loop until node gets to a requested state.

        Fails in the following cases:
        * Timeout (if provided) is reached
        * Node's last_error gets set to a non-empty value
        * Unexpected stable state is reached and fail_on_unexpected_state is on
        * Error state is reached (if it's not equal to expected_state)

        :param node_ident: node UUID or name
        :param expected_state: expected final provision state
        :param timeout: timeout in seconds, no timeout if 0
        :param poll_interval: interval in seconds between 2 poll
        :param poll_delay_function: function to use to wait between polls
            (defaults to time.sleep). Should take one argument - delay time
            in seconds. Any exceptions raised inside it will abort the wait.
        :param fail_on_unexpected_state: whether to fail if the nodes
            reaches a different stable state.
        :param os_ironic_api_version: String version (e.g. "1.35") to use for
            the request.  If not specified, the client's default is used.
        :param global_request_id: String containing global request ID header
            value (in form "req-<UUID>") to use for the request.

        :raises: StateTransitionFailed if node reached an error state
        :raises: StateTransitionTimeout on timeout
        """
        expected_state = expected_state.lower()
        timeout_msg = _('Node %(node)s failed to reach state %(state)s in '
                        '%(timeout)s seconds') % {
                            'node': node_ident,
                            'state': expected_state,
                            'timeout': timeout
                        }

        # TODO(dtantsur): use version negotiation to request API 1.8 and use
        # the "fields" argument to reduce amount of data sent.
        for _count in utils.poll(timeout, poll_interval, poll_delay_function,
                                 timeout_msg):
            node = self.get(node_ident,
                            os_ironic_api_version=os_ironic_api_version,
                            global_request_id=global_request_id)
            if node.provision_state == expected_state:
                LOG.debug('Node %(node)s reached provision state %(state)s', {
                    'node': node_ident,
                    'state': expected_state
                })
                return

            # Note that if expected_state == 'error' we still succeed
            if (node.provision_state == 'error'
                    or node.provision_state.endswith(' failed')):
                raise exc.StateTransitionFailed(
                    _('Node %(node)s failed to reach state %(state)s. '
                      'It\'s in state %(actual)s, and has error: %(error)s') %
                    {
                        'node': node_ident,
                        'state': expected_state,
                        'actual': node.provision_state,
                        'error': node.last_error
                    })

            if fail_on_unexpected_state and not node.target_provision_state:
                raise exc.StateTransitionFailed(
                    _('Node %(node)s failed to reach state %(state)s. '
                      'It\'s in unexpected stable state %(actual)s') % {
                          'node': node_ident,
                          'state': expected_state,
                          'actual': node.provision_state
                      })

            LOG.debug(
                'Still waiting for node %(node)s to reach state '
                '%(state)s, the current state is %(actual)s', {
                    'node': node_ident,
                    'state': expected_state,
                    'actual': node.provision_state
                })