Source code for octavia_tempest_plugin.tests.waiters

#   Copyright 2017 GoDaddy
# Copyright 2018 Rackspace US Inc.  All rights reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

import time

from oslo_log import log as logging
from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions

from octavia_tempest_plugin.common import constants as const

CONF = config.CONF
LOG = logging.getLogger(__name__)


[docs] def wait_for_status(show_client, id, status_key, status, check_interval, check_timeout, root_tag=None, error_ok=False, **kwargs): """Waits for an object to reach a specific status. :param show_client: The tempest service client show method. Ex. cls.os_primary.servers_client.show_server :param id: The id of the object to query. :param status_key: The key of the status field in the response. Ex. provisioning_status :param status: The status to wait for. Ex. "ACTIVE" :check_interval: How often to check the status, in seconds. :check_timeout: The maximum time, in seconds, to check the status. :root_tag: The root tag on the response to remove, if any. :error_ok: When true, ERROR status will not raise an exception. :raises CommandFailed: Raised if the object goes into ERROR and ERROR was not the desired status. :raises TimeoutException: The object did not achieve the status or ERROR in the check_timeout period. :returns: The object details from the show client. """ start = int(time.time()) LOG.info('Waiting for {name} status to update to {status}'.format( name=show_client.__name__, status=status)) while True: if status == const.DELETED: try: response = show_client(id, **kwargs) except exceptions.NotFound: return else: response = show_client(id, **kwargs) if root_tag: object_details = response[root_tag] else: object_details = response if object_details[status_key] == status: LOG.info('{name}\'s status updated to {status}.'.format( name=show_client.__name__, status=status)) return object_details elif object_details[status_key] == 'ERROR' and not error_ok: message = ('{name} {field} updated to an invalid state of ' 'ERROR'.format(name=show_client.__name__, field=status_key)) caller = test_utils.find_test_caller() if caller: message = '({caller}) {message}'.format(caller=caller, message=message) raise exceptions.UnexpectedResponseCode(message) if int(time.time()) - start >= check_timeout: message = ( '{name} {field} failed to update to {expected_status} within ' 'the required time {timeout}. Current status of {name}: ' '{status}'.format( name=show_client.__name__, timeout=check_timeout, status=object_details[status_key], expected_status=status, field=status_key )) caller = test_utils.find_test_caller() if caller: message = '({caller}) {message}'.format(caller=caller, message=message) raise exceptions.TimeoutException(message) time.sleep(check_interval)
[docs] def wait_for_not_found(delete_func, show_func, *args, **kwargs): """Call the delete function, then wait for it to be 'NotFound' :param delete_func: The delete function to call. :param show_func: The show function to call looking for 'NotFound'. :param ID: The ID of the object to delete/show. :raises TimeoutException: The object did not achieve the status or ERROR in the check_timeout period. :returns: None """ try: delete_func(*args, **kwargs) except exceptions.NotFound: return start = int(time.time()) LOG.info('Waiting for object to be NotFound') while True: try: show_func(*args, **kwargs) except exceptions.NotFound: return if int(time.time()) - start >= CONF.load_balancer.check_timeout: message = ('{name} did not raise NotFound in {timeout} ' 'seconds.'.format( name=show_func.__name__, timeout=CONF.load_balancer.check_timeout)) raise exceptions.TimeoutException(message) time.sleep(CONF.load_balancer.check_interval)
[docs] def wait_for_deleted_status_or_not_found( show_client, id, status_key, check_interval, check_timeout, root_tag=None, **kwargs): """Waits for an object to reach a DELETED status or be not found (404). :param show_client: The tempest service client show method. Ex. cls.os_primary.servers_client.show_server :param id: The id of the object to query. :param status_key: The key of the status field in the response. Ex. provisioning_status :check_interval: How often to check the status, in seconds. :check_timeout: The maximum time, in seconds, to check the status. :root_tag: The root tag on the response to remove, if any. :raises CommandFailed: Raised if the object goes into ERROR and ERROR was not the desired status. :raises TimeoutException: The object did not achieve the status or ERROR in the check_timeout period. :returns: None """ start = int(time.time()) LOG.info('Waiting for {name} status to update to DELETED or be not ' 'found(404)'.format(name=show_client.__name__)) while True: try: response = show_client(id, **kwargs) except exceptions.NotFound: return if root_tag: object_details = response[root_tag] else: object_details = response if object_details[status_key] == const.DELETED: LOG.info('{name}\'s status updated to DELETED.'.format( name=show_client.__name__)) return elif int(time.time()) - start >= check_timeout: message = ( '{name} {field} failed to update to DELETED or become not ' 'found (404) within the required time {timeout}. Current ' 'status of {name}: {status}'.format( name=show_client.__name__, timeout=check_timeout, status=object_details[status_key], field=status_key )) caller = test_utils.find_test_caller() if caller: message = '({caller}) {message}'.format(caller=caller, message=message) raise exceptions.TimeoutException(message) time.sleep(check_interval)
[docs] def wait_for_spare_amps(list_func, check_interval, check_timeout): """Waits for amphorae in spare pool. :param list_func: The tempest service client amphora list method. Ex. cls.os_admin.amphora_client.list_amphorae :check_interval: How often to check the status, in seconds. :check_timeout: The maximum time, in seconds, to check the status. :raises TimeoutException: No amphora available in spare pool in the check_timeout period. :returns: A list of amphorae in spare pool. """ LOG.info('Waiting for amphorae in spare pool') start = int(time.time()) while True: spare_amps = list_func( query_params='{status}={status_ready}'.format( status=const.STATUS, status_ready=const.STATUS_READY)) if len(spare_amps) >= 1: return spare_amps if int(time.time()) - start >= check_timeout: message = ("No available amphorae in spare pool within the " "required time {timeout}.".format( timeout=check_timeout)) raise exceptions.TimeoutException(message) time.sleep(check_interval)
[docs] def wait_until_true(func, timeout=60, sleep=1, **kwargs): """Wait until callable predicate is evaluated as True :param func: Callable deciding whether waiting should continue. :param timeout: Timeout in seconds how long should function wait. :param sleep: Polling interval for results in seconds. """ start = int(time.time()) while True: try: ret = func(**kwargs) if ret: return except Exception as e: LOG.error(e) if int(time.time()) - start >= timeout: message = "Timed out after {timeout} seconds waiting".format( timeout=timeout) raise exceptions.TimeoutException(message) time.sleep(sleep)