def wait_for_status(session, resource, status, failures, interval, wait):
    """Wait for the resource to be in a particular status.

    :param session: The session to use for making this request.
    :type session: :class:`~keystoneauth1.adapter.Adapter`
    :param resource: The resource to wait on to reach the status. The resource
                     must have a status attribute.
    :type resource: :class:`~openstack.resource.Resource`
    :param status: Desired status of the resource.
    :param list failures: Statuses that would indicate the transition
                          failed such as 'ERROR'. Defaults to ['ERROR'].
    :param interval: Number of seconds to wait between checks.
    :param wait: Maximum number of seconds to wait for transition.

    :return: Method returns self on success.
    :raises: :class:`~openstack.exceptions.ResourceTimeout` transition
             to status failed to occur in wait seconds.
    :raises: :class:`~openstack.exceptions.ResourceFailure` resource
             transitioned to one of the failure states.
    :raises: :class:`~AttributeError` if the resource does not have a status
             attribute
    """
    if resource.status == status:
        return resource

    if failures is None:
        failures = ['ERROR']

    failures = [f.lower() for f in failures]
    name = "{res}:{id}".format(res=resource.__class__.__name__, id=resource.id)
    msg = "Timeout waiting for {name} to transition to {status}".format(
        name=name, status=status)

    for count in utils.iterate_timeout(
            timeout=wait,
            message=msg,
            wait=interval):
        resource = resource.get(session)
        new_status = resource.status

        if not resource:
            raise exceptions.ResourceFailure(
                "{name} went away while waiting for {status}".format(
                    name=name, status=status))
        if new_status.lower() == status.lower():
            return resource
        if resource.status.lower() in failures:
            raise exceptions.ResourceFailure(
                "{name} transitioned to failure state {status}".format(
                    name=name, status=resource.status))
Beispiel #2
0
    def create(self, session, prepend_key=True):
        """Create a remote resource based on this instance.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param prepend_key: A boolean indicating whether the resource_key
                            should be prepended in a resource creation
                            request. Default to True.

        :return: This :class:`Resource` instance.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_create` is not set to ``True``.
        """
        if not self.allow_create:
            raise exceptions.MethodNotSupported(self, "create")

        session = self._get_session(session)
        if self.create_method == 'PUT':
            request = self._prepare_request(requires_id=True,
                                            prepend_key=prepend_key)
            response = session.put(request.url,
                                   json=request.body,
                                   headers=request.headers)
        elif self.create_method == 'POST':
            request = self._prepare_request(requires_id=False,
                                            prepend_key=prepend_key)
            response = session.post(request.url,
                                    json=request.body,
                                    headers=request.headers)
        else:
            raise exceptions.ResourceFailure(msg="Invalid create method: %s" %
                                             self.create_method)

        self._translate_response(response)
        return self
    def create(self, session, prepend_key=True, requires_id=True,
               endpoint_override=None, headers=None):
        if not self.allow_create:
            raise exceptions.MethodNotSupported(self, "create")

        session = self._get_session(session)

        if self.create_method == 'PUT':
            request = self._prepare_request(requires_id=True,
                                            prepend_key=prepend_key)
            req_args = self._prepare_override_args(
                endpoint_override=endpoint_override,
                request_headers=request.headers,
                additional_headers=headers)
            response = session.put(request.url,
                                   json=request.body, **req_args)
        elif self.create_method == 'POST':
            request = self._prepare_request(requires_id=False,
                                            prepend_key=prepend_key)
            req_args = self._prepare_override_args(
                endpoint_override=endpoint_override,
                request_headers=request.headers,
                additional_headers=headers)
            response = session.post(request.url,
                                    json=request.body, **req_args)
        else:
            raise exceptions.ResourceFailure(
                msg="Invalid create method: %s" % self.create_method)

        # This is an only difference to the existing sdk_resource.create
        self._translate_response(response, has_body=False)

        return self
