diff --git a/kingbird/tests/tempest/scenario/consts.py b/kingbird/tests/tempest/scenario/consts.py index dd0dc3c..e80853e 100644 --- a/kingbird/tests/tempest/scenario/consts.py +++ b/kingbird/tests/tempest/scenario/consts.py @@ -28,6 +28,8 @@ KEYPAIR_RESOURCE_TYPE = "keypair" IMAGE_RESOURCE_TYPE = "image" +FLAVOR_RESOURCE_TYPE = "flavor" + JOB_SUCCESS = "SUCCESS" JOB_PROGRESS = "IN_PROGRESS" diff --git a/kingbird/tests/tempest/scenario/quota_management/client_tests/base.py b/kingbird/tests/tempest/scenario/quota_management/client_tests/base.py index 9118b8d..0ba9723 100644 --- a/kingbird/tests/tempest/scenario/quota_management/client_tests/base.py +++ b/kingbird/tests/tempest/scenario/quota_management/client_tests/base.py @@ -160,11 +160,6 @@ class BaseKingbirdTest(api_version_utils.BaseMicroversionTest, cls.session, cls.regions, project_id) total_usages = cls.get_summation(resource_usage) for current_region in cls.regions: - # Calculate new limit for instance count - global_remaining_limit = GLOBAL_INSTANCE_LIMIT - \ - total_usages['instances'] - instances_limit = global_remaining_limit + resource_usage[ - current_region]['instances'] # Calculate new limit for network count global_remaining_limit = GLOBAL_NETWORK_LIMIT - \ total_usages['network'] @@ -175,6 +170,11 @@ class BaseKingbirdTest(api_version_utils.BaseMicroversionTest, total_usages['volumes'] volume_limit = global_remaining_limit + resource_usage[ current_region]['volumes'] + # Calculate new limit for instance count + global_remaining_limit = GLOBAL_INSTANCE_LIMIT - \ + total_usages['instances'] + instances_limit = global_remaining_limit + resource_usage[ + current_region]['instances'] calculated_quota_limits.update( {current_region: [instances_limit, network_limit, volume_limit]}) diff --git a/kingbird/tests/tempest/scenario/quota_management/client_tests/test_quota_management_api.py b/kingbird/tests/tempest/scenario/quota_management/client_tests/test_quota_management_api.py index a2fb42f..06bfbad 100644 --- a/kingbird/tests/tempest/scenario/quota_management/client_tests/test_quota_management_api.py +++ b/kingbird/tests/tempest/scenario/quota_management/client_tests/test_quota_management_api.py @@ -49,26 +49,34 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest): self.resource_ids["target_project_id"], new_quota) self.assertEqual(new_quota, actual_value) + self.delete_custom_kingbird_quota( + self.resource_ids["target_project_id"]) def test_kingbird_get_another_tenant_quota(self): + expected_value = dict(DEFAULT_QUOTAS) new_quota = {"instances": 15, "cores": 10} self.create_custom_kingbird_quota( self.resource_ids["target_project_id"], new_quota) - new_quota['project_id'] = self.resource_ids["target_project_id"] actual_value = self.get_kingbird_quota_another_tenant( self.resource_ids["target_project_id"]) - self.assertEqual(new_quota, actual_value) + expected_value.update(new_quota) + self.assertEqual(expected_value, actual_value) + self.delete_custom_kingbird_quota( + self.resource_ids["target_project_id"]) def test_kingbird_get_own_quota(self): + expected_value = dict(DEFAULT_QUOTAS) new_quota = {"instances": 15, "cores": 10} self.create_custom_kingbird_quota( self.resource_ids["target_project_id"], new_quota) - new_quota['project_id'] = self.resource_ids["target_project_id"] actual_value = self.get_own_kingbird_quota( self.resource_ids["target_project_id"]) - self.assertEqual(new_quota, actual_value) + expected_value.update(new_quota) + self.assertEqual(expected_value, actual_value) + self.delete_custom_kingbird_quota( + self.resource_ids["target_project_id"]) def test_kingbird_delete_all_method(self): new_quota = {"instances": 15, "cores": 10} @@ -79,9 +87,7 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest): self.resource_ids["target_project_id"]) actual_quota_after_delete = self.get_kingbird_quota_another_tenant( self.resource_ids["target_project_id"]) - expected_quota_after_delete = { - "project_id": self.resource_ids["target_project_id"] - } + expected_quota_after_delete = DEFAULT_QUOTAS self.assertEqual(expected_quota_after_delete, actual_quota_after_delete) @@ -118,8 +124,6 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest): self.resource_ids["project_id"]) expected_usage = self.get_usage_manually( self.resource_ids["project_id"]) - self.assertEqual(actual_usage["ram"][1], - expected_usage["quota_set"]["ram"]) self.assertEqual(actual_usage["cores"][1], expected_usage["quota_set"]["cores"]) self.assertEqual(actual_usage["instances"][1], @@ -130,20 +134,24 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest): expected_usage["quota_set"]["subnet"]) self.assertEqual(actual_usage["volumes"][1], expected_usage["quota_set"]["volumes"]) + self.assertEqual(actual_usage["ram"][1], + expected_usage["quota_set"]["ram"]) self.delete_instance() def test_quota_sync_for_project(self): - # Delete custom quota if there are any for this project - self.delete_custom_kingbird_quota( - self.resource_ids["project_id"]) + new_quota = {"instances": 10} + self.create_custom_kingbird_quota(self.resource_ids["project_id"], + new_quota) self.create_instance() self.quota_sync_for_project(self.resource_ids["project_id"]) + self.wait_sometime_for_sync() calculated_limits = self.calculate_quota_limits( self.resource_ids["project_id"]) - self.wait_sometime_for_sync() actual_limits = self.get_actual_limits( self.resource_ids["project_id"]) self.assertEqual(calculated_limits, actual_limits) + self.delete_custom_kingbird_quota( + self.resource_ids["project_id"]) self.delete_instance() def test_quota_exceed_after_sync(self): @@ -155,3 +163,5 @@ class KingbirdQMTestJSON(base.BaseKingbirdTest): self.assertRaises(novaclient.exceptions.Forbidden, self.create_instance, count=3) self.delete_instance() + self.delete_custom_kingbird_quota( + self.resource_ids["project_id"]) diff --git a/kingbird/tests/tempest/scenario/quota_management/sync_client.py b/kingbird/tests/tempest/scenario/quota_management/sync_client.py index edcfffd..5274191 100644 --- a/kingbird/tests/tempest/scenario/quota_management/sync_client.py +++ b/kingbird/tests/tempest/scenario/quota_management/sync_client.py @@ -125,7 +125,7 @@ def get_keystone_client(session): def create_instance(openstack_drivers, resource_ids, count=1): nova_client = openstack_drivers['nova'] server_ids = [] - image = nova_client.images.find(id=CONF.compute.image_ref) + image = nova_client.glance.find_image(CONF.compute.image_ref) flavor = nova_client.flavors.find(id=resource_ids['flavor_id']) try: for x in range(count): diff --git a/kingbird/tests/tempest/scenario/resource_management/sync_tests/base.py b/kingbird/tests/tempest/scenario/resource_management/sync_tests/base.py index e0f0e43..8203671 100644 --- a/kingbird/tests/tempest/scenario/resource_management/sync_tests/base.py +++ b/kingbird/tests/tempest/scenario/resource_management/sync_tests/base.py @@ -24,6 +24,7 @@ import six import tempest.test from tempest.api.compute import base as kp_base +from tempest.common import utils from tempest import config from tempest.lib.common.utils import data_utils from tempest.lib.common.utils import test_utils @@ -43,18 +44,19 @@ class BaseKingbirdClass(object): admin_client = self._get_admin_keystone() regions = self._get_regions(admin_client) target_regions = regions - target_regions.remove(self.client.region) + target_regions.remove(self.keypair_client.region) + source_region = self.keypair_client.region if keys: create_response = self._sync_job_create( - consts.KEYPAIR_RESOURCE_TYPE, target_regions, keys, - force=force) + consts.KEYPAIR_RESOURCE_TYPE, source_region, target_regions, + keys, force=force) result['keys'] = keys else: key_list = self._create_keypairs() # Now sync all the keypairs in other regions. create_response = self._sync_job_create( - consts.KEYPAIR_RESOURCE_TYPE, target_regions, key_list, - force=force) + consts.KEYPAIR_RESOURCE_TYPE, source_region, target_regions, + key_list, force=force) result['keys'] = key_list job_id = create_response.get('job_status').get('id') result['job_id'] = job_id @@ -62,6 +64,30 @@ class BaseKingbirdClass(object): result['target'] = target_regions return result + def _flavor_sync_job_create(self, force, admin_session, + existed_flavors=None): + result = dict() + admin_client = self._get_admin_keystone() + target_regions = self._get_regions(admin_client) + flavors, admin = self._create_flavor(admin_session) + target_regions.remove(admin.region) + source_region = admin.region + if existed_flavors: + create_response = self._sync_job_create( + consts.FLAVOR_RESOURCE_TYPE, source_region, target_regions, + existed_flavors, force) + result['flavors'] = existed_flavors + else: + create_response = self._sync_job_create( + consts.FLAVOR_RESOURCE_TYPE, source_region, target_regions, + flavors, force) + result['flavors'] = flavors + job_id = create_response.get('job_status').get('id') + result['job_id'] = job_id + result['admin'] = admin_client + result['target'] = target_regions + return result + def _image_sync_job_create(self, force, **kwargs): result = dict() images = self._create_images(**kwargs) @@ -69,10 +95,11 @@ class BaseKingbirdClass(object): regions = self._get_regions(admin_client) target_regions = regions target_regions.remove(self.client.region) + source_region = self.client.region # Now sync the created images in other regions. create_response = self._sync_job_create( - consts.IMAGE_RESOURCE_TYPE, target_regions, images.keys(), - force=force) + consts.IMAGE_RESOURCE_TYPE, source_region, target_regions, + images.keys(), force=force) job_id = create_response.get('job_status').get('id') result['job_id'] = job_id result['admin'] = admin_client @@ -86,16 +113,81 @@ class BaseKingbirdClass(object): status = job_list_resp.get('job_set')[0].get('sync_status') return status != consts.JOB_PROGRESS - def _sync_job_create(self, resource_type, target_regions, resource_list, - force): + def _check_template_job_status(self, job_id): + # Wait until the status of the each resource job is not "IN_PROGRESS" + job_list_resp = self.get_sync_job_detail(job_id) + for i in range(len(job_list_resp['job_set'])): + status = job_list_resp.get('job_set')[i].get('sync_status') + if(status == consts.JOB_PROGRESS): + return False + return True + + def _sync_job_create(self, resource_type, source_region, target_regions, + resource_list, force): # JSON body used to sync resource. body = {"resource_type": resource_type, "resources": resource_list, - "source": self.client.region, "force": force, + "source": source_region, "force": force, "target": target_regions} response = self.sync_resource(body) return response + def template_sync_job_create_non_admin(self, keypair, image, force): + # JSON body used to sync resource. + body = dict() + result = dict() + resource_set = list() + admin_client = self._get_admin_keystone() + regions = self._get_regions(admin_client) + keypair_target_regions = regions + keypair_target_regions.remove(self.keypair_client.region) + regions = self._get_regions(admin_client) + image_target_regions = regions + image_target_regions.remove(self.client.region) + keypair_set = {"resource_type": consts.KEYPAIR_RESOURCE_TYPE, + "resources": keypair, + "source": self.keypair_client.region, + "force": force, + "target": keypair_target_regions} + resource_set.append(keypair_set) + image_set = {"resource_type": consts.IMAGE_RESOURCE_TYPE, + "resources": image.keys(), + "source": self.client.region, + "force": force, + "target": image_target_regions} + resource_set.append(image_set) + body["Sync"] = resource_set + response = self.sync_resource(body) + job_id = response.get('job_status').get('id') + result['job_id'] = job_id + result['admin'] = admin_client + result['keypair_targets'] = keypair_target_regions + result['image_targets'] = image_target_regions + return result + + def template_sync_job_create_admin(self, flavor, force): + # JSON body used to sync resource. + body = dict() + result = dict() + resource_set = list() + admin_client = self._get_admin_keystone() + regions = self._get_regions(admin_client) + flavor_target_regions = regions + flavor_target_regions.remove(self.admin_flavors_client.region) + flavor_set = {"resource_type": consts.FLAVOR_RESOURCE_TYPE, + "resources": flavor, + "source": self.admin_flavors_client.region, + "force": force, + "target": flavor_target_regions} + resource_set.append(flavor_set) + body["Sync"] = resource_set + response = self.sync_resource(body) + job_id = response.get('job_status').get('id') + result['job_id'] = job_id + result['admin'] = admin_client + result['target'] = flavor_target_regions + return result + def _get_admin_keystone(self): auth = v3.Password( auth_url=CONF.identity.uri_v3, @@ -148,6 +240,7 @@ class BaseKingbirdClass(object): job_set = list() res = dict() for i in response: + result['resource_id'] = i.id result['resource'] = i.resource_name result['target_region'] = i.target_region result['sync_status'] = i.status @@ -166,7 +259,7 @@ class BaseKBKeypairTest(kp_base.BaseV2ComputeTest): @classmethod def setup_clients(cls): super(BaseKBKeypairTest, cls).setup_clients() - cls.client = cls.keypairs_client + cls.keypair_client = cls.keypairs_client def _create_keypairs(self): key_list = list() @@ -182,10 +275,10 @@ class BaseKBKeypairTest(kp_base.BaseV2ComputeTest): session=self.sess, region_name=region) source_keypair = nova_client.keypairs.get( - keypair, self.client.user_id) + keypair, self.keypair_client.user_id) self.assertEqual(source_keypair.name, keypair) - def _cleanup_resources(self, key_list, regions, user_id): + def _keypair_cleanup_resources(self, key_list, regions, user_id): for region in regions: for key in key_list: nova_client = nv_client.Client(NOVA_API_VERSION, @@ -194,7 +287,7 @@ class BaseKBKeypairTest(kp_base.BaseV2ComputeTest): nova_client.keypairs.delete(key, user_id) def _delete_keypair(self, keypair_name, **params): - self.client.delete_keypair(keypair_name, **params) + self.keypair_client.delete_keypair(keypair_name, **params) def create_keypair(self, keypair_name=None, pub_key=None, keypair_type=None, @@ -210,10 +303,10 @@ class BaseKBKeypairTest(kp_base.BaseV2ComputeTest): if user_id: kwargs.update({'user_id': user_id}) delete_params['user_id'] = user_id - body = self.client.create_keypair(**kwargs)['keypair'] + body = self.keypair_client.create_keypair(**kwargs)['keypair'] self.kingbird_client = kb_client.Client( - kingbird_url=KINGBIRD_URL, auth_token=self.client.token, - project_id=self.client.tenant_id) + kingbird_url=KINGBIRD_URL, auth_token=self.keypair_client.token, + project_id=self.keypair_client.tenant_id) self.addCleanup(self._delete_keypair, keypair_name, **delete_params) return body @@ -315,8 +408,8 @@ class BaseKBImageTest(tempest.test.BaseTestCase): target_regions.remove(self.client.region) # Now sync the created images in other regions. create_response = self._sync_job_create( - consts.IMAGE_RESOURCE_TYPE, target_regions, [ami_id], - force=force) + consts.IMAGE_RESOURCE_TYPE, self.client.region, target_regions, + [ami_id], force=force) job_id = create_response.get('job_status').get('id') result['job_id'] = job_id result['admin'] = admin_client @@ -392,3 +485,78 @@ class BaseKBImageTest(tempest.test.BaseTestCase): region_image.ramdisk_id) glance_client.images.delete(source_ari_image.id) glance_client.images.delete(target_image['id']) + + +class BaseKBFlavorsTest(kp_base.BaseV2ComputeAdminTest): + """Tests Flavors API Create and Delete that require admin privileges""" + + @classmethod + def skip_checks(cls): + super(BaseKBFlavorsTest, cls).skip_checks() + if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): + msg = "OS-FLV-EXT-DATA extension not enabled." + raise cls.skipException(msg) + + @classmethod + def resource_setup(cls): + super(BaseKBFlavorsTest, cls).resource_setup() + cls.flavor_client = cls.flavors_client + cls.flavor_name_prefix = 'test_flavor_' + cls.ram = 512 + cls.vcpus = 1 + cls.disk = 10 + cls.ephemeral = 10 + cls.swap = 1024 + cls.rxtx = 2 + + def _create_flavor(self, admin_session): + # Create a flavor and ensure it's details are listed + # This operation requires the user to have 'admin' role + flavor_list = list() + for i in range(2): + flavor_name = data_utils.rand_name(self.flavor_name_prefix) + # Create the flavor + self.create_flavor(name=flavor_name, ram=self.ram, + vcpus=self.vcpus, disk=self.disk, + ephemeral=self.ephemeral, swap=self.swap, + rxtx_factor=self.rxtx) + flavor_list.append(flavor_name) + if admin_session: + self.kingbird_client = kb_client.Client( + kingbird_url=KINGBIRD_URL, + auth_token=self.admin_flavors_client.token, + project_id=self.admin_flavors_client.tenant_id) + return flavor_list, self.admin_flavors_client + else: + self.kingbird_client = kb_client.Client( + kingbird_url=KINGBIRD_URL, + auth_token=self.flavors_client.token, + project_id=self.flavors_client.tenant_id) + return flavor_list, self.flavors_client + + def _check_flavors_in_target_region(self, target_regions, flavors, + admin_client, **properties): + for region in target_regions: + for flavor in flavors: + nova_client = nv_client.Client( + NOVA_API_VERSION, session=admin_client.session, + region_name=region) + res_id = nova_client.flavors.find(name=flavor) + source_flavor = nova_client.flavors.get(res_id) + self.assertEqual(source_flavor.name, flavor) + self.assertEqual(source_flavor.ram, properties["ram"]) + self.assertEqual(source_flavor.vcpus, properties["vcpus"]) + self.assertEqual(source_flavor.disk, properties["disk"]) + self.assertEqual(source_flavor.ephemeral, + properties["ephemeral"]) + self.assertEqual(source_flavor.swap, properties["swap"]) + self.assertEqual(source_flavor.rxtx_factor, properties["rxtx"]) + + def _flavor_cleanup_resources(self, flavors, regions, admin_client): + for region in regions: + for flavor in flavors: + nova_client = nv_client.Client( + NOVA_API_VERSION, session=admin_client.session, + region_name=region) + res_id = nova_client.flavors.find(name=flavor) + nova_client.flavors.delete(res_id) diff --git a/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_flavor_sync.py b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_flavor_sync.py new file mode 100644 index 0000000..3ac3ec3 --- /dev/null +++ b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_flavor_sync.py @@ -0,0 +1,216 @@ +# Copyright 2017 Ericsson AB. +# 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 kingbirdclient + +from tempest.lib import decorators + +from kingbird.tests.tempest.scenario import consts +from kingbird.tests.tempest.scenario.resource_management.sync_tests \ + import base +from kingbird.tests import utils + +FORCE = "True" +DEFAULT_FORCE = "False" + + +class KingbirdFlavorSyncTest(base.BaseKBFlavorsTest, + base.BaseKingbirdClass): + + @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5') + def test_kingbird_flavor_sync(self): + # Flavors are created by admin only + properties = dict() + properties["ram"] = self.ram + properties["vcpus"] = self.vcpus + properties["disk"] = self.disk + properties["ephemeral"] = self.ephemeral + properties["swap"] = self.swap + properties["rxtx"] = self.rxtx + admin_session = True + # Flavors created should be available in the response list + job_details = self._flavor_sync_job_create(FORCE, admin_session) + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Check for resources in target_regions + self._check_flavors_in_target_region(job_details['target'], + job_details['flavors'], + job_details['admin'], + **properties) + # Clean_up the database entries and resources + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('5024d38b-a46a-4ebb-84be-40c9929eb868') + def test_kingbird_flavor_sync_with_non_admin(self): + admin_session = False + self.assertRaisesRegexp(kingbirdclient.exceptions.APIException, + "403 *", + self._flavor_sync_job_create, + FORCE, admin_session) + + @decorators.idempotent_id('8eeb04d1-6371-4834-b2e1-0d2dbed98cd5') + def test_get_kingbird_sync_list(self): + # Flavors created should be available in the response list + admin_session = True + job_details = self._flavor_sync_job_create(FORCE, admin_session) + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + job_list_resp = self.get_sync_job_list() + self.assertEqual(job_list_resp['job_set'][0]['id'], + job_details['job_id']) + # Clean_up the database entries and resources + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('fed7e0b3-0d47-4729-9959-8b6b14230f48') + def test_get_sync_job_details(self): + admin_session = True + job_details = self._flavor_sync_job_create(FORCE, admin_session) + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + job_list_resp = self.get_sync_job_detail(job_details['job_id']) + flavor_list = job_details['flavors'] + for i in range(len(flavor_list)): + for j in range(len(job_list_resp.get('job_set'))): + if flavor_list[i] in job_list_resp.get('job_set')[j].values(): + self.assertEqual( + job_list_resp.get('job_set')[j].get('resource'), + flavor_list[i]) + self.assertEqual( + job_list_resp.get('job_set')[0].get('resource_type'), + consts.FLAVOR_RESOURCE_TYPE) + # Clean_up the database entries + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('f5701f6a-183b-41fe-b0ab-e0ddef3fbd86') + def test_get_active_jobs(self): + admin_session = True + job_details = self._flavor_sync_job_create(FORCE, admin_session) + active_job = self.get_sync_job_list(consts.JOB_ACTIVE) + status = active_job.get('job_set')[0].get('sync_status') + self.assertEqual(status, consts.JOB_PROGRESS) + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Clean_up the database entries + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('9e3fd15b-e170-4fa6-877c-ad4c22a137af') + def test_delete_active_jobs(self): + admin_session = True + job_details = self._flavor_sync_job_create(FORCE, admin_session) + self.assertRaisesRegexp(kingbirdclient.exceptions.APIException, + "406 *", + self.delete_db_entries, + job_details['job_id']) + # Actual result when we try and delete an active_job + # Clean_up the database entries + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Clean_up the database entries + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('adf565b1-c076-4273-b7d2-305cc144d0e2') + def test_delete_already_deleted_job(self): + admin_session = True + job_details = self._flavor_sync_job_create(FORCE, admin_session) + # Clean_up the database entries + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + self.delete_db_entries(job_details['job_id']) + self.assertRaisesRegexp(kingbirdclient.exceptions.APIException, + "404 *", + self.delete_db_entries, job_details['job_id']) + self._flavor_cleanup_resources(job_details['flavors'], + job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('fcdf50e0-1f7f-4844-8806-23de0fb221d6') + def test_flavor_sync_with_force_true(self): + admin_session = True + job_details_1 = self._flavor_sync_job_create(FORCE, admin_session) + job_id_1 = job_details_1['job_id'] + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % job_id_1)) + self.delete_db_entries(job_id_1) + job_details_2 = self._flavor_sync_job_create(FORCE, admin_session, + job_details_1['flavors']) + job_id_2 = job_details_2['job_id'] + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % job_id_2)) + # Clean_up the database entries + self.delete_db_entries(job_id_2) + self._flavor_cleanup_resources(job_details_2['flavors'], + job_details_2['target'], + job_details_2['admin']) + + @decorators.idempotent_id('a340a910-d367-401e-b79a-0a979a3ce65b') + def test_flavor_sync_with_force_false(self): + admin_session = True + job_details_1 = self._flavor_sync_job_create(DEFAULT_FORCE, + admin_session) + job_id_1 = job_details_1['job_id'] + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % job_id_1)) + self.delete_db_entries(job_id_1) + job_details_2 = self._flavor_sync_job_create(DEFAULT_FORCE, + admin_session, + job_details_1['flavors']) + job_id_2 = job_details_2['job_id'] + utils.wait_until_true( + lambda: self._check_job_status(), + exception=RuntimeError("Timed out waiting for job %s " % job_id_2)) + job_list_resp = self.get_sync_job_detail(job_id_2) + # This job fail because resoruce is already created. + # We can use force to recreate that resource. + self.assertEqual( + job_list_resp.get('job_set')[0].get('sync_status'), + consts.JOB_FAILURE) + self.assertEqual( + job_list_resp.get('job_set')[1].get('sync_status'), + consts.JOB_FAILURE) + # Clean_up the database entries + self.delete_db_entries(job_id_2) + self._flavor_cleanup_resources(job_details_2['flavors'], + job_details_2['target'], + job_details_2['admin']) diff --git a/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_keypair_sync_api.py b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_keypair_sync_api.py index eabad70..c9ef590 100644 --- a/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_keypair_sync_api.py +++ b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_keypair_sync_api.py @@ -43,8 +43,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, job_details['keys']) # Clean_up the database entries and resources self.delete_db_entries(job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('8eeb04d1-6371-4834-b2e1-0d2dbed98cd5') def test_get_kingbird_sync_list(self): @@ -58,8 +59,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, job_details['job_id']) # Clean_up the database entries and resources self.delete_db_entries(job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('fed7e0b3-0d47-4729-9959-8b6b14230f48') def test_get_sync_job_details(self): @@ -81,8 +83,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, consts.KEYPAIR_RESOURCE_TYPE) # Clean_up the database entries self.delete_db_entries(job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('f5701f6a-183b-41fe-b0ab-e0ddef3fbd86') def test_get_active_jobs(self): @@ -96,8 +99,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, job_details['job_id'])) # Clean_up the database entries self.delete_db_entries(job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('9e3fd15b-e170-4fa6-877c-ad4c22a137af') def test_delete_active_jobs(self): @@ -114,8 +118,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, job_details['job_id'])) # Clean_up the database entries self.delete_db_entries(job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('adf565b1-c076-4273-b7d2-305cc144d0e2') def test_delete_already_deleted_job(self): @@ -129,8 +134,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, self.assertRaisesRegexp(kingbirdclient.exceptions.APIException, "404 *", self.delete_db_entries, job_details['job_id']) - self._cleanup_resources(job_details['keys'], job_details['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details['keys'], + job_details['target'], + self.keypair_client.user_id) @decorators.idempotent_id('fcdf50e0-1f7f-4844-8806-23de0fb221d6') def test_keypair_sync_with_force_true(self): @@ -148,8 +154,9 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, exception=RuntimeError("Timed out waiting for job %s " % job_id_2)) # Clean_up the database entries self.delete_db_entries(job_id_2) - self._cleanup_resources(job_details_2['keys'], job_details_2['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details_2['keys'], + job_details_2['target'], + self.keypair_client.user_id) @decorators.idempotent_id('a340a910-d367-401e-b79a-0a979a3ce65b') def test_keypair_sync_with_force_false(self): @@ -176,5 +183,6 @@ class KingbirdKeyPairSyncTest(base.BaseKBKeypairTest, consts.JOB_FAILURE) # Clean_up the database entries self.delete_db_entries(job_id_2) - self._cleanup_resources(job_details_2['keys'], job_details_2['target'], - self.client.user_id) + self._keypair_cleanup_resources(job_details_2['keys'], + job_details_2['target'], + self.keypair_client.user_id) diff --git a/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_template_sync.py b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_template_sync.py new file mode 100644 index 0000000..eabc908 --- /dev/null +++ b/kingbird/tests/tempest/scenario/resource_management/sync_tests/test_template_sync.py @@ -0,0 +1,217 @@ +# Copyright 2017 Ericsson AB. +# 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 kingbirdclient + +from tempest import config +from tempest.lib import decorators + +from kingbird.tests.tempest.scenario import consts +from kingbird.tests.tempest.scenario.resource_management.sync_tests \ + import base +from kingbird.tests import utils + +CONF = config.CONF +FORCE = "True" +DEFAULT_FORCE = "False" + + +class KingbirdTemplateSyncTest(base.BaseKBKeypairTest, + base.BaseKBFlavorsTest, + base.BaseKBImageTest, + base.BaseKingbirdClass): + + @decorators.idempotent_id('5024d38b-a46a-4ebb-84be-40c9929eb865') + def test_kingbird_template_sync_with_non_admin(self): + # Keypairs and images can be created by non-admin + kwargs = { + "container_format": CONF.image.container_formats[3], + "disk_format": CONF.image.disk_formats[6], + "visibility": 'private' + } + keypairs = self._create_keypairs() + images = self._create_images(**kwargs) + job_details = self.template_sync_job_create_non_admin( + keypairs, images, FORCE) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Check for resources in target_regions + self._check_keypairs_in_target_region(job_details['keypair_targets'], + keypairs) + # Clean_up the database entries and resources + self._check_images_delete_target_region( + job_details['admin'], job_details['image_targets'], + images, FORCE, **kwargs) + self.delete_db_entries(job_details['job_id']) + self._keypair_cleanup_resources( + keypairs, job_details['keypair_targets'], + self.keypair_client.user_id) + + @decorators.idempotent_id('5024d38b-a46a-4ebb-84be-40c9929eb865') + def test_kingbird_template_sync_with_admin(self): + # Flavors should be created by admin + properties = dict() + properties["ram"] = self.ram + properties["vcpus"] = self.vcpus + properties["disk"] = self.disk + properties["ephemeral"] = self.ephemeral + properties["swap"] = self.swap + properties["rxtx"] = self.rxtx + admin_session = True + flavors = self._create_flavor(admin_session) + job_details = self.template_sync_job_create_admin(flavors[0], FORCE) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Check for resources in target_regions + self._check_flavors_in_target_region(job_details['target'], + flavors[0], + job_details['admin'], + **properties) + # Clean_up the database entries and resources + self.delete_db_entries(job_details['job_id']) + self._flavor_cleanup_resources(flavors[0], job_details['target'], + job_details['admin']) + + @decorators.idempotent_id('8eeb04d1-6371-4834-b2e1-0d2dbed98cd5') + def test_get_kingbird_sync_list(self): + # Keypairs and images can be created by non-admin + kwargs = { + "container_format": CONF.image.container_formats[3], + "disk_format": CONF.image.disk_formats[6], + "visibility": 'private' + } + keypairs = self._create_keypairs() + images = self._create_images(**kwargs) + job_details = self.template_sync_job_create_non_admin( + keypairs, images, DEFAULT_FORCE) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + job_list_resp = self.get_sync_job_list() + self.assertEqual(job_list_resp['job_set'][0]['id'], + job_details['job_id']) + # Clean_up the database entries and resources + self._check_images_delete_target_region( + job_details['admin'], job_details['image_targets'], + images, DEFAULT_FORCE, **kwargs) + self.delete_db_entries(job_details['job_id']) + self._keypair_cleanup_resources( + keypairs, job_details['keypair_targets'], + self.keypair_client.user_id) + + @decorators.idempotent_id('fed7e0b3-0d47-4729-9959-8b6b14230f48') + def test_get_sync_job_details(self): + # Keypairs and images can be created by non-admin + kwargs = { + "container_format": CONF.image.container_formats[3], + "disk_format": CONF.image.disk_formats[6], + "visibility": 'private' + } + keypairs = self._create_keypairs() + images = self._create_images(**kwargs) + image_list = images.values() + job_details = self.template_sync_job_create_non_admin( + keypairs, images, DEFAULT_FORCE) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + job_list_resp = self.get_sync_job_detail(job_details['job_id']) + for i in range(len(job_list_resp.get('job_set'))): + for j in range(len(keypairs)): + if keypairs[j] in job_list_resp.get('job_set')[i].values(): + self.assertEqual( + job_list_resp.get('job_set')[i].get('resource_type'), + consts.KEYPAIR_RESOURCE_TYPE) + self.assertEqual( + job_list_resp.get('job_set')[i].get('resource'), + keypairs[j]) + for k in range(len(images)): + if image_list[k] in job_list_resp.get('job_set')[i].values(): + self.assertEqual( + job_list_resp.get('job_set')[i].get('resource_type'), + consts.IMAGE_RESOURCE_TYPE) + self.assertEqual( + job_list_resp.get('job_set')[i].get('resource'), + image_list[k]) + # Clean_up the database entries and resources + self._check_images_delete_target_region( + job_details['admin'], job_details['image_targets'], + images, DEFAULT_FORCE, **kwargs) + self.delete_db_entries(job_details['job_id']) + self._keypair_cleanup_resources( + keypairs, job_details['keypair_targets'], + self.keypair_client.user_id) + + @decorators.idempotent_id('f5701f6a-183b-41fe-b0ab-e0ddef3fbd89') + def test_get_active_jobs(self): + # Keypairs and images can be created by non-admin + kwargs = { + "container_format": CONF.image.container_formats[3], + "disk_format": CONF.image.disk_formats[6], + "visibility": 'private' + } + keypairs = self._create_keypairs() + images = self._create_images(**kwargs) + job_details = self.template_sync_job_create_non_admin( + keypairs, images, FORCE) + active_job = self.get_sync_job_list(consts.JOB_ACTIVE) + status = active_job.get('job_set')[0].get('sync_status') + self.assertEqual(status, consts.JOB_PROGRESS) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Clean_up the database entries + self._check_images_delete_target_region( + job_details['admin'], job_details['image_targets'], + images, FORCE, **kwargs) + self.delete_db_entries(job_details['job_id']) + self._keypair_cleanup_resources( + keypairs, job_details['keypair_targets'], + self.keypair_client.user_id) + + @decorators.idempotent_id('adf565b1-c076-4273-b7d2-305cc144d0e2') + def test_delete_already_deleted_job(self): + # Keypairs and images can be created by non-admin + kwargs = { + "container_format": CONF.image.container_formats[3], + "disk_format": CONF.image.disk_formats[6], + "visibility": 'private' + } + keypairs = self._create_keypairs() + images = self._create_images(**kwargs) + job_details = self.template_sync_job_create_non_admin( + keypairs, images, FORCE) + utils.wait_until_true( + lambda: self._check_template_job_status(job_details['job_id']), + exception=RuntimeError("Timed out waiting for job %s " % + job_details['job_id'])) + # Clean_up the database entries + self.delete_db_entries(job_details['job_id']) + self.assertRaisesRegexp(kingbirdclient.exceptions.APIException, + "404 *", + self.delete_db_entries, job_details['job_id']) + self._check_images_delete_target_region( + job_details['admin'], job_details['image_targets'], + images, FORCE, **kwargs) + self._keypair_cleanup_resources( + keypairs, job_details['keypair_targets'], + self.keypair_client.user_id)