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 })
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 })
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 })