Beispiel #4
0
    def wait(self, session, timeout=None, ignore_error=False):
        """Wait for the allocation to become active.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param timeout: How much (in seconds) to wait for the allocation.
            The value of ``None`` (the default) means no client-side timeout.
        :param ignore_error: If ``True``, this call will raise an exception
            if the allocation reaches the ``error`` state. Otherwise the error
            state is considered successful and the call returns.

        :return: This :class:`Allocation` instance.
        :raises: :class:`~openstack.exceptions.ResourceFailure` if allocation
            fails and ``ignore_error`` is ``False``.
        :raises: :class:`~openstack.exceptions.ResourceTimeout` on timeout.
        """
        if self.state == 'active':
            return self

        for count in utils.iterate_timeout(
                timeout,
                "Timeout waiting for the allocation %s" % self.id):
            self.fetch(session)

            if self.state == 'error' and not ignore_error:
                raise exceptions.ResourceFailure(
                    "Allocation %(allocation)s failed: %(error)s" %
                    {'allocation': self.id, 'error': self.last_error})
            elif self.state != 'allocating':
                return self

            session.log.debug(
                'Still waiting for the allocation %(allocation)s '
                'to become active, the current state is %(state)s',
                {'allocation': self.id, 'state': self.state})
Beispiel #5
0
    def create(self, session, prepend_key=True, base_path=None, **params):
        """Create a remote resource based on this instance.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param prepend_key: A boolean indicating whether the resource_key
                            should be prepended in a resource creation
                            request. Default to True.
        :param str base_path: Base part of the URI for creating resources, if
                              different from
                              :data:`~openstack.resource.Resource.base_path`.
        :param dict params: Additional params to pass.
        :return: This :class:`Resource` instance.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_create` is not set to ``True``.
        """
        if not self.allow_create:
            raise exceptions.MethodNotSupported(self, "create")

        session = self._get_session(session)
        microversion = self._get_microversion_for(session, 'create')
        requires_id = (self.create_requires_id if self.create_requires_id
                       is not None else self.create_method == 'PUT')

        if self.create_exclude_id_from_body:
            self._body._dirty.discard("id")

        if self.create_method == 'POST':
            request = self._prepare_request(requires_id=requires_id,
                                            prepend_key=prepend_key,
                                            base_path=base_path)
            # NOTE(gtema) this is a funny example of when attribute
            # is called "incremental" on create, "is_incremental" on get
            # and use of "alias" or "aka" is not working for such conflict,
            # since our preferred attr name is exactly "is_incremental"
            body = request.body
            if 'is_incremental' in body['backup']:
                body['backup']['incremental'] = \
                    body['backup'].pop('is_incremental')
            response = session.post(request.url,
                                    json=request.body,
                                    headers=request.headers,
                                    microversion=microversion,
                                    params=params)
        else:
            # Just for safety of the implementation (since PUT removed)
            raise exceptions.ResourceFailure(msg="Invalid create method: %s" %
                                             self.create_method)

        has_body = (self.has_body if self.create_returns_body is None else
                    self.create_returns_body)
        self.microversion = microversion
        self._translate_response(response, has_body=has_body)
        # direct comparision to False since we need to rule out None
        if self.has_body and self.create_returns_body is False:
            # fetch the body if it's required but not returned by create
            return self.fetch(session)
        return self
Beispiel #6
0
    def _check_state_reached(self,
                             session,
                             expected_state,
                             abort_on_failed_state=True):
        """Wait for the node to reach the expected state.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param expected_state: The expected provisioning state to reach.
        :param abort_on_failed_state: If ``True`` (the default), abort waiting
            if the node reaches a failure state which does not match the
            expected one. Note that the failure state for ``enroll`` ->
            ``manageable`` transition is ``enroll`` again.

        :return: ``True`` if the target state is reached
        :raises: :class:`~openstack.exceptions.ResourceFailure` if the node
            reaches an error state and ``abort_on_failed_state`` is ``True``.
        """
        # NOTE(dtantsur): microversion 1.2 changed None to available
        if (self.provision_state == expected_state or
            (expected_state == 'available' and self.provision_state is None)):
            return True
        elif not abort_on_failed_state:
            return False

        if (self.provision_state.endswith(' failed')
                or self.provision_state == 'error'):
            raise exceptions.ResourceFailure(
                "Node %(node)s reached failure state \"%(state)s\"; "
                "the last error is %(error)s" % {
                    'node': self.id,
                    'state': self.provision_state,
                    'error': self.last_error
                })
        # Special case: a failure state for "manage" transition can be
        # "enroll"
        elif (expected_state == 'manageable'
              and self.provision_state == 'enroll' and self.last_error):
            raise exceptions.ResourceFailure(
                "Node %(node)s could not reach state manageable: "
                "failed to verify management credentials; "
                "the last error is %(error)s" % {
                    'node': self.id,
                    'error': self.last_error
                })
