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
This commit is contained in:
Chris St. Pierre 2016-03-15 08:56:58 -05:00
parent 81ae39a03b
commit c7c8f577c5
2 changed files with 73 additions and 33 deletions

View File

@ -16,8 +16,8 @@ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import utils as rutils from rally.common import utils as rutils
from rally import consts from rally import consts
from rally.plugins.openstack.cleanup import manager as resource_manager from rally import osclients
from rally.plugins.openstack.scenarios.glance import utils as glance_utils from rally.plugins.openstack.wrappers import glance as glance_wrapper
from rally.task import context from rally.task import context
@ -78,10 +78,10 @@ class ImageGenerator(context.Context):
for user, tenant_id in rutils.iterate_per_tenants( for user, tenant_id in rutils.iterate_per_tenants(
self.context["users"]): self.context["users"]):
current_images = [] current_images = []
glance_scenario = glance_utils.GlanceScenario( clients = osclients.Clients(
{"user": user, "task": user["credential"],
self.context["task"], api_info=self.context["config"].get("api_versions"))
"config": self.context["config"]}) glance_wrap = glance_wrapper.wrap(clients.glance, self)
kwargs = self.config.get("image_args", {}) kwargs = self.config.get("image_args", {})
if self.config.get("min_ram") is not None: if self.config.get("min_ram") is not None:
@ -101,7 +101,7 @@ class ImageGenerator(context.Context):
else: else:
cur_name = self.generate_random_name() cur_name = self.generate_random_name()
image = glance_scenario._create_image( image = glance_wrap.create_image(
image_container, image_url, image_type, image_container, image_url, image_type,
name=cur_name, **kwargs) name=cur_name, **kwargs)
current_images.append(image.id) current_images.append(image.id)
@ -110,6 +110,11 @@ class ImageGenerator(context.Context):
@logging.log_task_wrapper(LOG.info, _("Exit context: `Images`")) @logging.log_task_wrapper(LOG.info, _("Exit context: `Images`"))
def cleanup(self): def cleanup(self):
# TODO(boris-42): Delete only resources created by this context for user, tenant_id in rutils.iterate_per_tenants(
resource_manager.cleanup(names=["glance.images"], self.context["users"]):
users=self.context.get("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))

View File

@ -50,15 +50,17 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
{"min_disk": 1, "min_ram": 2}, {"min_disk": 1, "min_ram": 2},
{"image_name": "foo"}, {"image_name": "foo"},
{"tenants": 3, "users_per_tenant": 2, "images_per_tenant": 5}, {"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 @ddt.unpack
@mock.patch("%s.utils.GlanceScenario._create_image" % SCN) @mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
def test_setup(self, mock_glance_scenario__create_image, @mock.patch("rally.osclients.Clients")
def test_setup(self, mock_clients, mock_wrap,
image_container="bare", image_type="qcow2", image_container="bare", image_type="qcow2",
image_url="http://example.com/fake/url", image_url="http://example.com/fake/url",
tenants=1, users_per_tenant=1, images_per_tenant=1, tenants=1, users_per_tenant=1, images_per_tenant=1,
image_name=None, min_ram=None, min_disk=None, image_name=None, min_ram=None, min_disk=None,
image_args=None): image_args=None, api_versions=None):
tenant_data = self._gen_tenants(tenants) tenant_data = self._gen_tenants(tenants)
users = [] users = []
for tenant_id in tenant_data: for tenant_id in tenant_data:
@ -86,6 +88,8 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
"users": users, "users": users,
"tenants": tenant_data "tenants": tenant_data
}) })
if api_versions:
self.context["config"]["api_versions"] = api_versions
expected_image_args = {} expected_image_args = {}
if image_args is not None: if image_args is not None:
@ -100,52 +104,70 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
self.context["config"]["images"]["min_disk"] = min_disk self.context["config"]["images"]["min_disk"] = min_disk
expected_image_args["min_disk"] = min_disk expected_image_args["min_disk"] = min_disk
wrapper = mock_wrap.return_value
new_context = copy.deepcopy(self.context) new_context = copy.deepcopy(self.context)
for tenant_id in new_context["tenants"].keys(): for tenant_id in new_context["tenants"].keys():
new_context["tenants"][tenant_id]["images"] = [ new_context["tenants"][tenant_id]["images"] = [
mock_glance_scenario__create_image.return_value.id wrapper.create_image.return_value.id
] * images_per_tenant ] * images_per_tenant
images_ctx = images.ImageGenerator(self.context) images_ctx = images.ImageGenerator(self.context)
images_ctx.setup() images_ctx.setup()
self.assertEqual(new_context, self.context) self.assertEqual(new_context, self.context)
mock_glance_scenario__create_image.assert_has_calls(
[mock.call(image_container, image_url, image_type, wrapper_calls = []
name=mock.ANY, wrapper_calls.extend([mock.call(mock_clients.return_value.glance,
**expected_image_args)] * tenants * images_per_tenant) 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: 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)) 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) @ddt.data(
def test_cleanup(self, mock_cleanup): {},
{"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 tenants_count = 2
users_per_tenant = 5 users_per_tenant = 5
images_per_tenant = 5 images_per_tenant = 5
tenants = self._gen_tenants(tenants_count) tenants = self._gen_tenants(tenants_count)
users = [] users = []
for id_ in tenants: created_images = []
for tenant_id in tenants:
for i in range(users_per_tenant): for i in range(users_per_tenant):
users.append({"id": i, "tenant_id": id_, users.append({"id": i, "tenant_id": tenant_id,
"credential": "credential"}) "credential": mock.MagicMock()})
tenants[id_].setdefault("images", []) tenants[tenant_id].setdefault("images", [])
for j in range(images_per_tenant): 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({ self.context.update({
"config": { "config": {
"users": { "users": {
"tenants": 2, "tenants": tenants_count,
"users_per_tenant": 5, "users_per_tenant": users_per_tenant,
"concurrent": 10, "concurrent": 10,
}, },
"images": { "images": {
"image_url": "mock_url", "image_url": "mock_url",
"image_type": "qcow2", "image_type": "qcow2",
"image_container": "bare", "image_container": "bare",
"images_per_tenant": 5, "images_per_tenant": images_per_tenant,
"image_name": "some_name", "image_name": "some_name",
"min_ram": 128, "min_ram": 128,
"min_disk": 1, "min_disk": 1,
@ -157,8 +179,21 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
"users": users, "users": users,
"tenants": tenants "tenants": tenants
}) })
if api_versions:
self.context["config"]["api_versions"] = api_versions
images_ctx = images.ImageGenerator(self.context) images_ctx = images.ImageGenerator(self.context)
images_ctx.cleanup() 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)