# 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 functools import partial from oslo_utils import uuidutils from karbor.common import constants from karbor.tests.fullstack import karbor_base as base from karbor.tests.fullstack import utils SHORT_TIMEOUT = 150 MEDIUM_TIMEOUT = 450 LONG_TIMEOUT = 900 SHORT_SLEEP = 3 MEDIUM_SLEEP = 15 LONG_SLEEP = 30 HUGE_SLEEP = 100 DEFAULT_FLAVOR = "cirros256" DEFAULT_NETWORK = "private" class Checkpoint(object): def __init__(self): super(Checkpoint, self).__init__() self.id = None self._provider_id = None self.karbor_client = base._get_karbor_client() def _checkpoint_status(self, status=None): try: cp = self.karbor_client.checkpoints.get(self._provider_id, self.id) except Exception: return False if status is None or cp.status == status: return True else: return False def create(self, provider_id, plan_id, timeout=LONG_TIMEOUT): self._provider_id = provider_id checkpoint = self.karbor_client.checkpoints.create(provider_id, plan_id) self.id = checkpoint.id utils.wait_until_true(partial(self._checkpoint_status, constants.CHECKPOINT_STATUS_AVAILABLE), timeout=timeout, sleep=HUGE_SLEEP) return self.id def close(self, timeout=MEDIUM_TIMEOUT): try: self.karbor_client.checkpoints.delete(self._provider_id, self.id) except Exception: return utils.wait_until_true(partial(self._checkpoint_status, constants.CHECKPOINT_STATUS_DELETED), timeout=timeout, sleep=LONG_SLEEP) class Plan(object): _name_id = 0 def __init__(self): super(Plan, self).__init__() self.id = None self.karbor_client = base._get_karbor_client() def create(self, provider_id, resources, parameters={}, name=None): def _transform_resource(resource): if isinstance(resource, dict): return resource if hasattr(resource, 'to_dict') and callable(resource.to_dict): return resource.to_dict() if name is None: name = "KarborFullstack-Plan-{id}".format( id=self.__class__._name_id ) self.__class__._name_id += 1 resources = map(_transform_resource, resources) plan = self.karbor_client.plans.create(name, provider_id, resources, parameters) self.id = plan.id return self.id def update(self, data): return self.karbor_client.plans.update(self.id, data) def close(self): try: self.karbor_client.plans.delete(self.id) except Exception: return class Restore(object): def __init__(self): super(Restore, self).__init__() self.id = None self.karbor_client = base._get_karbor_client() def _restore_status(self, status=None): try: restore = self.karbor_client.restores.get(self.id) except Exception: return False if status is None or restore.status == status: return True else: return False def create(self, provider_id, checkpoint_id, target, parameters, restore_auth, timeout=LONG_TIMEOUT): restore = self.karbor_client.restores.create(provider_id, checkpoint_id, target, parameters, restore_auth) self.id = restore.id utils.wait_until_true(partial(self._restore_status, 'success'), timeout=timeout, sleep=HUGE_SLEEP) return self.id def close(self): pass class Trigger(object): _name_id = 0 def __init__(self): super(Trigger, self).__init__() self.id = None self.karbor_client = base._get_karbor_client() def create(self, type, properties, name=None): if name is None: name = "KarborFullstack-Trigger-{id}".format( id=self.__class__._name_id ) self.__class__._name_id += 1 trigger = self.karbor_client.triggers.create(name, type, properties) self.id = trigger.id return self.id def close(self): try: self.karbor_client.triggers.delete(self.id) except Exception: return class ScheduledOperation(object): _name_id = 0 def __init__(self): super(ScheduledOperation, self).__init__() self.id = None self.karbor_client = base._get_karbor_client() def create(self, operation_type, trigger_id, operation_definition, name=None): if name is None: name = "KarborFullstack-Scheduled-Operation-{id}".format( id=self.__class__._name_id ) self.__class__._name_id += 1 scheduled_operation = self.karbor_client.scheduled_operations.create( name, operation_type, trigger_id, operation_definition ) self.id = scheduled_operation.id return self.id def close(self): try: self.karbor_client.scheduled_operations.delete(self.id) except Exception: return class Server(object): _name_id = 0 def __init__(self): super(Server, self).__init__() self.id = None self._name = None self.nova_client = base._get_nova_client() self.neutron_client = base._get_neutron_client() self.cinder_client = base._get_cinder_client() self.glance_client = base._get_glance_client() def _server_status(self, status=None): try: server = self.nova_client.servers.get(self.id) except Exception: return False if status is None or status == server.status: return True else: return False def to_dict(self): return { "id": self.id, "type": constants.SERVER_RESOURCE_TYPE, "name": self._name, } def create(self, name=None, image=None, volume=None, flavor=DEFAULT_FLAVOR, network=DEFAULT_NETWORK, timeout=LONG_TIMEOUT): block_device_mapping_v2 = None if volume: block_device_mapping_v2 = [{ 'uuid': volume, 'source_type': 'volume', 'destination_type': 'volume', 'boot_index': 0, 'delete_on_termination': False}] else: if not image: images = self.glance_client.images.list() for image_iter in images: if image_iter['disk_format'] not in ('aki', 'ari') and ( image_iter['name'].startswith('cirros')): image = image_iter['id'] break assert image flavor = self.nova_client.flavors.find(name=flavor) if name is None: name = "KarborFullstack-Server-{id}".format( id=self.__class__._name_id ) self.__class__._name_id += 1 self._name = name networks = self.neutron_client.list_networks(name=network) assert len(networks['networks']) > 0 network_id = networks['networks'][0]['id'] server = self.nova_client.servers.create( name=name, image=image, block_device_mapping_v2=block_device_mapping_v2, flavor=flavor, nics=[{"net-id": network_id}], ) self.id = server.id utils.wait_until_true(partial(self._server_status, 'ACTIVE'), timeout=timeout, sleep=MEDIUM_SLEEP) return self.id def _volume_attached(self, volume_id): volume_item = self.cinder_client.volumes.get(volume_id) server_attachments = filter(lambda x: x['server_id'] == self.id, volume_item.attachments) if len(server_attachments) > 0: return True else: return False def attach_volume(self, volume_id, timeout=MEDIUM_TIMEOUT): self.nova_client.volumes.create_server_volume(self.id, volume_id) utils.wait_until_true(partial(self._volume_attached, volume_id), timeout=timeout, sleep=SHORT_SLEEP) def _volume_detached(self, volume_id): volume_item = self.cinder_client.volumes.get(volume_id) server_attachments = filter(lambda x: x['server_id'] == self.id, volume_item.attachments) if len(server_attachments) > 0: return False else: return True def detach_volume(self, volume_id, timeout=MEDIUM_TIMEOUT): self.nova_client.volumes.delete_server_volume(self.id, volume_id) utils.wait_until_true(partial(self._volume_detached, volume_id), timeout=timeout, sleep=SHORT_SLEEP) def close(self, timeout=MEDIUM_TIMEOUT): try: self.nova_client.servers.delete(self.id) except Exception: return utils.wait_until_none(self._server_status, timeout=timeout, sleep=MEDIUM_SLEEP) class Volume(object): _name_id = 0 def __init__(self): super(Volume, self).__init__() self.id = None self._name = None self.cinder_client = base._get_cinder_client() self.glance_client = base._get_glance_client() def _volume_status(self, status=None): try: volume = self.cinder_client.volumes.get(self.id) except Exception: return False if status is None or status == volume.status: return True else: return False def to_dict(self): return { "id": self.id, "type": constants.VOLUME_RESOURCE_TYPE, "name": self._name, "extra_info": {'availability_zone': 'az1'}, } def create(self, size, name=None, create_from_image=False, timeout=LONG_TIMEOUT): if name is None: name = "KarborFullstack-Volume-{id}".format( id=self.__class__._name_id ) self.__class__._name_id += 1 self._name = name image = None if create_from_image: images = self.glance_client.images.list() for image_iter in images: if image_iter['disk_format'] not in ('aki', 'ari') and ( image_iter['name'].startswith('cirros')): image = image_iter['id'] break assert image volume = self.cinder_client.volumes.create(size, name=name, imageRef=image) self.id = volume.id utils.wait_until_true(partial(self._volume_status, 'available'), timeout=timeout, sleep=MEDIUM_SLEEP) return self.id def close(self, timeout=LONG_TIMEOUT): try: self.cinder_client.volumes.delete(self.id) except Exception: return utils.wait_until_none(self._volume_status, timeout=timeout, sleep=MEDIUM_SLEEP) class Share(object): _name_id = 0 def __init__(self): super(Share, self).__init__() self.id = None self._name = None self.manila_client = base._get_manila_client() self.neutron_client = base._get_neutron_client() def _share_status(self, status=None): try: share = self.manila_client.shares.get(self.id) except Exception: return False if status is None or status == share.status: return True else: return False def to_dict(self): return { "id": self.id, "type": constants.SHARE_RESOURCE_TYPE, "name": self._name, } def create(self, share_proto, size, name=None, timeout=LONG_TIMEOUT): if name is None: name = "KarborFullstack-Share-{id}".format(id=self._name_id) self._name_id += 1 self._name = name share = self.manila_client.shares.create(share_proto, size, name=name) self.id = share.id utils.wait_until_true(partial(self._share_status, 'available'), timeout=timeout, sleep=MEDIUM_SLEEP) return self.id def close(self, timeout=MEDIUM_TIMEOUT): try: self.manila_client.shares.delete(self.id) except Exception: return utils.wait_until_none(self._share_status, timeout=timeout, sleep=MEDIUM_SLEEP) class Network(object): def __init__(self): super(Network, self).__init__() self.id = None self.project_id = None self._name = "private-net-%s" % uuidutils.generate_uuid() self.neutron_client = base._get_neutron_client() def _network_status(self, status=None): try: networks = self.neutron_client.list_networks(name=self._name) assert len(networks['networks']) > 0 network = networks['networks'][0] except Exception: return False if status is None or status == network['status']: return True else: return False def to_dict(self): return { "id": self.id, "type": constants.NETWORK_RESOURCE_TYPE, "name": self._name, } def create(self, timeout=MEDIUM_TIMEOUT): network = {'name': self._name, 'admin_state_up': True} self.neutron_client.create_network({'network': network}) networks = self.neutron_client.list_networks(name=self._name) assert len(networks['networks']) > 0 network_id = networks['networks'][0]['id'] self.id = network_id self.project_id = networks['networks'][0]['tenant_id'] utils.wait_until_true(partial(self._network_status, 'ACTIVE'), timeout=timeout, sleep=MEDIUM_SLEEP) return self.id def close(self, timeout=LONG_TIMEOUT): try: self.neutron_client.delete_network(self.id) except Exception: return utils.wait_until_none(self._network_status, timeout=timeout, sleep=MEDIUM_SLEEP)