Beispiel #7
0
 def _check_state(self, ignore_error):
     if self.state == 'error' and not ignore_error:
         raise exceptions.ResourceFailure(
             "Introspection of node %(node)s failed: %(error)s" % {
                 'node': self.id,
                 'error': self.error
             })
     else:
         return self.is_finished
    def update_no_id(self,
                     session,
                     prepend_key=True,
                     has_body=True,
                     endpoint_override=None,
                     headers=None):
        """Update the remote resource based on this instance.

        Method is required for resources without ID
        (single resource at endpoint)

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param prepend_key: A boolean indicating whether the resource_key
                            should be prepended in a resource update request.
                            Default to True.

        :return: This :class:`Resource` instance.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_update` is not set to ``True``.
        """
        # Only try to update if we actually have anything to update.
        if not any([self._body.dirty, self._header.dirty]):
            return self

        if not self.allow_update:
            raise exceptions.MethodNotSupported(self, "update")

        request = self._prepare_request(requires_id=False,
                                        prepend_key=prepend_key)
        session = self._get_session(session)

        update_args = self._prepare_override_args(
            endpoint_override=endpoint_override,
            request_headers=request.headers,
            additional_headers=headers)

        if self.commit_method == 'PATCH':
            response = session.patch(request.url,
                                     json=request.body,
                                     **update_args)
        elif self.commit_method == 'POST':
            response = session.post(request.url,
                                    json=request.body,
                                    **update_args)
        elif self.commit_method == 'PUT':
            response = session.put(request.url,
                                   json=request.body,
                                   **update_args)
        else:
            raise exceptions.ResourceFailure(msg="Invalid update method: %s" %
                                             self.commit_method)

        self._translate_response(response, has_body=has_body)
        return self
Beispiel #9
0
 def _fake_get(_self, uuid):
     result = mock.Mock()
     result.id = uuid
     if uuid == '1':
         result._check_state_reached.return_value = True
     elif uuid == '2':
         result._check_state_reached.side_effect = \
             exceptions.ResourceFailure("boom")
     else:
         result._check_state_reached.return_value = False
     return result
Beispiel #10
0
def wait_for_status(session,
                    resource,
                    status,
                    failures=[],
                    interval=5,
                    wait=120):
    """Wait for the resource to be in a particular status.

    :param session: The session to use for making this request.
    :type session: :class:`~openstack.session.Session`
    :param resource: The resource to wait on to reach the status. The resource
                     must have a status attribute.
    :type resource: :class:`~openstack.resource.Resource`
    :param status: Desired status of the resource.
    :param list failures: Statuses that would indicate the transition
                          failed such as 'ERROR'.
    :param interval: Number of seconds to wait between checks.
    :param wait: Maximum number of seconds to wait for transition.

    :return: Method returns self on success.
    :raises: :class:`~openstack.exceptions.ResourceTimeout` transition
             to status failed to occur in wait seconds.
    :raises: :class:`~openstack.exceptions.ResourceFailure` resource
             transitioned to one of the failure states.
    :raises: :class:`~AttributeError` if the resource does not have a status
             attribute
    """
    if resource.status == status:
        return resource

    total_sleep = 0
    if failures is None:
        failures = []

    while total_sleep < wait:
        resource.get(session)
        if resource.status == status:
            return resource
        if resource.status in failures:
            msg = ("Resource %s transitioned to failure state %s" %
                   (resource.id, resource.status))
            raise exceptions.ResourceFailure(msg)
        time.sleep(interval)
        total_sleep += interval
    msg = "Timeout waiting for %s to transition to %s" % (resource.id, status)
    raise exceptions.ResourceTimeout(msg)
