diff --git a/.zuul.yaml b/.zuul.yaml index 1395bfc8..d7b7e6cb 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -18,6 +18,7 @@ - openstack/blazar - openstack/blazar-nova - openstack/python-blazarclient + - openstack/blazar-tempest-plugin - project: name: openstack/blazar diff --git a/blazar_tempest_plugin/README.rst b/blazar_tempest_plugin/README.rst deleted file mode 100644 index c5a039b3..00000000 --- a/blazar_tempest_plugin/README.rst +++ /dev/null @@ -1,5 +0,0 @@ -=============================================== -Tempest Integration of blazar -=============================================== - -This directory contains Tempest tests to cover the blazar project diff --git a/blazar_tempest_plugin/__init__.py b/blazar_tempest_plugin/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/blazar_tempest_plugin/config.py b/blazar_tempest_plugin/config.py deleted file mode 100644 index 671560f9..00000000 --- a/blazar_tempest_plugin/config.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2014 Intel Corporation -# 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. - -from oslo_config import cfg - - -service_available_group = cfg.OptGroup(name="service_available", - title="Available OpenStack Services") - -service_option = [ - cfg.BoolOpt("climate", - default=True, - help="Whether or not climate is expected to be available. " - "This config remains for backward compatibility."), - cfg.BoolOpt("blazar", - default=True, - help="Whether or not blazar is expected to be available"), -] - -resource_reservation_group = cfg.OptGroup(name='resource_reservation', - title='Resource reservation service ' - 'options') - -ResourceReservationGroup = [ - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the resource_reservation " - "service."), - cfg.IntOpt('lease_interval', - default=10, - help="Time in seconds between lease status checks."), - cfg.IntOpt('lease_end_timeout', - default=300, - help="Timeout in seconds to wait for a lease to finish.") -] diff --git a/blazar_tempest_plugin/plugin.py b/blazar_tempest_plugin/plugin.py deleted file mode 100644 index 42f798f6..00000000 --- a/blazar_tempest_plugin/plugin.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2015 -# 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 os - -from tempest import config -from tempest.test_discover import plugins - -from blazar_tempest_plugin import config as blazar_config - - -class BlazarTempestPlugin(plugins.TempestPlugin): - def load_tests(self): - base_path = os.path.split(os.path.dirname( - os.path.abspath(__file__)))[0] - test_dir = "blazar_tempest_plugin/tests" - full_test_dir = os.path.join(base_path, test_dir) - return full_test_dir, base_path - - def register_opts(self, conf): - config.register_opt_group(conf, - blazar_config.service_available_group, - blazar_config.service_option) - config.register_opt_group(conf, - blazar_config.resource_reservation_group, - blazar_config.ResourceReservationGroup) - - def get_opt_lists(self): - return [ - (blazar_config.service_available_group.name, - blazar_config.service_option), - (blazar_config.resource_reservation_group.name, - blazar_config.ResourceReservationGroup) - ] diff --git a/blazar_tempest_plugin/services/__init__.py b/blazar_tempest_plugin/services/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/blazar_tempest_plugin/services/reservation/__init__.py b/blazar_tempest_plugin/services/reservation/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/blazar_tempest_plugin/services/reservation/reservation_client.py b/blazar_tempest_plugin/services/reservation/reservation_client.py deleted file mode 100644 index 4a9c2107..00000000 --- a/blazar_tempest_plugin/services/reservation/reservation_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2017 NTT -# 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 json - -from tempest.lib.common import rest_client - - -class ResourceReservationV1Client(rest_client.RestClient): - """Client class for accessing the resource reservation API.""" - CLIMATECLIENT_VERSION = '1' - - lease = '/leases' - lease_path = '/leases/%s' - host = '/os-hosts' - host_path = '/os-hosts/%s' - - def _response_helper(self, resp, body=None): - if body: - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_lease(self): - resp, body = self.get(self.lease) - return self._response_helper(resp, body) - - def get_lease(self, lease): - resp, body = self.get(self.lease_path % lease) - return self._response_helper(resp, body) - - def create_lease(self, body): - body = json.dumps(body) - resp, body = self.post(self.lease, body=body) - return self._response_helper(resp, body) - - def update_lease(self, lease, body): - body = json.dumps(body) - resp, body = self.put(self.lease_path % lease, body=body) - return self._response_helper(resp, body) - - def delete_lease(self, lease): - resp, body = self.delete(self.lease_path % lease) - return self._response_helper(resp, body) - - def list_host(self): - resp, body = self.get(self.host) - return self._response_helper(resp, body) - - def get_host(self, host): - resp, body = self.get(self.host_path % host) - return self._response_helper(resp, body) - - def create_host(self, body): - body = json.dumps(body) - resp, body = self.post(self.host, body=body) - return self._response_helper(resp, body) - - def update_host(self, host, body): - body = json.dumps(body) - resp, body = self.put(self.host_path % host, body=body) - return self._response_helper(resp, body) - - def delete_host(self, host): - resp, body = self.delete(self.host_path % host) - return self._response_helper(resp, body) diff --git a/blazar_tempest_plugin/tests/__init__.py b/blazar_tempest_plugin/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/blazar_tempest_plugin/tests/scenario/__init__.py b/blazar_tempest_plugin/tests/scenario/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/blazar_tempest_plugin/tests/scenario/manager_freeze.py b/blazar_tempest_plugin/tests/scenario/manager_freeze.py deleted file mode 100644 index 22477993..00000000 --- a/blazar_tempest_plugin/tests/scenario/manager_freeze.py +++ /dev/null @@ -1,686 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# 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 subprocess - -from oslo_log import log -from oslo_serialization import jsonutils as json - -from tempest.common import compute -from tempest.common import image as common_image -from tempest.common.utils.linux import remote_client -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = log.getLogger(__name__) - - -class ScenarioTest(tempest.test.BaseTestCase): - """Base class for scenario tests. Uses tempest own clients. """ - - credentials = ['primary'] - - @classmethod - def setup_clients(cls): - super(ScenarioTest, cls).setup_clients() - # Clients (in alphabetical order) - cls.flavors_client = cls.os_primary.flavors_client - cls.compute_floating_ips_client = ( - cls.os_primary.compute_floating_ips_client) - if CONF.service_available.glance: - # Check if glance v1 is available to determine which client to use. - if CONF.image_feature_enabled.api_v1: - cls.image_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.image_client = cls.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - # Compute image client - cls.compute_images_client = cls.os_primary.compute_images_client - cls.keypairs_client = cls.os_primary.keypairs_client - # Nova security groups client - cls.compute_security_groups_client = ( - cls.os_primary.compute_security_groups_client) - cls.compute_security_group_rules_client = ( - cls.os_primary.compute_security_group_rules_client) - cls.servers_client = cls.os_primary.servers_client - cls.interface_client = cls.os_primary.interfaces_client - # Neutron network client - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - - if CONF.volume_feature_enabled.api_v2: - cls.volumes_client = cls.os_primary.volumes_v2_client - cls.snapshots_client = cls.os_primary.snapshots_v2_client - else: - cls.volumes_client = cls.os_primary.volumes_client - cls.snapshots_client = cls.os_primary.snapshots_client - - # ## Test functions library - # - # The create_[resource] functions only return body and discard the - # resp part which is not used in scenario tests - - def _create_port(self, network_id, client=None, namestart='port-quotatest', - **kwargs): - if not client: - client = self.ports_client - name = data_utils.rand_name(namestart) - result = client.create_port( - name=name, - network_id=network_id, - **kwargs) - self.assertIsNotNone(result, 'Unable to allocate port') - port = result['port'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_port, port['id']) - return port - - def create_keypair(self, client=None): - if not client: - client = self.keypairs_client - name = data_utils.rand_name(self.__class__.__name__) - # We don't need to create a keypair by pubkey in scenario - body = client.create_keypair(name=name) - self.addCleanup(client.delete_keypair, name) - return body['keypair'] - - def create_server(self, name=None, image_id=None, flavor=None, - validatable=False, wait_until='ACTIVE', - clients=None, **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - """ - - # NOTE(jlanoux): As a first step, ssh checks in the scenario - # tests need to be run regardless of the run_validation and - # validatable parameters and thus until the ssh validation job - # becomes voting in CI. The test resources management and IP - # association are taken care of in the scenario tests. - # Therefore, the validatable parameter is set to false in all - # those tests. In this way create_server just return a standard - # server and the scenario tests always perform ssh checks. - - # Needed for the cross_tenant_traffic test: - if clients is None: - clients = self.os_primary - - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-server") - - vnic_type = CONF.network.port_vnic_type - - # If vnic_type is configured create port for - # every network - if vnic_type: - ports = [] - - create_port_body = {'binding:vnic_type': vnic_type, - 'namestart': 'port-smoke'} - if kwargs: - # Convert security group names to security group ids - # to pass to create_port - if 'security_groups' in kwargs: - security_groups = \ - clients.security_groups_client.list_security_groups( - ).get('security_groups') - sec_dict = dict([(s['name'], s['id']) - for s in security_groups]) - - sec_groups_names = [s['name'] for s in kwargs.pop( - 'security_groups')] - security_groups_ids = [sec_dict[s] - for s in sec_groups_names] - - if security_groups_ids: - create_port_body[ - 'security_groups'] = security_groups_ids - networks = kwargs.pop('networks', []) - else: - networks = [] - - # If there are no networks passed to us we look up - # for the project's private networks and create a port. - # The same behaviour as we would expect when passing - # the call to the clients with no networks - if not networks: - networks = clients.networks_client.list_networks( - **{'router:external': False, 'fields': 'id'})['networks'] - - # It's net['uuid'] if networks come from kwargs - # and net['id'] if they come from - # clients.networks_client.list_networks - for net in networks: - net_id = net.get('uuid', net.get('id')) - if 'port' not in net: - port = self._create_port(network_id=net_id, - client=clients.ports_client, - **create_port_body) - ports.append({'port': port['id']}) - else: - ports.append({'port': net['port']}) - if ports: - kwargs['networks'] = ports - self.ports = ports - - tenant_network = self.get_tenant_network() - - body, servers = compute.create_test_server( - clients, - tenant_network=tenant_network, - wait_until=wait_until, - name=name, flavor=flavor, - image_id=image_id, **kwargs) - - self.addCleanup(waiters.wait_for_server_termination, - clients.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - clients.servers_client.delete_server, body['id']) - server = clients.servers_client.show_server(body['id'])['server'] - return server - - def create_volume(self, size=None, name=None, snapshot_id=None, - imageRef=None, volume_type=None): - if size is None: - size = CONF.volume.volume_size - if imageRef: - image = self.compute_images_client.show_image(imageRef)['image'] - min_disk = image.get('minDisk') - size = max(size, min_disk) - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-volume") - kwargs = {'display_name': name, - 'snapshot_id': snapshot_id, - 'imageRef': imageRef, - 'volume_type': volume_type, - 'size': size} - volume = self.volumes_client.create_volume(**kwargs)['volume'] - - self.addCleanup(self.volumes_client.wait_for_resource_deletion, - volume['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volumes_client.delete_volume, volume['id']) - - # NOTE(e0ne): Cinder API v2 uses name instead of display_name - if 'display_name' in volume: - self.assertEqual(name, volume['display_name']) - else: - self.assertEqual(name, volume['name']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - # The volume retrieved on creation has a non-up-to-date status. - # Retrieval after it becomes active ensures correct details. - volume = self.volumes_client.show_volume(volume['id'])['volume'] - return volume - - def create_volume_type(self, client=None, name=None, backend_name=None): - if not client: - client = self.admin_volume_types_client - if not name: - class_name = self.__class__.__name__ - name = data_utils.rand_name(class_name + '-volume-type') - randomized_name = data_utils.rand_name('scenario-type-' + name) - - LOG.debug("Creating a volume type: %s on backend %s", - randomized_name, backend_name) - extra_specs = {} - if backend_name: - extra_specs = {"volume_backend_name": backend_name} - - body = client.create_volume_type(name=randomized_name, - extra_specs=extra_specs) - volume_type = body['volume_type'] - self.assertIn('id', volume_type) - self.addCleanup(client.delete_volume_type, volume_type['id']) - return volume_type - - def _create_loginable_secgroup_rule(self, secgroup_id=None): - _client = self.compute_security_groups_client - _client_rules = self.compute_security_group_rules_client - if secgroup_id is None: - sgs = _client.list_security_groups()['security_groups'] - for sg in sgs: - if sg['name'] == 'default': - secgroup_id = sg['id'] - - # These rules are intended to permit inbound ssh and icmp - # traffic from all sources, so no group_id is provided. - # Setting a group_id would only permit traffic from ports - # belonging to the same security group. - rulesets = [ - { - # ssh - 'ip_protocol': 'tcp', - 'from_port': 22, - 'to_port': 22, - 'cidr': '0.0.0.0/0', - }, - { - # ping - 'ip_protocol': 'icmp', - 'from_port': -1, - 'to_port': -1, - 'cidr': '0.0.0.0/0', - } - ] - rules = list() - for ruleset in rulesets: - sg_rule = _client_rules.create_security_group_rule( - parent_group_id=secgroup_id, **ruleset)['security_group_rule'] - rules.append(sg_rule) - return rules - - def _create_security_group(self): - # Create security group - sg_name = data_utils.rand_name(self.__class__.__name__) - sg_desc = sg_name + " description" - secgroup = self.compute_security_groups_client.create_security_group( - name=sg_name, description=sg_desc)['security_group'] - self.assertEqual(secgroup['name'], sg_name) - self.assertEqual(secgroup['description'], sg_desc) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.compute_security_groups_client.delete_security_group, - secgroup['id']) - - # Add rules to the security group - self._create_loginable_secgroup_rule(secgroup['id']) - - return secgroup - - def get_remote_client(self, ip_address, username=None, private_key=None): - """Get a SSH client to a remote server - - @param ip_address the server floating or fixed IP address to use - for ssh validation - @param username name of the Linux account on the remote server - @param private_key the SSH private key to use - @return a RemoteClient object - """ - - if username is None: - username = CONF.validation.image_ssh_user - # Set this with 'keypair' or others to log in with keypair or - # username/password. - if CONF.validation.auth_method == 'keypair': - password = None - if private_key is None: - private_key = self.keypair['private_key'] - else: - password = CONF.validation.image_ssh_password - private_key = None - linux_client = remote_client.RemoteClient(ip_address, username, - pkey=private_key, - password=password) - try: - linux_client.validate_authentication() - except Exception as e: - message = ('Initializing SSH connection to %(ip)s failed. ' - 'Error: %(error)s' % {'ip': ip_address, - 'error': e}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - LOG.exception(message) - self._log_console_output() - raise - - return linux_client - - def _image_create(self, name, fmt, path, - disk_format=None, properties=None): - if properties is None: - properties = {} - name = data_utils.rand_name('%s-' % name) - params = { - 'name': name, - 'container_format': fmt, - 'disk_format': disk_format or fmt, - } - if CONF.image_feature_enabled.api_v1: - params['is_public'] = 'False' - params['properties'] = properties - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params['visibility'] = 'private' - # Additional properties are flattened out in the v2 API. - params.update(properties) - body = self.image_client.create_image(**params) - image = body['image'] if 'image' in body else body - self.addCleanup(self.image_client.delete_image, image['id']) - self.assertEqual("queued", image['status']) - with open(path, 'rb') as image_file: - if CONF.image_feature_enabled.api_v1: - self.image_client.update_image(image['id'], data=image_file) - else: - self.image_client.store_image_file(image['id'], image_file) - return image['id'] - - def glance_image_create(self): - img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file - aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file - ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file - ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file - img_container_format = CONF.scenario.img_container_format - img_disk_format = CONF.scenario.img_disk_format - img_properties = CONF.scenario.img_properties - LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, " - "properties: %s, ami: %s, ari: %s, aki: %s", - img_path, img_container_format, img_disk_format, - img_properties, ami_img_path, ari_img_path, aki_img_path) - try: - image = self._image_create('scenario-img', - img_container_format, - img_path, - disk_format=img_disk_format, - properties=img_properties) - except IOError: - LOG.debug("A qcow2 image was not found. Try to get a uec image.") - kernel = self._image_create('scenario-aki', 'aki', aki_img_path) - ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path) - properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk} - image = self._image_create('scenario-ami', 'ami', - path=ami_img_path, - properties=properties) - LOG.debug("image:%s", image) - - return image - - def _log_console_output(self, servers=None): - if not CONF.compute_feature_enabled.console_output: - LOG.debug('Console output not supported, cannot log') - return - if not servers: - servers = self.servers_client.list_servers() - servers = servers['servers'] - for server in servers: - try: - console_output = self.servers_client.get_console_output( - server['id'])['output'] - LOG.debug('Console output for %s\nbody=\n%s', - server['id'], console_output) - except lib_exc.NotFound: - LOG.debug("Server %s disappeared(deleted) while looking " - "for the console log", server['id']) - - def _log_net_info(self, exc): - # network debug is called as part of ssh init - if not isinstance(exc, lib_exc.SSHTimeout): - LOG.debug('Network information on a devstack host') - - def create_server_snapshot(self, server, name=None): - # Glance client - _image_client = self.image_client - # Compute client - _images_client = self.compute_images_client - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + 'snapshot') - LOG.debug("Creating a snapshot image for server: %s", server['name']) - image = _images_client.create_image(server['id'], name=name) - image_id = image.response['location'].split('images/')[1] - waiters.wait_for_image_status(_image_client, image_id, 'active') - - self.addCleanup(_image_client.wait_for_resource_deletion, - image_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - _image_client.delete_image, image_id) - - if CONF.image_feature_enabled.api_v1: - # In glance v1 the additional properties are stored in the headers. - resp = _image_client.check_image(image_id) - snapshot_image = common_image.get_image_meta_from_headers(resp) - image_props = snapshot_image.get('properties', {}) - else: - # In glance v2 the additional properties are flattened. - snapshot_image = _image_client.show_image(image_id) - image_props = snapshot_image - - bdm = image_props.get('block_device_mapping') - if bdm: - bdm = json.loads(bdm) - if bdm and 'snapshot_id' in bdm[0]: - snapshot_id = bdm[0]['snapshot_id'] - self.addCleanup( - self.snapshots_client.wait_for_resource_deletion, - snapshot_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.snapshots_client.delete_snapshot, - snapshot_id) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot_id, - 'available') - image_name = snapshot_image['name'] - self.assertEqual(name, image_name) - LOG.debug("Created snapshot image %s for server %s", - image_name, server['name']) - return snapshot_image - - def nova_volume_attach(self, server, volume_to_attach): - volume = self.servers_client.attach_volume( - server['id'], volumeId=volume_to_attach['id'], device='/dev/%s' - % CONF.compute.volume_device_name)['volumeAttachment'] - self.assertEqual(volume_to_attach['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'in-use') - - # Return the updated volume after the attachment - return self.volumes_client.show_volume(volume['id'])['volume'] - - def nova_volume_detach(self, server, volume): - self.servers_client.detach_volume(server['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual('available', volume['status']) - - def rebuild_server(self, server_id, image=None, - preserve_ephemeral=False, wait=True, - rebuild_kwargs=None): - if image is None: - image = CONF.compute.image_ref - - rebuild_kwargs = rebuild_kwargs or {} - - LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)", - server_id, image, preserve_ephemeral) - self.servers_client.rebuild_server( - server_id=server_id, image_ref=image, - preserve_ephemeral=preserve_ephemeral, - **rebuild_kwargs) - if wait: - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - def ping_ip_address(self, ip_address, should_succeed=True, - ping_timeout=None, mtu=None): - timeout = ping_timeout or CONF.validation.ping_timeout - cmd = ['ping', '-c1', '-w1'] - - if mtu: - cmd += [ - # don't fragment - '-M', 'do', - # ping receives just the size of ICMP payload - '-s', str(net_utils.get_ping_payload_size(mtu, 4)) - ] - cmd.append(ip_address) - - def ping(): - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - proc.communicate() - - return (proc.returncode == 0) == should_succeed - - caller = test_utils.find_test_caller() - LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the' - ' expected result is %(should_succeed)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'should_succeed': - 'reachable' if should_succeed else 'unreachable' - }) - result = test_utils.call_until_true(ping, timeout, 1) - LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the ' - 'ping result is %(result)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'result': 'expected' if result else 'unexpected' - }) - return result - - def check_vm_connectivity(self, ip_address, - username=None, - private_key=None, - should_connect=True, - mtu=None): - """Check server connectivity - - :param ip_address: server to test against - :param username: server's ssh username - :param private_key: server's ssh private key to be used - :param should_connect: True/False indicates positive/negative test - positive - attempt ping and ssh - negative - attempt ping and fail if succeed - :param mtu: network MTU to use for connectivity validation - - :raises: AssertError if the result of the connectivity check does - not match the value of the should_connect param - """ - if should_connect: - msg = "Timed out waiting for %s to become reachable" % ip_address - else: - msg = "ip address %s is reachable" % ip_address - self.assertTrue(self.ping_ip_address(ip_address, - should_succeed=should_connect, - mtu=mtu), - msg=msg) - if should_connect: - # no need to check ssh for negative connectivity - self.get_remote_client(ip_address, username, private_key) - - def check_public_network_connectivity(self, ip_address, username, - private_key, should_connect=True, - msg=None, servers=None, mtu=None): - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - LOG.debug('checking network connections to IP %s with user: %s', - ip_address, username) - try: - self.check_vm_connectivity(ip_address, - username, - private_key, - should_connect=should_connect, - mtu=mtu) - except Exception: - ex_msg = 'Public network connectivity check failed' - if msg: - ex_msg += ": " + msg - LOG.exception(ex_msg) - self._log_console_output(servers) - raise - - def create_floating_ip(self, thing, pool_name=None): - """Create a floating IP and associates to a server on Nova""" - - if not pool_name: - pool_name = CONF.network.floating_network_name - floating_ip = (self.compute_floating_ips_client. - create_floating_ip(pool=pool_name)['floating_ip']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.compute_floating_ips_client.delete_floating_ip, - floating_ip['id']) - self.compute_floating_ips_client.associate_floating_ip_to_server( - floating_ip['ip'], thing['id']) - return floating_ip - - def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.make_fs(dev_name) - ssh_client.mount(dev_name, mount_path) - cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path - ssh_client.exec_command(cmd_timestamp) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.umount(mount_path) - return timestamp - - def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.mount(dev_name, mount_path) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.umount(mount_path) - return timestamp - - def get_server_ip(self, server): - """Get the server fixed or floating IP. - - Based on the configuration we're in, return a correct ip - address for validating that a guest is up. - """ - if CONF.validation.connect_method == 'floating': - # The tests calling this method don't have a floating IP - # and can't make use of the validation resources. So the - # method is creating the floating IP there. - return self.create_floating_ip(server)['ip'] - elif CONF.validation.connect_method == 'fixed': - # Determine the network name to look for based on config or creds - # provider network resources. - if CONF.validation.network_for_ssh: - addresses = server['addresses'][ - CONF.validation.network_for_ssh] - else: - creds_provider = self._get_credentials_provider() - net_creds = creds_provider.get_primary_creds() - network = getattr(net_creds, 'network', None) - addresses = (server['addresses'][network['name']] - if network else []) - for address in addresses: - if (address['version'] == CONF.validation.ip_version_for_ssh - and address['OS-EXT-IPS:type'] == 'fixed'): - return address['addr'] - raise exceptions.ServerUnreachable(server_id=server['id']) - else: - raise lib_exc.InvalidConfiguration() diff --git a/blazar_tempest_plugin/tests/scenario/resource_reservation_scenario.py b/blazar_tempest_plugin/tests/scenario/resource_reservation_scenario.py deleted file mode 100644 index aab5c1a9..00000000 --- a/blazar_tempest_plugin/tests/scenario/resource_reservation_scenario.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2014 Intel Corporation -# 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. - - -from oslo_log import log -from tempest import clients as tempestclients -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import test_utils - -from blazar_tempest_plugin.services.reservation import ( - reservation_client as clients) -from blazar_tempest_plugin.tests.scenario import manager_freeze as manager - -CONF = config.CONF - -LOG = log.getLogger(__name__) - - -class ResourceReservationScenarioTest(manager.ScenarioTest): - """Base class for resource reservation scenario tests.""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(ResourceReservationScenarioTest, cls).setup_clients() - if not (CONF.service_available.climate or - CONF.service_available.blazar): - raise cls.skipException("Resource reservation support is" - "required") - - cred_provider = cls._get_credentials_provider() - creds = cred_provider.get_credentials('admin') - auth_prov = tempestclients.get_auth_provider(creds._credentials) - cls.os_admin.resource_reservation_client = ( - clients.ResourceReservationV1Client(auth_prov, - 'reservation', - CONF.identity.region)) - cls.reservation_client = ( - cls.os_admin.resource_reservation_client) - - def get_lease_by_name(self, lease_name): - # the same as the blazarclient does it: ask for the entire list - lease_list = self.reservation_client.list_lease() - named_lease = [] - - # and then search by lease_name - named_lease = ( - filter(lambda lease: lease['name'] == lease_name, lease_list)) - - if named_lease: - return self.reservation_client.get_lease( - named_lease[0]['id']) - else: - message = "Unable to find lease with name '%s'" % lease_name - raise exceptions.NotFound(message) - - def delete_lease(self, lease_id): - return self.reservation_client.delete_lease(lease_id) - - def wait_for_lease_end(self, lease_id): - - def check_lease_end(): - try: - lease = self.reservation_client.get_lease(lease_id)['lease'] - if lease: - events = lease['events'] - return len(filter(lambda evt: - evt['event_type'] == 'end_lease' and - evt['status'] == 'DONE', - events)) > 0 - else: - LOG.info("Lease with id %s is empty", lease_id) - except Exception as e: - LOG.info("Unable to find lease with id %(lease_id)s. " - "Exception: %(message)s", - {'lease_id': lease_id, 'message': e.message}) - return True - - if not test_utils.call_until_true( - check_lease_end, - CONF.resource_reservation.lease_end_timeout, - CONF.resource_reservation.lease_interval): - message = "Timed out waiting for lease to change status to DONE" - raise exceptions.TimeoutException(message) - - def remove_image_snapshot(self, image_name): - try: - image = filter(lambda i: - i['name'] == image_name, - self.image_client.list()) - self.image_client.delete(image) - except Exception as e: - LOG.info("Unable to delete %(image_name)s snapshot. " - "Exception: %(message)s", - {'image_name': image_name, 'message': e.message}) - - def is_flavor_enough(self, flavor_id, image_id): - image = self.compute_images_client.show_image(image_id)['image'] - flavor = self.flavors_client.show_flavor(flavor_id)['flavor'] - return image['minDisk'] <= flavor['disk'] diff --git a/blazar_tempest_plugin/tests/scenario/test_host_reservation.py b/blazar_tempest_plugin/tests/scenario/test_host_reservation.py deleted file mode 100644 index d3d66324..00000000 --- a/blazar_tempest_plugin/tests/scenario/test_host_reservation.py +++ /dev/null @@ -1,337 +0,0 @@ -# Copyright 2017 NTT Corporation. 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 datetime -import time - -from oslo_log import log as logging -from six.moves import range -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions - -from blazar_tempest_plugin.tests.scenario import ( - resource_reservation_scenario as rrs) - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class TestHostReservationScenario(rrs.ResourceReservationScenarioTest): - """A Scenario test class that checks host reservation.""" - - MAX_RETRY = 20 - WAIT_TIME = 2 - - def setUp(self): - super(TestHostReservationScenario, self).setUp() - self.aggr_client = self.os_admin.aggregates_client - - def tearDown(self): - super(TestHostReservationScenario, self).tearDown() - - def fetch_one_compute_host(self): - """Returns a first host listed in nova-compute services.""" - compute = next(iter(self.os_admin.services_client. - list_services(binary='nova-compute')['services'])) - return compute - - def get_lease_body(self, lease_name, host_name): - current_time = datetime.datetime.utcnow() - end_time = current_time + datetime.timedelta(hours=1) - body = { - "start_date": "now", - "end_date": end_time.strftime('%Y-%m-%d %H:%M'), - "name": lease_name, - "events": [], - } - body["reservations"] = [ - { - "hypervisor_properties": ('["==", "$hypervisor_hostname", "' - '%s"]' % host_name), - "max": 1, - "min": 1, - "resource_type": 'physical:host', - "resource_properties": '' - } - ] - - return body - - def get_lease_body_missing_param(self, lease_name, host_name): - current_time = datetime.datetime.utcnow() - end_time = current_time + datetime.timedelta(hours=1) - body = { - "start_date": "now", - "end_date": end_time.strftime('%Y-%m-%d %H:%M'), - "name": lease_name, - "events": [], - } - body["reservations"] = [ - { - "hypervisor_properties": ('["==", "$hypervisor_hostname", "' - '%s"]' % host_name), - "min": '1', - "resource_type": 'physical:host', - "resource_properties": '' - } - ] - - return body - - def get_invalid_lease_body(self, lease_name, host_name): - current_time = datetime.datetime.utcnow() - end_time = current_time + datetime.timedelta(hours=1) - body = { - "start_date": "now", - "end_date": end_time.strftime('%Y-%m-%d %H:%M'), - "name": lease_name, - "events": [], - } - body["reservations"] = [ - { - "hypervisor_properties": ('["==", "$hypervisor_hostname", "' - '%s"]' % host_name), - "max": 'foo', - "min": 'bar', - "resource_type": 'physical:host', - "resource_properties": '' - } - ] - - return body - - def get_expiration_lease_body(self, lease_name, host_name): - current_time = datetime.datetime.utcnow() - end_time = current_time + datetime.timedelta(seconds=90) - body = { - 'start_date': "now", - 'end_date': end_time.strftime('%Y-%m-%d %H:%M'), - 'name': lease_name, - 'events': [], - } - body['reservations'] = [ - { - 'hypervisor_properties': ('["==", "$hypervisor_hostname", "' - '%s"]' % host_name), - 'max': 1, - 'min': 1, - 'resource_type': 'physical:host', - 'resource_properties': '' - } - ] - - return body - - def fetch_aggregate_by_name(self, name): - aggregates = self.aggr_client.list_aggregates()['aggregates'] - try: - aggr = next(iter(filter(lambda aggr: aggr['name'] == name, - aggregates))) - except StopIteration: - err_msg = "aggregate with name %s doesn't exist." % name - raise exceptions.NotFound(err_msg) - return aggr - - def wait_until_aggregated(self, aggregate_name, host_name): - for i in range(self.MAX_RETRY): - try: - aggr = self.fetch_aggregate_by_name(aggregate_name) - self.assertTrue(host_name in aggr['hosts']) - return - except Exception: - pass - time.sleep(self.WAIT_TIME) - err_msg = ("hostname %s doesn't exist in aggregate %s." - % (host_name, aggregate_name)) - raise exceptions.NotFound(err_msg) - - def _add_host_once(self): - host = self.fetch_one_compute_host() - hosts = self.reservation_client.list_host()['hosts'] - try: - next(iter(filter( - lambda h: h['hypervisor_hostname'] == host['host'], hosts))) - except StopIteration: - self.reservation_client.create_host({'name': host['host']}) - return host - - @decorators.attr(type='smoke') - def test_host_reservation(self): - - # Create the host if it doesn't exists - host = self._add_host_once() - - # check the host is in freepool - freepool = self.fetch_aggregate_by_name('freepool') - self.assertTrue(host['host'] in freepool['hosts']) - - # try creating a new lease with a missing parameter - body = self.get_lease_body_missing_param('scenario-1-missing-param', - host['host']) - self.assertRaises(exceptions.BadRequest, - self.reservation_client.create_lease, body) - - # try creating a new lease with an invalid request - body = self.get_invalid_lease_body('scenario-1-invalid', host['host']) - self.assertRaises(exceptions.BadRequest, - self.reservation_client.create_lease, body) - - # create new lease and start reservation immediately - body = self.get_lease_body('scenario-1', host['host']) - lease = self.reservation_client.create_lease(body)['lease'] - - # check host added to the reservation - reservation_id = next(iter(lease['reservations']))['id'] - self.wait_until_aggregated(reservation_id, host['host']) - - # create an instance with reservation id - create_kwargs = { - 'scheduler_hints': { - "reservation": reservation_id, - }, - 'image_id': CONF.compute.image_ref, - 'flavor': CONF.compute.flavor_ref, - } - server = self.create_server(clients=self.os_admin, - **create_kwargs) - # ensure server is located on the requested host - self.assertEqual(host['host'], server['OS-EXT-SRV-ATTR:host']) - - # delete the lease, which should trigger termination of the instance - self.reservation_client.delete_lease(lease['id']) - waiters.wait_for_server_termination(self.os_admin.servers_client, - server['id']) - - # create an instance without reservation id, which is expected to fail - create_kwargs = { - 'image_id': CONF.compute.image_ref, - 'flavor': CONF.compute.flavor_ref, - } - server = self.create_server(clients=self.os_admin, - wait_until=None, - **create_kwargs) - waiters.wait_for_server_status(self.os_admin.servers_client, - server['id'], 'ERROR', - raise_on_error=False) - - @decorators.attr(type='smoke') - def test_lease_expiration(self): - - # create the host if it doesn't exist - host = self._add_host_once() - - # create new lease and start reservation immediately - body = self.get_expiration_lease_body('scenario-2-expiration', - host['host']) - lease = self.reservation_client.create_lease(body)['lease'] - lease_id = lease['id'] - - # check host added to the reservation - reservation_id = next(iter(lease['reservations']))['id'] - self.wait_until_aggregated(reservation_id, host['host']) - - create_kwargs = { - 'scheduler_hints': { - 'reservation': reservation_id, - }, - 'image_id': CONF.compute.image_ref, - 'flavor': CONF.compute.flavor_ref, - } - server = self.create_server(clients=self.os_admin, - **create_kwargs) - - # wait for lease end - self.wait_for_lease_end(lease_id) - - # check if the lease has been correctly terminated and - # the instance is removed - waiters.wait_for_server_termination(self.os_admin.servers_client, - server['id']) - - # check that the host aggregate was deleted - self.assertRaises(exceptions.NotFound, - self.fetch_aggregate_by_name, reservation_id) - - # check that the host is back in the freepool - freepool = self.fetch_aggregate_by_name('freepool') - self.assertTrue(host['host'] in freepool['hosts']) - - # check the reservation status - lease = self.reservation_client.get_lease(lease_id)['lease'] - self.assertTrue('deleted' in - next(iter(lease['reservations']))['status']) - - @decorators.attr(type='smoke') - def test_update_host_reservation(self): - - # create the host if it doesn't exist - host = self._add_host_once() - - # create new lease and start reservation immediately - body = self.get_lease_body('scenario-3-update', host['host']) - lease = self.reservation_client.create_lease(body)['lease'] - lease_id = lease['id'] - - # check host added to the reservation - reservation_id = next(iter(lease['reservations']))['id'] - self.wait_until_aggregated(reservation_id, host['host']) - - # check the host aggregate for blazar - self.fetch_aggregate_by_name(reservation_id) - - # create an instance with reservation id - create_kwargs = { - 'scheduler_hints': { - 'reservation': reservation_id, - }, - 'image_id': CONF.compute.image_ref, - 'flavor': CONF.compute.flavor_ref, - } - server = self.create_server(clients=self.os_admin, - wait_until=None, - **create_kwargs) - waiters.wait_for_server_status(self.os_admin.servers_client, - server['id'], 'ACTIVE') - - # wait enough time for the update API to succeed - time.sleep(75) - - # update the lease end_time - end_time = datetime.datetime.utcnow() - body = { - 'end_date': end_time.strftime('%Y-%m-%d %H:%M') - } - self.reservation_client.update_lease(lease_id, - body)['lease'] - - # check if the lease has been correctly terminated and - # the instance is removed - waiters.wait_for_server_termination(self.os_admin.servers_client, - server['id']) - - # check that the host aggregate was deleted - self.assertRaises(exceptions.NotFound, - self.fetch_aggregate_by_name, reservation_id) - - # check that the host is back in the freepool - freepool = self.fetch_aggregate_by_name('freepool') - self.assertTrue(host['host'] in freepool['hosts']) - - # check the reservation status - lease = self.reservation_client.get_lease(lease_id)['lease'] - self.assertTrue('deleted'in - next(iter(lease['reservations']))['status']) diff --git a/blazar_tempest_plugin/tests/scenario/test_instance_reservation.py b/blazar_tempest_plugin/tests/scenario/test_instance_reservation.py deleted file mode 100644 index 15b9a4c2..00000000 --- a/blazar_tempest_plugin/tests/scenario/test_instance_reservation.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 Intel Corporation -# 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 datetime -import json - -import dateutil.parser -from oslo_log import log as logging -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib import decorators -from tempest import test - -from blazar_tempest_plugin.tests.scenario import ( - resource_reservation_scenario as rrs) - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - -# same as the one at blazar/manager/service -LEASE_DATE_FORMAT = "%Y-%m-%d %H:%M" -LEASE_MIN_DURATION = 2 -# TODO(cmart): LEASE_IMAGE_PREFIX should be extracted from CONF -LEASE_IMAGE_PREFIX = 'reserved_' - - -class TestInstanceReservationScenario(rrs.ResourceReservationScenarioTest): - - """Test that checks the instance reservation scenario. - - The following is the scenario outline: - 1) Create an instance with the hint parameters - 2) check vm was shelved - 3) check vm became active - 4) check that a new lease is created on blazar - 5) check its param - 6) wait lease end - 7) make sure VM was snapshoted and removed - - """ - - def setUp(self): - super(TestInstanceReservationScenario, self).setUp() - # Setup image and flavor the test instance - # Support both configured and injected values - if not hasattr(self, 'image_ref'): - self.image_ref = CONF.compute.image_ref - if not hasattr(self, 'flavor_ref'): - self.flavor_ref = CONF.compute.flavor_ref - if not self.is_flavor_enough(self.flavor_ref, self.image_ref): - raise self.skipException( - '{image} does not fit in {flavor}'.format( - image=self.image_ref, flavor=self.flavor_ref - ) - ) - - def tearDown(self): - super(TestInstanceReservationScenario, self).tearDown() - - def add_keypair(self): - self.keypair = self.create_keypair() - - def boot_server_with_lease_data(self, lease_data, wait): - self.add_keypair() - - # Create server with lease_data - create_kwargs = { - 'key_name': self.keypair['name'], - 'scheduler_hints': lease_data - } - - server = self.create_server(image_id=self.image_ref, - flavor=self.flavor_ref, - wait_until=wait, - **create_kwargs) - self.server_id = server['id'] - self.server_name = server['name'] - - def check_lease_creation(self, expected_lease_data): - server = self.servers_client.show_server(self.server_id)['server'] - expected_lease_params = json.loads(expected_lease_data['lease_params']) - - # compare lease_data with data passed as parameter - lease = self.get_lease_by_name(expected_lease_params['name']) - - # check lease dates!! (Beware of date format) - lease_start_date = dateutil.parser.parse(lease['start_date']) - lease_start_date = lease_start_date.strftime(LEASE_DATE_FORMAT) - lease_end_date = dateutil.parser.parse(lease['end_date']) - lease_end_date = lease_end_date.strftime(LEASE_DATE_FORMAT) - - self.assertEqual(expected_lease_params['start'], lease_start_date) - self.assertEqual(expected_lease_params['end'], lease_end_date) - - # check lease events! - events = lease['events'] - self.assertTrue(len(events) >= 3) - - self.assertFalse( - len(filter(lambda evt: evt['event_type'] != 'start_lease' and - evt['event_type'] != 'end_lease' and - evt['event_type'] != 'before_end_lease', - events)) > 0) - - # check that only one reservation was made and it is for a vm - # compare the resource id from the lease with the server.id attribute! - reservations = lease['reservations'] - self.assertTrue(len(reservations) == 1) - self.assertEqual(server['id'], reservations[0]['resource_id']) - self.assertEqual("virtual:instance", - lease['reservations'][0]['resource_type']) - - def check_server_is_snapshoted(self): - image_name = LEASE_IMAGE_PREFIX + self.server_name - try: - images_list = self.image_client.list() - self.assertNotEmpty( - filter(lambda image: image.name == image_name, images_list)) - except Exception as e: - message = ("Unable to find image with name '%s'. " - "Exception: %s" % (image_name, e.message)) - raise exceptions.NotFound(message) - - def check_server_status(self, expected_status): - server = self.servers_client.show_server(self.server_id)['server'] - self.assertEqual(expected_status, server['status']) - - # TODO(cmart): add blazar to services after pushing this code into tempest - @decorators.skip_because('Instance reservation is not supported yet.', - bug='1659200') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_basic_resource_reservation_operation(self): - start_date = datetime.datetime.utcnow() + datetime.timedelta(minutes=1) - end_date = start_date + datetime.timedelta(minutes=LEASE_MIN_DURATION) - start_date = start_date.strftime(LEASE_DATE_FORMAT) - end_date = end_date.strftime(LEASE_DATE_FORMAT) - lease_name = 'scenario_test' - lease_data = { - 'lease_params': '{"name": "%s",' - '"start": "%s",' - '"end": "%s"}' - % (lease_name, start_date, end_date)} - - # boot the server and don't wait until it is active - self.boot_server_with_lease_data(lease_data, wait=False) - self.check_server_status('SHELVED_OFFLOADED') - - # now, wait until the server is active - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'ACTIVE') - self.check_lease_creation(lease_data) - - # wait for lease end - created_lease = self.get_lease_by_name(lease_name) - self.wait_for_lease_end(created_lease['id']) - - # check server final status - self.check_server_is_snapshoted() - waiters.wait_for_server_termination(self.servers_client, - self.server_id) - - # remove created snapshot - image_name = LEASE_IMAGE_PREFIX + self.server_name - self.remove_image_snapshot(image_name) - - # remove created lease - self.delete_lease(created_lease['id']) diff --git a/blazar_tempest_plugin/tests/scenario/test_reservation_concurrency.py b/blazar_tempest_plugin/tests/scenario/test_reservation_concurrency.py deleted file mode 100644 index aa589306..00000000 --- a/blazar_tempest_plugin/tests/scenario/test_reservation_concurrency.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2017 University of Chicago. 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. - -from multiprocessing.pool import ThreadPool - -from blazar_tempest_plugin.tests.scenario import ( - resource_reservation_scenario as rrs) - - -class TestReservationConcurrencyScenario(rrs.ResourceReservationScenarioTest): - """A Scenario test class checking Blazar handles concurrent requests.""" - - MAX_CONCURRENCY = 10 - - def setUp(self): - super(TestReservationConcurrencyScenario, self).setUp() - - def tearDown(self): - super(TestReservationConcurrencyScenario, self).tearDown() - - def test_concurrent_list_lease(self): - # run lease-list requests in parallel to check service concurrency - results = [] - pool = ThreadPool(self.MAX_CONCURRENCY) - for i in range(0, self.MAX_CONCURRENCY): - results.append( - pool.apply_async(self.reservation_client.list_lease, ())) - - pool.close() - pool.join() - results = [r.get() for r in results] - for r in results: - self.assertEqual('200', r.response['status']) diff --git a/playbooks/legacy/blazar-devstack-dsvm/run.yaml b/playbooks/legacy/blazar-devstack-dsvm/run.yaml index 5f237460..1e9c0271 100644 --- a/playbooks/legacy/blazar-devstack-dsvm/run.yaml +++ b/playbooks/legacy/blazar-devstack-dsvm/run.yaml @@ -30,6 +30,8 @@ cat << 'EOF' >>"/tmp/dg-local.conf" [[local|localrc]] enable_plugin blazar git://git.openstack.org/openstack/blazar + # Enable Tempest plugin + TEMPEST_PLUGINS='/opt/stack/new/blazar-tempest-plugin' EOF executable: /bin/bash chdir: '{{ ansible_user_dir }}/workspace' @@ -45,8 +47,8 @@ export PROJECTS="openstack/blazar $PROJECTS" export PROJECTS="openstack/blazar-nova $PROJECTS" export PROJECTS="openstack/python-blazarclient $PROJECTS" - export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1 - export DEVSTACK_GATE_TEMPEST_REGEX="blazar_tempest_plugin.tests" + export PROJECTS="openstack/blazar-tempest-plugin $PROJECTS" + export DEVSTACK_GATE_TEMPEST_REGEX="blazar_tempest_plugin" cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh executable: /bin/bash diff --git a/setup.cfg b/setup.cfg index 203ac73a..9ff40204 100644 --- a/setup.cfg +++ b/setup.cfg @@ -24,7 +24,6 @@ setup-hooks = pbr.hooks.setup_hook [files] packages = blazar - blazar_tempest_plugin [entry_points] console_scripts = @@ -59,9 +58,6 @@ oslo.config.opts = wsgi_scripts = blazar-api-wsgi = blazar.api.wsgi_app:init_app -tempest.test_plugins = - blazar_tests = blazar_tempest_plugin.plugin:BlazarTempestPlugin - [build_sphinx] all_files = 1 build-dir = doc/build