From c7c8f577c53907bee0c8d89bccc591e630ef95a3 Mon Sep 17 00:00:00 2001 From: "Chris St. Pierre" Date: Tue, 15 Mar 2016 08:56:58 -0500 Subject: [PATCH] Delete only images created by images context Since the images context allows creating images with arbitrary names, name-based cleanup won't work for it, so we have to delete the exact list of images that it created instead. Implements: blueprint cleanup-refactoring Change-Id: I3caa0e73a124bb1317492262ea45cd2a4d116721 --- .../openstack/context/glance/images.py | 25 +++--- .../openstack/context/glance/test_images.py | 81 +++++++++++++------ 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/rally/plugins/openstack/context/glance/images.py b/rally/plugins/openstack/context/glance/images.py index d1e00b5e..bfe17c48 100644 --- a/rally/plugins/openstack/context/glance/images.py +++ b/rally/plugins/openstack/context/glance/images.py @@ -16,8 +16,8 @@ from rally.common.i18n import _ from rally.common import logging from rally.common import utils as rutils from rally import consts -from rally.plugins.openstack.cleanup import manager as resource_manager -from rally.plugins.openstack.scenarios.glance import utils as glance_utils +from rally import osclients +from rally.plugins.openstack.wrappers import glance as glance_wrapper from rally.task import context @@ -78,10 +78,10 @@ class ImageGenerator(context.Context): for user, tenant_id in rutils.iterate_per_tenants( self.context["users"]): current_images = [] - glance_scenario = glance_utils.GlanceScenario( - {"user": user, "task": - self.context["task"], - "config": self.context["config"]}) + clients = osclients.Clients( + user["credential"], + api_info=self.context["config"].get("api_versions")) + glance_wrap = glance_wrapper.wrap(clients.glance, self) kwargs = self.config.get("image_args", {}) if self.config.get("min_ram") is not None: @@ -101,7 +101,7 @@ class ImageGenerator(context.Context): else: cur_name = self.generate_random_name() - image = glance_scenario._create_image( + image = glance_wrap.create_image( image_container, image_url, image_type, name=cur_name, **kwargs) current_images.append(image.id) @@ -110,6 +110,11 @@ class ImageGenerator(context.Context): @logging.log_task_wrapper(LOG.info, _("Exit context: `Images`")) def cleanup(self): - # TODO(boris-42): Delete only resources created by this context - resource_manager.cleanup(names=["glance.images"], - users=self.context.get("users", [])) + for user, tenant_id in rutils.iterate_per_tenants( + self.context["users"]): + clients = osclients.Clients( + user["credential"], + api_info=self.context["config"].get("api_versions")) + glance_wrap = glance_wrapper.wrap(clients.glance, self) + for image in self.context["tenants"][tenant_id].get("images", []): + glance_wrap.delete_image(glance_wrap.get_image(image)) diff --git a/tests/unit/plugins/openstack/context/glance/test_images.py b/tests/unit/plugins/openstack/context/glance/test_images.py index 5df95237..12d71cd9 100644 --- a/tests/unit/plugins/openstack/context/glance/test_images.py +++ b/tests/unit/plugins/openstack/context/glance/test_images.py @@ -50,15 +50,17 @@ class ImageGeneratorTestCase(test.ScenarioTestCase): {"min_disk": 1, "min_ram": 2}, {"image_name": "foo"}, {"tenants": 3, "users_per_tenant": 2, "images_per_tenant": 5}, - {"image_args": {"min_disk": 1, "min_ram": 2, "visibility": "public"}}) + {"image_args": {"min_disk": 1, "min_ram": 2, "visibility": "public"}}, + {"api_versions": {"glance": {"version": 2, "service_type": "image"}}}) @ddt.unpack - @mock.patch("%s.utils.GlanceScenario._create_image" % SCN) - def test_setup(self, mock_glance_scenario__create_image, + @mock.patch("rally.plugins.openstack.wrappers.glance.wrap") + @mock.patch("rally.osclients.Clients") + def test_setup(self, mock_clients, mock_wrap, image_container="bare", image_type="qcow2", image_url="http://example.com/fake/url", tenants=1, users_per_tenant=1, images_per_tenant=1, image_name=None, min_ram=None, min_disk=None, - image_args=None): + image_args=None, api_versions=None): tenant_data = self._gen_tenants(tenants) users = [] for tenant_id in tenant_data: @@ -86,6 +88,8 @@ class ImageGeneratorTestCase(test.ScenarioTestCase): "users": users, "tenants": tenant_data }) + if api_versions: + self.context["config"]["api_versions"] = api_versions expected_image_args = {} if image_args is not None: @@ -100,52 +104,70 @@ class ImageGeneratorTestCase(test.ScenarioTestCase): self.context["config"]["images"]["min_disk"] = min_disk expected_image_args["min_disk"] = min_disk + wrapper = mock_wrap.return_value + new_context = copy.deepcopy(self.context) for tenant_id in new_context["tenants"].keys(): new_context["tenants"][tenant_id]["images"] = [ - mock_glance_scenario__create_image.return_value.id + wrapper.create_image.return_value.id ] * images_per_tenant images_ctx = images.ImageGenerator(self.context) images_ctx.setup() self.assertEqual(new_context, self.context) - mock_glance_scenario__create_image.assert_has_calls( - [mock.call(image_container, image_url, image_type, - name=mock.ANY, - **expected_image_args)] * tenants * images_per_tenant) + + wrapper_calls = [] + wrapper_calls.extend([mock.call(mock_clients.return_value.glance, + images_ctx)] * tenants) + wrapper_calls.extend( + [mock.call().create_image( + image_container, image_url, image_type, + name=mock.ANY, **expected_image_args)] * + tenants * images_per_tenant) + mock_wrap.assert_has_calls(wrapper_calls, any_order=True) + if image_name: - for args in mock_glance_scenario__create_image.call_args_list: + for args in wrapper.create_image.call_args_list: self.assertTrue(args[1]["name"].startswith(image_name)) + mock_clients.assert_has_calls( + [mock.call(mock.ANY, api_info=api_versions)] * tenants) - @mock.patch("%s.images.resource_manager.cleanup" % CTX) - def test_cleanup(self, mock_cleanup): - + @ddt.data( + {}, + {"api_versions": {"glance": {"version": 2, "service_type": "image"}}}) + @ddt.unpack + @mock.patch("rally.plugins.openstack.wrappers.glance.wrap") + @mock.patch("rally.osclients.Clients") + def test_cleanup(self, mock_clients, mock_wrap, api_versions=None): tenants_count = 2 users_per_tenant = 5 images_per_tenant = 5 tenants = self._gen_tenants(tenants_count) users = [] - for id_ in tenants: + created_images = [] + for tenant_id in tenants: for i in range(users_per_tenant): - users.append({"id": i, "tenant_id": id_, - "credential": "credential"}) - tenants[id_].setdefault("images", []) + users.append({"id": i, "tenant_id": tenant_id, + "credential": mock.MagicMock()}) + tenants[tenant_id].setdefault("images", []) for j in range(images_per_tenant): - tenants[id_]["images"].append("uuid") + image = mock.Mock() + created_images.append(image) + tenants[tenant_id]["images"].append(image) self.context.update({ "config": { "users": { - "tenants": 2, - "users_per_tenant": 5, + "tenants": tenants_count, + "users_per_tenant": users_per_tenant, "concurrent": 10, }, "images": { "image_url": "mock_url", "image_type": "qcow2", "image_container": "bare", - "images_per_tenant": 5, + "images_per_tenant": images_per_tenant, "image_name": "some_name", "min_ram": 128, "min_disk": 1, @@ -157,8 +179,21 @@ class ImageGeneratorTestCase(test.ScenarioTestCase): "users": users, "tenants": tenants }) + if api_versions: + self.context["config"]["api_versions"] = api_versions images_ctx = images.ImageGenerator(self.context) images_ctx.cleanup() - mock_cleanup.assert_called_once_with(names=["glance.images"], - users=self.context["users"]) + + wrapper = mock_wrap.return_value + wrapper_calls = [] + wrapper_calls.extend([mock.call(mock_clients.return_value.glance, + images_ctx)] * tenants_count) + wrapper_calls.extend([mock.call().get_image(i) + for i in created_images]) + wrapper_calls.extend( + [mock.call().delete_image(wrapper.get_image.return_value)] * + len(created_images)) + mock_wrap.assert_has_calls(wrapper_calls, any_order=True) + mock_clients.assert_has_calls( + [mock.call(mock.ANY, api_info=api_versions)] * tenants_count)