Beispiel #11
0
    def update(self, session, prepend_key=True, has_body=True):
        """Update the remote resource based on this instance.

        :param session: The session to use for making this request.
        :type session: :class:`~keystoneauth1.adapter.Adapter`
        :param prepend_key: A boolean indicating whether the resource_key
                            should be prepended in a resource update request.
                            Default to True.

        :return: This :class:`Resource` instance.
        :raises: :exc:`~openstack.exceptions.MethodNotSupported` if
                 :data:`Resource.allow_update` is not set to ``True``.
        """
        # The id cannot be dirty for an update
        self._body._dirty.discard("id")

        # Only try to update if we actually have anything to update.
        if not any([self._body.dirty, self._header.dirty]):
            return self

        if not self.allow_update:
            raise exceptions.MethodNotSupported(self, "update")

        request = self._prepare_request(prepend_key=prepend_key)
        session = self._get_session(session)

        if self.update_method == 'PATCH':
            response = session.patch(request.url,
                                     json=request.body,
                                     headers=request.headers)
        elif self.update_method == 'POST':
            response = session.post(request.url,
                                    json=request.body,
                                    headers=request.headers)
        elif self.update_method == 'PUT':
            response = session.put(request.url,
                                   json=request.body,
                                   headers=request.headers)
        else:
            raise exceptions.ResourceFailure(msg="Invalid update method: %s" %
                                             self.update_method)

        self._translate_response(response, has_body=has_body)
        return self
Beispiel #12
0
    def wait_for_status(self,
                        session,
                        status='ACTIVE',
                        failures=None,
                        interval=5,
                        wait=120):
        """Wait for the server to be in some status.

        :param session: The session to use for making this request.
        :type session: :class:`~openstack.session.Session`
        :param status: Desired status of the server.
        :param list failures: Statuses that would indicate the transition
                              failed such as 'ERROR'.
        :param interval: Number of seconds to wait between checks.
        :param wait: Maximum number of seconds to wait for transition.

        :return: Method returns self on success.
        :raises: :class:`~openstack.exceptions.ResourceTimeout` transition
                 to status failed to occur in wait seconds.
        :raises: :class:`~openstack.exceptions.ResourceFailure` resource
                 transitioned to one of the failure states.
        """
        try:
            if self.status == status:
                return self
        except AttributeError:
            pass
        total_sleep = 0
        if failures is None:
            failures = []
        while total_sleep < wait:
            self.get(session)
            if self.status == status:
                return self
            if self.status in failures:
                msg = ("Resource %s transitioned to failure state %s" %
                       (self.id, self.status))
                raise exceptions.ResourceFailure(msg)
            time.sleep(interval)
            total_sleep += interval
        msg = "Timeout waiting for %s to transition to %s" % (self.id, status)
        raise exceptions.ResourceTimeout(msg)
Beispiel #13
0
    def lb_wait_for_status(cls, lb, status, failures, interval=1, wait=120):
        """Wait for load balancer to be in a particular provisioning status.

        :param lb: The load balancer to wait on to reach the status.
        :type lb: :class:`~openstack.load_blanacer.v2.load_balancer
        :param status: Desired status of the resource.
        :param list failures: Statuses that would indicate the transition
                              failed such as 'ERROR'.
        :param interval: Number of seconds to wait between checks.
        :param wait: Maximum number of seconds to wait for transition.
                     Note, most actions should easily finish in 120 seconds,
                     but for load balancer create slow hosts can take up to
                     ten minutes for nova to fully boot a VM.
        :return: None
        :raises: :class:`~openstack.exceptions.ResourceTimeout` transition
                 to status failed to occur in wait seconds.
        :raises: :class:`~openstack.exceptions.ResourceFailure` resource
                 transitioned to one of the failure states.
        """

        total_sleep = 0
        if failures is None:
            failures = []

        while total_sleep < wait:
            lb = cls.conn.load_balancer.get_load_balancer(lb.id)
            if lb.provisioning_status == status:
                return None
            if lb.provisioning_status in failures:
                msg = ("Load Balancer %s transitioned to failure state %s" %
                       (lb.id, lb.provisioning_status))
                raise exceptions.ResourceFailure(msg)
            time.sleep(interval)
            total_sleep += interval
        msg = "Timeout waiting for Load Balancer %s to transition to %s" % (
            lb.id, status)
        raise exceptions.ResourceTimeout(msg)
