From 83b7fb110e76a02551feb0cb5cc0a9dc18cccb72 Mon Sep 17 00:00:00 2001 From: Hongbin Lu Date: Tue, 19 Sep 2017 22:21:00 -0400 Subject: [PATCH] Remove the local tempest plugin The plugin has been split into its own repository [1] in accordance with Queens Goal "Split Tempest Plugins into Separate Repos/Projects" [2]. This patch removes the local copy as well as the setuptools entry point. [1] https://github.com/openstack/zun-tempest-plugin [2] https://governance.openstack.org/tc/goals/queens/ split-tempest-plugins.html Implements: blueprint zun-split-tempest-plugins Change-Id: Ibfeb38b52c05a9f886dc7524d892842971cbd264 --- devstack/lib/zun | 6 + doc/source/contributor/tempest-tests.rst | 2 +- setup.cfg | 3 - zun/tests/contrib/gate_hook.sh | 2 +- zun/tests/tempest/README.rst | 69 --- zun/tests/tempest/__init__.py | 0 zun/tests/tempest/api/__init__.py | 0 zun/tests/tempest/api/clients.py | 287 ---------- zun/tests/tempest/api/common/__init__.py | 0 zun/tests/tempest/api/common/base_model.py | 70 --- zun/tests/tempest/api/common/datagen.py | 105 ---- zun/tests/tempest/api/models/__init__.py | 0 .../tempest/api/models/container_model.py | 41 -- zun/tests/tempest/api/models/service_model.py | 30 - zun/tests/tempest/api/test_containers.py | 511 ------------------ zun/tests/tempest/api/test_services.py | 50 -- zun/tests/tempest/base.py | 35 -- zun/tests/tempest/config.py | 31 -- zun/tests/tempest/plugin.py | 41 -- zun/tests/tempest/utils.py | 25 - 20 files changed, 8 insertions(+), 1300 deletions(-) delete mode 100644 zun/tests/tempest/README.rst delete mode 100644 zun/tests/tempest/__init__.py delete mode 100644 zun/tests/tempest/api/__init__.py delete mode 100644 zun/tests/tempest/api/clients.py delete mode 100644 zun/tests/tempest/api/common/__init__.py delete mode 100644 zun/tests/tempest/api/common/base_model.py delete mode 100644 zun/tests/tempest/api/common/datagen.py delete mode 100644 zun/tests/tempest/api/models/__init__.py delete mode 100644 zun/tests/tempest/api/models/container_model.py delete mode 100644 zun/tests/tempest/api/models/service_model.py delete mode 100644 zun/tests/tempest/api/test_containers.py delete mode 100644 zun/tests/tempest/api/test_services.py delete mode 100644 zun/tests/tempest/base.py delete mode 100644 zun/tests/tempest/config.py delete mode 100644 zun/tests/tempest/plugin.py delete mode 100644 zun/tests/tempest/utils.py diff --git a/devstack/lib/zun b/devstack/lib/zun index 790a0d755..dc7f7f0a1 100644 --- a/devstack/lib/zun +++ b/devstack/lib/zun @@ -32,6 +32,9 @@ set +o xtrace ZUN_REPO=${ZUN_REPO:-${GIT_BASE}/openstack/zun.git} ZUN_BRANCH=${ZUN_BRANCH:-master} ZUN_DIR=$DEST/zun +ZUN_TEMPEST_PLUGIN_REPO=${ZUN_REPO:-${GIT_BASE}/openstack/zun-tempest-plugin.git} +ZUN_TEMPEST_PLUGIN_BRANCH=${ZUN_BRANCH:-master} +ZUN_TEMPEST_PLUGIN_DIR=$DEST/zun-tempest-plugin GITREPO["python-zunclient"]=${ZUNCLIENT_REPO:-${GIT_BASE}/openstack/python-zunclient.git} GITBRANCH["python-zunclient"]=${ZUNCLIENT_BRANCH:-master} @@ -296,6 +299,9 @@ function install_zunclient { function install_zun { git_clone $ZUN_REPO $ZUN_DIR $ZUN_BRANCH setup_develop $ZUN_DIR + + git_clone $ZUN_TEMPEST_PLUGIN_REPO $ZUN_TEMPEST_PLUGIN_DIR $ZUN_TEMPEST_PLUGIN_BRANCH + setup_develop $ZUN_TEMPEST_PLUGIN_DIR } function install_etcd_server { diff --git a/doc/source/contributor/tempest-tests.rst b/doc/source/contributor/tempest-tests.rst index 775f258ed..130d25363 100644 --- a/doc/source/contributor/tempest-tests.rst +++ b/doc/source/contributor/tempest-tests.rst @@ -61,4 +61,4 @@ Navigate to tempest directory:: Run this command:: - tox -eall-plugin -- zun.tests.tempest.api + tox -eall-plugin -- zun_tempest_plugin.tests.tempest.api diff --git a/setup.cfg b/setup.cfg index 588c71806..10fbf8c50 100644 --- a/setup.cfg +++ b/setup.cfg @@ -85,9 +85,6 @@ zun.network.driver = zun.volume.driver = cinder = zun.volume.driver:Cinder -tempest.test_plugins = - zun_tests = zun.tests.tempest.plugin:ZunTempestPlugin - [extras] osprofiler = osprofiler>=1.4.0 # Apache-2.0 diff --git a/zun/tests/contrib/gate_hook.sh b/zun/tests/contrib/gate_hook.sh index 2d7a693a5..fddd94a7d 100755 --- a/zun/tests/contrib/gate_hook.sh +++ b/zun/tests/contrib/gate_hook.sh @@ -27,7 +27,7 @@ export DEVSTACK_LOCAL_CONFIG+=$'\n'"ZUN_USE_UWSGI=True" export DEVSTACK_LOCAL_CONFIG+=$'\n'"KURYR_CONFIG_DIR=/etc/kuryr-libnetwork" export DEVSTACK_GATE_TEMPEST=1 export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1 -export DEVSTACK_GATE_TEMPEST_REGEX="zun.tests.tempest.api" +export DEVSTACK_GATE_TEMPEST_REGEX="zun_tempest_plugin.tests.tempest.api" if [ "$driver" = "docker" ]; then export DEVSTACK_LOCAL_CONFIG+=$'\n'"ZUN_DRIVER=docker" diff --git a/zun/tests/tempest/README.rst b/zun/tests/tempest/README.rst deleted file mode 100644 index 78e4abc72..000000000 --- a/zun/tests/tempest/README.rst +++ /dev/null @@ -1,69 +0,0 @@ -============== -Tempest Plugin -============== - -This directory contains Tempest tests to cover Zun project. - - -Tempest installation --------------------- - -To install Tempest you can issue the following commands:: - - $ git clone https://git.openstack.org/openstack/tempest/ - $ cd tempest/ - $ pip install . - -The folder you are into now will be called ```` from now onwards. - -Please note that although it is fully working outside a virtual environment, it -is recommended to install within a `venv`. - -Zun Tempest testing setup -------------------------- - -Before using zun tempest plugin, you need to install zun first:: - - $ pip install -e - -To list all Zun tempest cases, go to tempest directory, then run:: - - $ testr list-tests zun - -Need to adopt tempest.conf, an example as follows:: - - $ cat /etc/tempest/tempest.conf - - [auth] - use_dynamic_credentials=True - admin_username=admin - admin_password=123 - admin_project_name=admin - - [identity] - disable_ssl_certificate_validation=True - uri=http://127.0.0.1:5000/v2.0/ - auth_version=v2 - region=RegionOne - - [identity-feature-enabled] - api_v2 = true - api_v3 = false - trust = false - - [oslo_concurrency] - lock_path = /tmp/ - - [container_management] - catalog_type = container - - [debug] - trace_requests=true - -To run only these tests in tempest, go to tempest directory, then run:: - - $ tempest run zun - -To run a single test case, go to tempest directory, then run with test case name, e.g.:: - - $ tempest run --regex zun.tests.tempest.api.test_containers.TestContainer.test_create_list_delete diff --git a/zun/tests/tempest/__init__.py b/zun/tests/tempest/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/zun/tests/tempest/api/__init__.py b/zun/tests/tempest/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/zun/tests/tempest/api/clients.py b/zun/tests/tempest/api/clients.py deleted file mode 100644 index 45596e2eb..000000000 --- a/zun/tests/tempest/api/clients.py +++ /dev/null @@ -1,287 +0,0 @@ -# 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 contextlib -import sys - -from docker import errors as docker_errors -import six -from six.moves.urllib import parse -from tempest import config -from tempest.lib.common import rest_client -from tempest.lib.services.image.v2 import images_client -from tempest.lib.services.network import ports_client -from tempest.lib.services.network import security_groups_client -from tempest import manager - -from zun.common import exception -import zun.conf -from zun.container.docker import utils as docker_utils -from zun.tests.tempest.api.models import container_model -from zun.tests.tempest.api.models import service_model -from zun.tests.tempest import utils - -ZUN_CONF = zun.conf.CONF -CONF = config.CONF - - -class Manager(manager.Manager): - - def __init__(self, credentials=None, service=None): - super(Manager, self).__init__(credentials=credentials) - - self.images_client = images_client.ImagesClient( - self.auth_provider, 'image', CONF.identity.region) - self.ports_client = ports_client.PortsClient( - self.auth_provider, 'network', CONF.identity.region) - self.sgs_client = security_groups_client.SecurityGroupsClient( - self.auth_provider, 'network', CONF.identity.region) - self.container_client = ZunClient(self.auth_provider) - - -class ZunClient(rest_client.RestClient): - - def __init__(self, auth_provider): - super(ZunClient, self).__init__( - auth_provider=auth_provider, - service=CONF.container_management.catalog_type, - region=CONF.identity.region, - disable_ssl_certificate_validation=True - ) - - @classmethod - def deserialize(cls, resp, body, model_type): - return resp, model_type.from_json(body) - - @classmethod - def containers_uri(cls, params=None): - url = "/containers/" - if params: - url = cls.add_params(url, params) - return url - - @classmethod - def container_uri(cls, container_id, action=None, params=None): - """Construct container uri - - """ - url = None - if action is None: - url = "{0}/{1}".format(cls.containers_uri(), container_id) - else: - url = "{0}/{1}/{2}".format(cls.containers_uri(), container_id, - action) - - if params: - url = cls.add_params(url, params) - - return url - - @classmethod - def add_params(cls, url, params): - """add_params adds dict values (params) to url as query parameters - - :param url: base URL for the request - :param params: dict with var:val pairs to add as parameters to URL - :returns: url string - """ - url_parts = list(parse.urlparse(url)) - query = dict(parse.parse_qsl(url_parts[4])) - query.update(params) - url_parts[4] = parse.urlencode(query) - return parse.urlunparse(url_parts) - - @classmethod - def services_uri(cls): - url = "/services/" - return url - - def post_container(self, model, **kwargs): - """Makes POST /container request - - """ - resp, body = self.post( - self.containers_uri(), - body=model.to_json(), **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) - - def run_container(self, model, **kwargs): - resp, body = self.post( - self.containers_uri(params={'run': True}), - body=model.to_json(), **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) - - def get_container(self, container_id): - resp, body = self.get(self.container_uri(container_id)) - return self.deserialize(resp, body, container_model.ContainerEntity) - - def list_containers(self, **kwargs): - resp, body = self.get(self.containers_uri(), **kwargs) - return self.deserialize(resp, body, - container_model.ContainerCollection) - - def delete_container(self, container_id, params=None, **kwargs): - return self.delete( - self.container_uri(container_id, params=params), **kwargs) - - def commit_container(self, container_id, params=None, **kwargs): - return self.post( - self.container_uri(container_id, action='commit', params=params), - None, **kwargs) - - def start_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='start'), None, **kwargs) - - def stop_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='stop'), None, *kwargs) - - def pause_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='pause'), None, **kwargs) - - def unpause_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='unpause'), None, **kwargs) - - def kill_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='kill'), None, **kwargs) - - def reboot_container(self, container_id, **kwargs): - return self.post( - self.container_uri(container_id, action='reboot'), None, **kwargs) - - def exec_container(self, container_id, command, **kwargs): - return self.post( - self.container_uri(container_id, action='execute'), - '{"command": "%s"}' % command, **kwargs) - - def logs_container(self, container_id, **kwargs): - return self.get( - self.container_uri(container_id, action='logs'), None, **kwargs) - - def update_container(self, container_id, model, **kwargs): - resp, body = self.patch( - self.container_uri(container_id), body=model.to_json(), **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) - - def rename_container(self, container_id, model, **kwargs): - resp, body = self.post( - self.container_uri(container_id, action='rename'), - body=model.to_json(), **kwargs) - return self.deserialize(resp, body, container_model.ContainerEntity) - - def top_container(self, container_id, **kwargs): - return self.get( - self.container_uri(container_id, action='top'), None, **kwargs) - - def stats_container(self, container_id, **kwargs): - return self.get( - self.container_uri(container_id, action='stats'), None, **kwargs) - - def add_security_group(self, container_id, model, **kwargs): - return self.post( - self.container_uri(container_id, action='add_security_group'), - body=model.to_json(), **kwargs) - - def list_services(self, **kwargs): - resp, body = self.get(self.services_uri(), **kwargs) - return self.deserialize(resp, body, - service_model.ServiceCollection) - - def ensure_container_in_desired_state(self, container_id, status): - def is_container_in_desired_state(): - _, container = self.get_container(container_id) - if container.status == status: - return True - else: - return False - utils.wait_for_condition(is_container_in_desired_state) - - def ensure_container_deleted(self, container_id): - def is_container_deleted(): - _, model = self.list_containers() - container_ids = [c['uuid'] for c in model.containers] - if container_id in container_ids: - return False - else: - return True - utils.wait_for_condition(is_container_deleted) - - -@contextlib.contextmanager -def docker_client(docker_auth_url): - client_kwargs = dict() - if not ZUN_CONF.docker.api_insecure: - client_kwargs['ca_cert'] = CONF.docker.ca_file - client_kwargs['client_key'] = CONF.docker.key_file - client_kwargs['client_cert'] = CONF.docker.key_file - - try: - yield docker_utils.DockerHTTPClient( - docker_auth_url, - ZUN_CONF.docker.docker_remote_api_version, - ZUN_CONF.docker.default_timeout, - **client_kwargs - ) - except docker_errors.APIError as e: - desired_exc = exception.DockerError(error_msg=six.text_type(e)) - six.reraise(type(desired_exc), desired_exc, sys.exc_info()[2]) - - -class DockerClient(object): - - def get_container(self, container_id, - docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - for info in docker.list_instances(inspect=True): - if container_id in info['Name']: - return info - return None - - def ensure_container_pid_changed( - self, container_id, pid, - docker_auth_url=ZUN_CONF.docker.api_url): - def is_pid_changed(): - container = self.get_container(container_id, - docker_auth_url=docker_auth_url) - new_pid = container.get('State').get('Pid') - if pid != new_pid: - return True - else: - return False - utils.wait_for_condition(is_pid_changed) - - def pull_image( - self, repo, tag=None, - docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - docker.pull(repo, tag=tag) - - def get_image(self, name, docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - return docker.get_image(name) - - def delete_image(self, name, docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - return docker.remove_image(name) - - def list_networks(self, name, - docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - return docker.networks(names=[name]) - - def remove_network(self, name, - docker_auth_url=ZUN_CONF.docker.api_url): - with docker_client(docker_auth_url) as docker: - return docker.remove_network(name) diff --git a/zun/tests/tempest/api/common/__init__.py b/zun/tests/tempest/api/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/zun/tests/tempest/api/common/base_model.py b/zun/tests/tempest/api/common/base_model.py deleted file mode 100644 index b9b80365b..000000000 --- a/zun/tests/tempest/api/common/base_model.py +++ /dev/null @@ -1,70 +0,0 @@ -# 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. - -from oslo_serialization import jsonutils as json - - -class BaseModel(object): - """Superclass responsible for converting json data to/from model""" - - @classmethod - def from_json(cls, json_str): - return cls.from_dict(json.loads(json_str)) - - def to_json(self): - return json.dump_as_bytes(self.to_dict()) - - @classmethod - def from_dict(cls, data): - model = cls() - for key in data: - setattr(model, key, data.get(key)) - return model - - def to_dict(self): - result = {} - for key in self.__dict__: - result[key] = getattr(self, key) - if isinstance(result[key], BaseModel): - result[key] = result[key].to_dict() - return result - - def __str__(self): - return "%s" % self.to_dict() - - -class EntityModel(BaseModel): - """Superclass resposible from converting dict to instance of model""" - - @classmethod - def from_dict(cls, data): - model = super(EntityModel, cls).from_dict(data) - if hasattr(model, cls.ENTITY_NAME): - val = getattr(model, cls.ENTITY_NAME) - setattr(model, cls.ENTITY_NAME, cls.MODEL_TYPE.from_dict(val)) - return model - - -class CollectionModel(BaseModel): - """Superclass resposible from converting dict to list of models""" - - @classmethod - def from_dict(cls, data): - model = super(CollectionModel, cls).from_dict(data) - - collection = [] - if hasattr(model, cls.COLLECTION_NAME): - for d in getattr(model, cls.COLLECTION_NAME): - collection.append(cls.MODEL_TYPE.from_dict(d)) - setattr(model, cls.COLLECTION_NAME, collection) - - return model diff --git a/zun/tests/tempest/api/common/datagen.py b/zun/tests/tempest/api/common/datagen.py deleted file mode 100644 index e71d08038..000000000 --- a/zun/tests/tempest/api/common/datagen.py +++ /dev/null @@ -1,105 +0,0 @@ -# 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 random -import socket -import string -import struct - -from tempest.lib.common.utils import data_utils -from zun.tests.tempest.api.models import container_model - - -def random_int(min_int=1, max_int=100): - return random.randrange(min_int, max_int) - - -def gen_random_port(): - return random_int(49152, 65535) - - -def gen_docker_volume_size(min_int=3, max_int=5): - return random_int(min_int, max_int) - - -def gen_fake_ssh_pubkey(): - chars = "".join( - random.choice(string.ascii_uppercase + - string.ascii_letters + string.digits + '/+=') - for _ in range(372)) - return "ssh-rsa " + chars - - -def gen_random_ip(): - return socket.inet_ntoa(struct.pack('>I', random.randint(1, 0xffffffff))) - - -def gen_url(scheme="http", domain="example.com", port=80): - return "%s://%s:%s" % (scheme, domain, port) - - -def container_data(default_data=None, **kwargs): - if default_data is None: - default_data = { - 'name': data_utils.rand_name('container'), - 'image': 'cirros:latest', - 'command': 'sleep 10000', - 'cpu': 0.1, - 'memory': '100', - 'environment': {}, - 'labels': {}, - 'image_driver': 'docker', - 'image_pull_policy': 'always', - 'restart_policy': {'Name': 'no'}, - 'workdir': '/', - 'interactive': False, - 'security_groups': ['default'], - } - - default_data.update(kwargs) - model = container_model.ContainerEntity.from_dict(default_data) - - return model - - -def container_patch_data(**kwargs): - data = { - 'cpu': 0.2, - 'memory': '512', - } - - data.update(kwargs) - model = container_model.ContainerPatchEntity.from_dict(data) - - return model - - -def container_rename_data(**kwargs): - data = { - 'name': 'new_name', - } - - data.update(kwargs) - model = container_model.ContainerPatchEntity.from_dict(data) - - return model - - -def container_add_sg_data(**kwargs): - data = { - 'name': 'sg_name', - } - - data.update(kwargs) - model = container_model.ContainerPatchEntity.from_dict(data) - - return model diff --git a/zun/tests/tempest/api/models/__init__.py b/zun/tests/tempest/api/models/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/zun/tests/tempest/api/models/container_model.py b/zun/tests/tempest/api/models/container_model.py deleted file mode 100644 index ec246f46f..000000000 --- a/zun/tests/tempest/api/models/container_model.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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. - -from zun.tests.tempest.api.common import base_model - - -class ContainerData(base_model.BaseModel): - """Data that encapsulates container attributes""" - pass - - -class ContainerEntity(base_model.EntityModel): - """Entity Model that represents a single instance of ContainerData""" - ENTITY_NAME = 'container' - MODEL_TYPE = ContainerData - - -class ContainerCollection(base_model.CollectionModel): - """Collection Model that represents a list of ContainerData objects""" - COLLECTION_NAME = 'containerlists' - MODEL_TYPE = ContainerData - - -class ContainerPatchData(base_model.BaseModel): - """Data that encapsulates container update attributes""" - pass - - -class ContainerPatchEntity(base_model.EntityModel): - """Entity Model that represents a single instance of ContainerPatchData""" - ENTITY_NAME = 'containerpatch' - MODEL_TYPE = ContainerPatchData diff --git a/zun/tests/tempest/api/models/service_model.py b/zun/tests/tempest/api/models/service_model.py deleted file mode 100644 index 13ae608be..000000000 --- a/zun/tests/tempest/api/models/service_model.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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. - -from zun.tests.tempest.api.common import base_model - - -class ServiceData(base_model.BaseModel): - """Data that encapsulates service attributes""" - pass - - -class ServiceEntity(base_model.EntityModel): - """Entity Model that represents a single instance of ServiceData""" - ENTITY_NAME = 'service' - MODEL_TYPE = ServiceData - - -class ServiceCollection(base_model.CollectionModel): - """Collection Model that represents a list of ServiceData objects""" - COLLECTION_NAME = 'servicelists' - MODEL_TYPE = ServiceData diff --git a/zun/tests/tempest/api/test_containers.py b/zun/tests/tempest/api/test_containers.py deleted file mode 100644 index 5b49b216a..000000000 --- a/zun/tests/tempest/api/test_containers.py +++ /dev/null @@ -1,511 +0,0 @@ -# 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. - -from oslo_utils import encodeutils -from tempest.lib import decorators - -from zun.tests.tempest.api import clients -from zun.tests.tempest.api.common import datagen -from zun.tests.tempest import base -from zun.tests.tempest import utils - - -class TestContainer(base.BaseZunTest): - - @classmethod - def get_client_manager(cls, credential_type=None, roles=None, - force_new=None): - manager = super(TestContainer, cls).get_client_manager( - credential_type=credential_type, - roles=roles, - force_new=force_new - ) - return clients.Manager(manager.credentials) - - @classmethod - def setup_clients(cls): - super(TestContainer, cls).setup_clients() - cls.container_client = cls.os_primary.container_client - cls.docker_client = clients.DockerClient() - cls.images_client = cls.os_primary.images_client - cls.ports_client = cls.os_primary.ports_client - cls.sgs_client = cls.os_primary.sgs_client - - @classmethod - def resource_setup(cls): - super(TestContainer, cls).resource_setup() - - def setUp(self): - super(TestContainer, self).setUp() - self.containers = [] - - def tearDown(self): - hosts = [] - _, model = self.container_client.list_containers() - for c in model.containers: - if c['uuid'] in self.containers: - if c['host'] and c['host'] not in hosts: - hosts.append(c['host']) - self.container_client.delete_container(c['uuid'], - params={'force': True}) - self.container_client.ensure_container_deleted(c['uuid']) - - # cleanup the network resources - project_id = self.container_client.tenant_id - for host in hosts: - # NOTE(kiennt): Default docker remote url - # Remove networks in all hosts - docker_base_url = self._get_docker_url(host) - networks = self.docker_client.list_networks(project_id, - docker_base_url) - for network in networks: - self.docker_client.remove_network(network['Id'], - docker_base_url) - - super(TestContainer, self).tearDown() - - @decorators.idempotent_id('b8946b8c-57d5-4fdc-a09a-001d6b552725') - def test_create_container(self): - self._create_container() - - @decorators.idempotent_id('b3e307d4-844b-4a57-8c60-8fb3f57aea7c') - def test_list_containers(self): - _, container = self._create_container() - resp, model = self.container_client.list_containers() - self.assertEqual(200, resp.status) - self.assertGreater(len(model.containers), 0) - self.assertIn( - container.uuid, - list([c['uuid'] for c in model.containers])) - - @decorators.idempotent_id('0dd13c28-c5ff-4b9e-b73b-61185b410de4') - def test_get_container(self): - _, container = self._create_container() - resp, model = self.container_client.get_container(container.uuid) - self.assertEqual(200, resp.status) - self.assertEqual(container.uuid, model.uuid) - - @decorators.idempotent_id('cef53a56-22b7-4808-b01c-06b2b7126115') - def test_delete_container(self): - _, container = self._create_container() - self._delete_container(container.uuid, container.host, True) - - @decorators.idempotent_id('ef69c9e7-0ce0-4e14-b7ec-c1dc581a3927') - def test_run_container(self): - self._run_container() - - @decorators.idempotent_id('a2152d78-b6a6-4f47-8767-d83d29c6fb19') - def test_run_container_with_minimal_params(self): - gen_model = datagen.container_data({'image': 'nginx'}) - self._run_container(gen_model=gen_model) - - @decorators.idempotent_id('c32f93e3-da88-4c13-be38-25d2e662a28e') - def test_run_container_with_image_driver_glance(self): - image = None - try: - docker_base_url = self._get_docker_url() - self.docker_client.pull_image( - 'cirros', docker_auth_url=docker_base_url) - image_data = self.docker_client.get_image( - 'cirros', docker_base_url) - image = self.images_client.create_image( - name='cirros', disk_format='raw', container_format='docker') - self.images_client.store_image_file(image['id'], image_data) - # delete the local image that was previously pulled down - self.docker_client.delete_image('cirros', docker_base_url) - - _, model = self._run_container( - image='cirros', image_driver='glance') - finally: - if image: - try: - self.images_client.delete_image(image['id']) - except Exception: - pass - - @decorators.idempotent_id('b70bedbc-5ba2-400c-8f5f-0cf05ca17151') - def test_run_container_with_environment(self): - _, model = self._run_container(environment={ - 'key1': 'env1', 'key2': 'env2'}) - - container = self.docker_client.get_container( - model.uuid, - self._get_docker_url(model.host)) - env = container.get('Config').get('Env') - self.assertTrue('key1=env1', env) - self.assertTrue('key2=env2', env) - - @decorators.idempotent_id('0e59d549-58ff-440f-8704-10e223c31cbc') - def test_run_container_with_labels(self): - _, model = self._run_container(labels={ - 'key1': 'label1', 'key2': 'label2'}) - - container = self.docker_client.get_container( - model.uuid, - self._get_docker_url(model.host)) - labels = container.get('Config').get('Labels') - self.assertTrue('key1=label1', labels) - self.assertTrue('key2=label2', labels) - - @decorators.idempotent_id('9fc7fec0-e1a9-4f65-a5a6-dba425c1607c') - def test_run_container_with_restart_policy(self): - _, model = self._run_container(restart_policy={ - 'Name': 'on-failure', 'MaximumRetryCount': 2}) - - container = self.docker_client.get_container( - model.uuid, - self._get_docker_url(model.host)) - policy = container.get('HostConfig').get('RestartPolicy') - self.assertEqual('on-failure', policy['Name']) - self.assertTrue(2, policy['MaximumRetryCount']) - - @decorators.idempotent_id('58585a4f-cdce-4dbd-9741-4416d1098f94') - def test_run_container_with_interactive(self): - _, model = self._run_container(interactive=True) - - container = self.docker_client.get_container( - model.uuid, - self._get_docker_url(model.host)) - tty = container.get('Config').get('Tty') - stdin_open = container.get('Config').get('OpenStdin') - self.assertIs(True, tty) - self.assertIs(True, stdin_open) - - @decorators.idempotent_id('f181eeda-a9d1-4b2e-9746-d6634ca81e2f') - def test_run_container_without_security_groups(self): - gen_model = datagen.container_data() - delattr(gen_model, 'security_groups') - _, model = self._run_container(gen_model=gen_model) - sgs = self._get_all_security_groups(model) - self.assertEqual(1, len(sgs)) - self.assertEqual('default', sgs[0]) - - @decorators.idempotent_id('f181eeda-a9d1-4b2e-9746-d6634ca81e2f') - def test_run_container_with_security_groups(self): - sg_name = 'test_sg' - self.sgs_client.create_security_group(name=sg_name) - _, model = self._run_container(security_groups=[sg_name]) - sgs = self._get_all_security_groups(model) - self.assertEqual(1, len(sgs)) - self.assertEqual(sg_name, sgs[0]) - - @decorators.idempotent_id('c3f02fa0-fdfb-49fc-95e2-6e4dc982f9be') - def test_commit_container(self): - """Test container snapshot - - This test does the following: - 1. Create a container - 2. Create and write to a file inside the container - 3. Commit the container and upload the snapshot to Glance - 4. Create another container from the snapshot image - 5. Verify the pre-created file is there - """ - # This command creates a file inside the container - command = "/bin/sh -c 'echo hello > testfile;sleep 1000000'" - _, model = self._run_container(command=command) - - try: - resp, _ = self.container_client.commit_container( - model.uuid, params={'repository': 'myrepo'}) - self.assertEqual(202, resp.status) - self._ensure_image_active('myrepo') - - # This command outputs the content of pre-created file - command = "/bin/sh -c 'cat testfile;sleep 1000000'" - _, model = self._run_container( - image="myrepo", image_driver="glance", command=command) - resp, body = self.container_client.logs_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertTrue('hello' in encodeutils.safe_decode(body)) - finally: - try: - response = self.images_client.list_images() - for image in response['images']: - if (image['name'] == 'myrepo' and - image['container_format'] == 'docker'): - self.images_client.delete_image(image['id']) - except Exception: - pass - - def _ensure_image_active(self, image_name): - def is_image_in_desired_state(): - response = self.images_client.list_images() - for image in response['images']: - if (image['name'] == image_name and - image['container_format'] == 'docker' and - image['status'] == 'active'): - return True - - return False - - utils.wait_for_condition(is_image_in_desired_state) - - @decorators.idempotent_id('3fa024ef-aba1-48fe-9682-0d6b7854faa3') - def test_start_stop_container(self): - _, model = self._run_container() - - resp, _ = self.container_client.stop_container(model.uuid) - self.assertEqual(202, resp.status) - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Stopped') - self.assertEqual('Stopped', - self._get_container_state(model.uuid, model.host)) - - resp, _ = self.container_client.start_container(model.uuid) - self.assertEqual(202, resp.status) - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Running') - self.assertEqual('Running', - self._get_container_state(model.uuid, model.host)) - - @decorators.idempotent_id('b5f39756-8898-4e0e-a48b-dda0a06b66b6') - def test_pause_unpause_container(self): - _, model = self._run_container() - - resp, _ = self.container_client.pause_container(model.uuid) - self.assertEqual(202, resp.status) - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Paused') - self.assertEqual('Paused', - self._get_container_state(model.uuid, model.host)) - - resp, _ = self.container_client.unpause_container(model.uuid) - self.assertEqual(202, resp.status) - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Running') - self.assertEqual('Running', - self._get_container_state(model.uuid, model.host)) - - @decorators.idempotent_id('6179a588-3d48-4372-9599-f228411d1449') - def test_kill_container(self): - _, model = self._run_container() - - resp, _ = self.container_client.kill_container(model.uuid) - self.assertEqual(202, resp.status) - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Stopped') - self.assertEqual('Stopped', - self._get_container_state(model.uuid, model.host)) - - @decorators.idempotent_id('c2e54321-0a70-4331-ba62-9dcaa75ac250') - def test_reboot_container(self): - _, model = self._run_container() - docker_base_url = self._get_docker_url(model.host) - container = self.docker_client.get_container(model.uuid, - docker_base_url) - pid = container.get('State').get('Pid') - - resp, _ = self.container_client.reboot_container(model.uuid) - self.assertEqual(202, resp.status) - self.docker_client.ensure_container_pid_changed(model.uuid, pid, - docker_base_url) - self.assertEqual('Running', - self._get_container_state(model.uuid, model.host)) - # assert pid is changed - container = self.docker_client.get_container(model.uuid, - docker_base_url) - self.assertNotEqual(pid, container.get('State').get('Pid')) - - @decorators.idempotent_id('8a591ff8-6793-427f-82a6-e3921d8b4f81') - def test_exec_container(self): - _, model = self._run_container() - resp, body = self.container_client.exec_container(model.uuid, - command='echo hello') - self.assertEqual(200, resp.status) - self.assertTrue('hello' in encodeutils.safe_decode(body)) - - @decorators.idempotent_id('a912ca23-14e7-442f-ab15-e05aaa315204') - def test_logs_container(self): - _, model = self._run_container( - command="/bin/sh -c 'echo hello;sleep 1000000'") - resp, body = self.container_client.logs_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertTrue('hello' in encodeutils.safe_decode(body)) - - @decorators.idempotent_id('d383f359-3ebd-40ef-9dc5-d36922790230') - def test_update_container(self): - _, model = self._run_container(cpu=0.1, memory=100) - self.assertEqual('100M', model.memory) - self.assertEqual(0.1, model.cpu) - docker_base_url = self._get_docker_url(model.host) - container = self.docker_client.get_container(model.uuid, - docker_base_url) - self._assert_resource_constraints(container, cpu=0.1, memory=100) - - gen_model = datagen.container_patch_data(cpu=0.2, memory=200) - resp, model = self.container_client.update_container(model.uuid, - gen_model) - self.assertEqual(200, resp.status) - self.assertEqual('200M', model.memory) - self.assertEqual(0.2, model.cpu) - container = self.docker_client.get_container(model.uuid, - docker_base_url) - self._assert_resource_constraints(container, cpu=0.2, memory=200) - - @decorators.idempotent_id('b218bea7-f19b-499f-9819-c7021ffc59f4') - def test_rename_container(self): - _, model = self._run_container(name='container1') - self.assertEqual('container1', model.name) - gen_model = datagen.container_rename_data(name='container2') - resp, model = self.container_client.rename_container(model.uuid, - gen_model) - self.assertEqual(200, resp.status) - self.assertEqual('container2', model.name) - - @decorators.idempotent_id('142b7716-0b21-41ed-b47d-a42fba75636b') - def test_top_container(self): - _, model = self._run_container( - command="/bin/sh -c 'sleep 1000000'") - resp, body = self.container_client.top_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertTrue('sleep 1000000' in encodeutils.safe_decode(body)) - - @decorators.idempotent_id('09638306-b501-4803-aafa-7e8025632cef') - def test_stats_container(self): - _, model = self._run_container() - resp, body = self.container_client.stats_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertTrue('NET I/O(B)' in encodeutils.safe_decode(body)) - self.assertTrue('CONTAINER' in encodeutils.safe_decode(body)) - self.assertTrue('MEM LIMIT(MiB)' in encodeutils.safe_decode(body)) - self.assertTrue('CPU %' in encodeutils.safe_decode(body)) - self.assertTrue('MEM USAGE(MiB)' in encodeutils.safe_decode(body)) - self.assertTrue('MEM %' in encodeutils.safe_decode(body)) - self.assertTrue('BLOCK I/O(B)' in encodeutils.safe_decode(body)) - - @decorators.idempotent_id('b3b9cf17-82ad-4c1b-a4af-8210a778a33e') - def test_add_sg_to_container(self): - _, model = self._run_container() - sgs = self._get_all_security_groups(model) - self.assertEqual(1, len(sgs)) - self.assertEqual('default', sgs[0]) - - sg_name = 'test_add_sg' - self.sgs_client.create_security_group(name=sg_name) - gen_model = datagen.container_add_sg_data(name=sg_name) - resp, body = self.container_client.add_security_group( - model.uuid, gen_model) - self.assertEqual(202, resp.status) - - def assert_security_group_is_added(): - sgs = self._get_all_security_groups(model) - if len(sgs) == 2: - self.assertTrue('default' in sgs) - self.assertTrue(sg_name in sgs) - return True - else: - return False - - utils.wait_for_condition(assert_security_group_is_added) - - def _assert_resource_constraints(self, container, cpu=None, memory=None): - if cpu is not None: - cpu_quota = container.get('HostConfig').get('CpuQuota') - self.assertEqual(int(cpu * 100000), cpu_quota) - cpu_period = container.get('HostConfig').get('CpuPeriod') - self.assertEqual(100000, cpu_period) - if memory is not None: - docker_memory = container.get('HostConfig').get('Memory') - self.assertEqual(memory * 1024 * 1024, docker_memory) - - def _create_container(self, **kwargs): - gen_model = datagen.container_data(**kwargs) - resp, model = self.container_client.post_container(gen_model) - self.containers.append(model.uuid) - self.assertEqual(202, resp.status) - # Wait for container to finish creation - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Created') - - # Assert the container is created - resp, model = self.container_client.get_container(model.uuid) - self.assertEqual(200, resp.status) - self.assertEqual('Created', model.status) - self.assertEqual('Created', self._get_container_state(model.uuid, - model.host)) - return resp, model - - def _run_container(self, gen_model=None, **kwargs): - if gen_model is None: - gen_model = datagen.container_data(**kwargs) - resp, model = self.container_client.run_container(gen_model) - self.containers.append(model.uuid) - self.assertEqual(202, resp.status) - # Wait for container to started - self.container_client.ensure_container_in_desired_state( - model.uuid, 'Running') - - # Assert the container is started - resp, model = self.container_client.get_container(model.uuid) - self.assertEqual('Running', model.status) - self.assertEqual('Running', self._get_container_state(model.uuid, - model.host)) - self.assertIsNotNone(model.host) - return resp, model - - def _delete_container(self, container_id, container_host, force=False): - resp, _ = self.container_client.delete_container( - container_id, params={'force': force}) - self.assertEqual(204, resp.status) - self.container_client.ensure_container_deleted(container_id) - container = self.docker_client.get_container( - container_id, self._get_docker_url(container_host)) - self.assertIsNone(container) - - def _get_container_state(self, container_id, docker_host=None): - if docker_host is not None: - container = self.docker_client.get_container( - container_id, self._get_docker_url(docker_host)) - else: - container = self.docker_client.get_container(container_id) - status = container.get('State') - if status.get('Error') is True: - return 'Error' - elif status.get('Paused'): - return 'Paused' - elif status.get('Running'): - return 'Running' - elif status.get('Status') == 'created': - return 'Created' - else: - return 'Stopped' - - def _get_all_security_groups(self, container): - # find all neutron ports of this container - port_ids = set() - for addrs_list in container.addresses.values(): - for addr in addrs_list: - port_id = addr['port'] - port_ids.add(port_id) - - # find all security groups of this container - sg_ids = set() - for port_id in port_ids: - port = self.ports_client.show_port(port_id) - for sg in port['port']['security_groups']: - sg_ids.add(sg) - - sg_names = [] - for sg_id in sg_ids: - sg = self.sgs_client.show_security_group(sg_id) - sg_names.append(sg['security_group']['name']) - - return sg_names - - def _get_docker_url(self, host='localhost', protocol='tcp', port='2375'): - # NOTE(kiennt): By default, devstack-plugin-container will - # set docker_api_url = { - # "unix://$DOCKER_ENGINE_SOCKET_FILE", - # "tcp://0.0.0.0:$DOCKER_ENGINE_PORT" - # } - base_url = '{}://{}:{}' . format(protocol, host, port) - return base_url diff --git a/zun/tests/tempest/api/test_services.py b/zun/tests/tempest/api/test_services.py deleted file mode 100644 index 0d54e2552..000000000 --- a/zun/tests/tempest/api/test_services.py +++ /dev/null @@ -1,50 +0,0 @@ -# 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. - -from tempest.lib import decorators -from tempest.lib import exceptions - -from zun.tests.tempest.api import clients -from zun.tests.tempest import base - - -class TestService(base.BaseZunTest): - - @classmethod - def get_client_manager(cls, credential_type=None, roles=None, - force_new=None): - - manager = super(TestService, cls).get_client_manager( - credential_type=credential_type, - roles=roles, - force_new=force_new - ) - return clients.Manager(manager.credentials) - - @classmethod - def setup_clients(cls): - - super(TestService, cls).setup_clients() - cls.container_client = cls.os_primary.container_client - - @classmethod - def resource_setup(cls): - - super(TestService, cls).resource_setup() - - # TODO(pksingh): currently functional test doesn't support - # policy, will write another test after - # implementing policy in functional tests - @decorators.idempotent_id('a04f61f2-15ae-4200-83b7-1f311b101f36') - def test_service_list(self): - self.assertRaises(exceptions.Forbidden, - self.container_client.list_services) diff --git a/zun/tests/tempest/base.py b/zun/tests/tempest/base.py deleted file mode 100644 index 2d0233758..000000000 --- a/zun/tests/tempest/base.py +++ /dev/null @@ -1,35 +0,0 @@ -# -# 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. - -from tempest import config -from tempest import test - -CONF = config.CONF - - -class BaseZunTest(test.BaseTestCase): - - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseZunTest, cls).skip_checks() - if not CONF.service_available.zun: - skip_msg = 'Zun is disabled' - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(BaseZunTest, cls).setup_clients() - pass diff --git a/zun/tests/tempest/config.py b/zun/tests/tempest/config.py deleted file mode 100644 index 4da5f1574..000000000 --- a/zun/tests/tempest/config.py +++ /dev/null @@ -1,31 +0,0 @@ -# -# 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. - -from oslo_config import cfg - -service_option = cfg.BoolOpt("zun", - default=True, - help="Whether or not zun is expected to be " - "available") - -container_management_group = cfg.OptGroup( - name="container_management", title="Container Management Service Options") - -ContainerManagementGroup = [ - cfg.StrOpt("catalog_type", - default="container", - help="Catalog type of the container management service."), - cfg.IntOpt("wait_timeout", - default=60, - help="Waiting time for a specific status, in seconds.") -] diff --git a/zun/tests/tempest/plugin.py b/zun/tests/tempest/plugin.py deleted file mode 100644 index 677d7989e..000000000 --- a/zun/tests/tempest/plugin.py +++ /dev/null @@ -1,41 +0,0 @@ -# -# 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 os - -from tempest.test_discover import plugins - -from zun.tests.tempest import config as config_zun - - -class ZunTempestPlugin(plugins.TempestPlugin): - def load_tests(self): - base_path = os.path.split(os.path.dirname( - os.path.abspath(__file__)))[0] - base_path += '/../..' - test_dir = "zun/tests/tempest" - full_test_dir = os.path.join(base_path, test_dir) - return full_test_dir, base_path - - def register_opts(self, conf): - conf.register_opt(config_zun.service_option, - group='service_available') - conf.register_group(config_zun.container_management_group) - conf.register_opts(config_zun.ContainerManagementGroup, - group='container_management') - - def get_opt_lists(self): - return [(config_zun.container_management_group.name, - config_zun.ContainerManagementGroup), - ('service_available', [config_zun.service_option])] diff --git a/zun/tests/tempest/utils.py b/zun/tests/tempest/utils.py deleted file mode 100644 index dd6498901..000000000 --- a/zun/tests/tempest/utils.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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 - - -def wait_for_condition(condition, interval=2, timeout=60): - start_time = time.time() - end_time = time.time() + timeout - while time.time() < end_time: - result = condition() - if result: - return result - time.sleep(interval) - raise Exception(("Timed out after %s seconds. Started on %s and ended " - "on %s") % (timeout, start_time, end_time))