zun-tempest-plugin/zun_tempest_plugin/tests/tempest/api/clients.py

458 lines
17 KiB
Python

# 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 docker
from six.moves.urllib import parse
from tempest.common import credentials_factory as common_creds
from tempest import config
from tempest.lib.common import api_version_utils
from tempest.lib.common import rest_client
from tempest.lib.services.image.v2 import images_client
from tempest.lib.services.network import networks_client
from tempest.lib.services.network import ports_client
from tempest.lib.services.network import security_groups_client
from tempest.lib.services.network import subnetpools_client
from tempest.lib.services.network import subnets_client
from tempest.lib.services.volume.v3 import volumes_client
from tempest import manager
from zun_tempest_plugin.tests.tempest.api.models import capsule_model
from zun_tempest_plugin.tests.tempest.api.models import container_model
from zun_tempest_plugin.tests.tempest.api.models import service_model
from zun_tempest_plugin.tests.tempest import utils
CONF = config.CONF
ADMIN_CREDS = None
CONTAINER_SERVICE_MICROVERSION = None
def get_container_service_api_version():
"""Get zun-api-version with format: 'container X.Y'"""
return 'container ' + CONTAINER_SERVICE_MICROVERSION
def set_container_service_api_microversion(
container_service_microversion):
global CONTAINER_SERVICE_MICROVERSION
CONTAINER_SERVICE_MICROVERSION = container_service_microversion
def reset_container_service_api_microversion():
global CONTAINER_SERVICE_MICROVERSION
CONTAINER_SERVICE_MICROVERSION = None
class Manager(manager.Manager):
def __init__(self, credentials=None):
"""Initialization of Manager class.
Setup service client and make it available for test cases.
:param credentials: type Credentials or TestResources
"""
if credentials is None:
global ADMIN_CREDS
if ADMIN_CREDS is None:
ADMIN_CREDS = common_creds.get_configured_admin_credentials()
credentials = ADMIN_CREDS
super(Manager, self).__init__(credentials=credentials)
self.images_client = images_client.ImagesClient(
self.auth_provider, 'image', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.ports_client = ports_client.PortsClient(
self.auth_provider, 'network', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.sgs_client = security_groups_client.SecurityGroupsClient(
self.auth_provider, 'network', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.vol_client = volumes_client.VolumesClient(
self.auth_provider, 'volumev3', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.container_client = ZunClient(self.auth_provider)
self.neutron_client = networks_client.NetworksClient(
self.auth_provider, 'network', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.subnets_client = subnets_client.SubnetsClient(
self.auth_provider, 'network', CONF.identity.region,
disable_ssl_certificate_validation=True)
self.subnetpools_client = subnetpools_client.SubnetpoolsClient(
self.auth_provider, 'network', CONF.identity.region,
disable_ssl_certificate_validation=True)
class ZunClient(rest_client.RestClient):
""""Base Tempest REST client for Zun API."""
api_microversion_header_name = 'OpenStack-API-Version'
def __init__(self, auth_provider):
super(ZunClient, self).__init__(
auth_provider=auth_provider,
service=CONF.container_service.catalog_type,
region=CONF.identity.region,
disable_ssl_certificate_validation=True
)
def get_headers(self):
headers = super(ZunClient, self).get_headers()
if CONTAINER_SERVICE_MICROVERSION:
headers[self.api_microversion_header_name] = \
get_container_service_api_version()
return headers
def request(self, *args, **kwargs):
resp, resp_body = super(ZunClient, self).request(*args, **kwargs)
if (CONTAINER_SERVICE_MICROVERSION and
CONTAINER_SERVICE_MICROVERSION
!= api_version_utils.LATEST_MICROVERSION):
api_version_utils.assert_version_header_matches_request(
self.api_microversion_header_name,
get_container_service_api_version(),
resp)
return resp, resp_body
@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
def container_action_uri(cls, container_id, request_id):
url = "/containers/{0}/container_actions/{1}".format(
container_id, request_id)
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
@classmethod
def capsules_uri(cls):
url = "/capsules/"
return url
@classmethod
def capsule_uri(cls, capsule_id, params=None):
"""Construct capsule uri
"""
url = "{0}/{1}".format(cls.capsules_uri(), capsule_id)
if params:
url = cls.add_params(url, params)
return url
@classmethod
def networks_uri(cls):
url = "/networks/"
return url
@classmethod
def network_uri(cls, network_id, params=None):
url = "{0}/{1}".format(cls.networks_uri(), network_id)
if params:
url = cls.add_params(url, params)
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, params=None):
resp, body = self.get(self.container_uri(container_id, params=params))
return self.deserialize(resp, body, container_model.ContainerEntity)
def list_containers(self, params=None, **kwargs):
resp, body = self.get(self.containers_uri(params=params), **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 rebuild_container(self, container_id, **kwargs):
return self.post(
self.container_uri(container_id, action='rebuild'), 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 remove_security_group(self, container_id, model, **kwargs):
return self.post(
self.container_uri(container_id, action='remove_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 get_container_action(self, container_id, request_id):
resp, body = self.get(
self.container_action_uri(container_id, request_id))
return self.deserialize(
resp, body, container_model.ContainerActionEntity)
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, timeout=120)
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)
def ensure_action_finished(self, container_id, request_id):
def is_action_finished():
_, action = self.get_container_action(container_id, request_id)
if action.finish_time is not None:
return True
else:
return False
utils.wait_for_condition(is_action_finished, timeout=120)
def network_attach(self, container_id, params=None, **kwargs):
return self.post(
self.container_uri(container_id, action='network_attach',
params=params),
None, **kwargs)
def network_detach(self, container_id, params=None, **kwargs):
return self.post(
self.container_uri(container_id, action='network_detach',
params=params),
None, **kwargs)
def put_archive(self, container_id, params=None, **kwargs):
return self.post(
self.container_uri(container_id, action='put_archive',
params=params), **kwargs)
def get_archive(self, container_id, params=None, **kwargs):
return self.get(
self.container_uri(container_id, action='get_archive',
params=params), None, **kwargs)
def post_capsule(self, model, **kwargs):
"""Makes POST /capsules request
"""
resp, body = self.post(
self.capsules_uri(),
body=model.to_json(), **kwargs)
return self.deserialize(resp, body, capsule_model.CapsuleEntity)
def ensure_capsule_in_desired_state(self, capsule_id, status):
def is_capsule_in_desired_state():
_, capsule = self.get_capsule(capsule_id)
if capsule.status == status:
return True
else:
return False
utils.wait_for_condition(is_capsule_in_desired_state, timeout=120)
def list_capsules(self, **kwargs):
resp, body = self.get(self.capsules_uri(), **kwargs)
return self.deserialize(resp, body, capsule_model.CapsuleEntity)
def get_capsule(self, capsule_id, params=None):
resp, body = self.get(self.capsule_uri(capsule_id, params=params))
return self.deserialize(resp, body, capsule_model.CapsuleEntity)
def delete_capsule(self, capsule_id, params=None):
return self.delete(self.capsule_uri(capsule_id, params=params))
def ensure_capsule_deleted(self, capsule_id):
def is_capsule_deleted():
_, model = self.list_capsules()
capsule_ids = [c['uuid'] for c in model.capsules]
if capsule_id in capsule_ids:
return False
else:
return True
utils.wait_for_condition(is_capsule_deleted)
def delete_network(self, network_id, params=None):
return self.delete(self.network_uri(network_id, params=params))
@contextlib.contextmanager
def docker_client(docker_auth_url):
yield DockerHTTPClient(
docker_auth_url,
CONF.docker.docker_remote_api_version,
CONF.docker.default_timeout
)
class DockerHTTPClient(docker.APIClient):
def __init__(self, url=CONF.docker.api_url,
ver=CONF.docker.docker_remote_api_version,
timeout=CONF.docker.default_timeout):
super(DockerHTTPClient, self).__init__(
base_url=url,
version=ver,
timeout=timeout,
tls=False
)
class DockerClient(object):
def pull_image(
self, repo, tag=None,
docker_auth_url=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=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=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=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=CONF.docker.api_url):
with docker_client(docker_auth_url) as docker:
return docker.remove_network(name)