Beispiel #14
0
    def wait_for_task(self,
                      task,
                      status='success',
                      failures=None,
                      interval=2,
                      wait=120):
        """Wait for a task to be in a particular status.

        :param task: The resource to wait on to reach the specified status.
                    The resource must have a ``status`` attribute.
        :type resource: A :class:`~openstack.resource.Resource` object.
        :param status: Desired status.
        :param failures: Statuses that would be interpreted as failures.
        :type failures: :py:class:`list`
        :param interval: Number of seconds to wait before to consecutive
                         checks. Default to 2.
        :param wait: Maximum number of seconds to wait before the change.
                     Default to 120.
        :returns: The resource is returned on success.
        :raises: :class:`~openstack.exceptions.ResourceTimeout` if transition
                 to the desired status failed to occur in specified seconds.
        :raises: :class:`~openstack.exceptions.ResourceFailure` if the resource
                 has transited to one of the failure statuses.
        :raises: :class:`~AttributeError` if the resource does not have a
                ``status`` attribute.
        """
        if failures is None:
            failures = ['failure']
        else:
            failures = [f.lower() for f in failures]

        if task.status.lower() == status.lower():
            return task

        name = "{res}:{id}".format(res=task.__class__.__name__, id=task.id)
        msg = "Timeout waiting for {name} to transition to {status}".format(
            name=name, status=status)

        for count in utils.iterate_timeout(timeout=wait,
                                           message=msg,
                                           wait=interval):
            task = task.fetch(self)

            if not task:
                raise exceptions.ResourceFailure(
                    "{name} went away while waiting for {status}".format(
                        name=name, status=status))

            new_status = task.status
            normalized_status = new_status.lower()
            if normalized_status == status.lower():
                return task
            elif normalized_status in failures:
                if task.message == _IMAGE_ERROR_396:
                    task_args = dict(input=task.input, type=task.type)
                    task = self.create_task(**task_args)
                    self.log.debug('Got error 396. Recreating task %s' % task)
                else:
                    raise exceptions.ResourceFailure(
                        "{name} transitioned to failure state {status}".format(
                            name=name, status=new_status))

            self.log.debug(
                'Still waiting for resource %s to reach state %s, '
                'current state is %s', name, status, new_status)
Beispiel #15
0
def wait_for_status(session,
                    resource,
                    status,
                    failures,
                    interval=None,
                    wait=None,
                    attribute='status'):
    """Wait for the resource to be in a particular status.

    :param session: The session to use for making this request.
    :type session: :class:`~keystoneauth1.adapter.Adapter`
    :param resource: The resource to wait on to reach the status. The resource
                     must have a status attribute specified via ``attribute``.
    :type resource: :class:`~openstack.resource.Resource`
    :param status: Desired status of the resource.
    :param list failures: Statuses that would indicate the transition
                          failed such as 'ERROR'. Defaults to ['ERROR'].
    :param interval: Number of seconds to wait between checks.
                     Set to ``None`` to use the default interval.
    :param wait: Maximum number of seconds to wait for transition.
                 Set to ``None`` to wait forever.
    :param attribute: Name of the resource attribute that contains the status.

    :return: The updated resource.
    :raises: :class:`~openstack.exceptions.ResourceTimeout` transition
             to status failed to occur in wait seconds.
    :raises: :class:`~openstack.exceptions.ResourceFailure` resource
             transitioned to one of the failure states.
    :raises: :class:`~AttributeError` if the resource does not have a status
             attribute
    """
    log = _log.setup_logging(__name__)

    current_status = getattr(resource, attribute)
    if _normalize_status(current_status) == status.lower():
        return resource

    if failures is None:
        failures = ['ERROR']

    failures = [f.lower() for f in failures]
    name = "{res}:{id}".format(res=resource.__class__.__name__, id=resource.id)
    msg = "Timeout waiting for {name} to transition to {status}".format(
        name=name, status=status)

    for count in utils.iterate_timeout(timeout=wait,
                                       message=msg,
                                       wait=interval):
        resource = resource.get(session)

        if not resource:
            raise exceptions.ResourceFailure(
                "{name} went away while waiting for {status}".format(
                    name=name, status=status))

        new_status = getattr(resource, attribute)
        normalized_status = _normalize_status(new_status)
        if normalized_status == status.lower():
            return resource
        elif normalized_status in failures:
            raise exceptions.ResourceFailure(
                "{name} transitioned to failure state {status}".format(
                    name=name, status=new_status))

        log.debug(
            'Still waiting for resource %s to reach state %s, '
            'current state is %s', name, status, new_status)