From 81aaae7fc26d8d09082428f8adf9b3f572f20708 Mon Sep 17 00:00:00 2001 From: bkopilov Date: Fri, 15 May 2015 23:46:25 +0300 Subject: [PATCH] Add support for image deactivate and reactivate https://wiki.openstack.org/wiki/Glance-deactivate-image Adding the api support for these commands. Deactivate and reactivate image action is done by admin tenant. - Added admin folder to image tests - Added support for admin image classes for v1 and v2 - Added config deactivate_image , this feature is not running on icehouse - Added a testcase for image deactivate. Depends-On: Ia1d3d811bd57d3de16d397cfab341e8d0f17cb69 Change-Id: I7880f0e2646ce8660e035ebaa19a60f5bf271b64 --- etc/tempest.conf.sample | 4 ++ tempest/api/image/admin/__init__.py | 0 tempest/api/image/admin/v2/__init__.py | 0 tempest/api/image/admin/v2/test_images.py | 55 +++++++++++++++++++ tempest/api/image/base.py | 20 +++++++ tempest/config.py | 4 ++ .../services/image/v2/json/image_client.py | 12 ++++ 7 files changed, 95 insertions(+) create mode 100644 tempest/api/image/admin/__init__.py create mode 100644 tempest/api/image/admin/v2/__init__.py create mode 100644 tempest/api/image/admin/v2/test_images.py diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample index b3aca42b0b..371ff97e52 100644 --- a/etc/tempest.conf.sample +++ b/etc/tempest.conf.sample @@ -647,6 +647,10 @@ # Is the v1 image API enabled (boolean value) #api_v1 = true +# Is the deactivate-image feature enabled. The feature has been +# integrated since Kilo. (boolean value) +#deactivate_image = false + [input-scenario] diff --git a/tempest/api/image/admin/__init__.py b/tempest/api/image/admin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tempest/api/image/admin/v2/__init__.py b/tempest/api/image/admin/v2/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tempest/api/image/admin/v2/test_images.py b/tempest/api/image/admin/v2/test_images.py new file mode 100644 index 0000000000..83efc7d0b5 --- /dev/null +++ b/tempest/api/image/admin/v2/test_images.py @@ -0,0 +1,55 @@ +# Copyright 2015 Red Hat, Inc. +# 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 six import moves +from tempest_lib.common.utils import data_utils +import testtools + +from tempest.api.image import base +from tempest import config +from tempest import test + + +CONF = config.CONF + + +class BasicAdminOperationsImagesTest(base.BaseV2ImageAdminTest): + + """ + Here we test admin operations of images + """ + @testtools.skipUnless(CONF.image_feature_enabled.deactivate_image, + 'deactivate-image is not available.') + @test.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0') + def test_admin_deactivate_reactivate_image(self): + # Create image by non-admin tenant + image_name = data_utils.rand_name('image') + body = self.client.create_image(name=image_name, + container_format='bare', + disk_format='raw', + visibility='private') + image_id = body['id'] + self.addCleanup(self.client.delete_image, image_id) + # upload an image file + image_file = moves.cStringIO(data_utils.random_bytes()) + self.client.store_image(image_id, image_file) + # deactivate image + self.admin_client.deactivate_image(image_id) + body = self.client.show_image(image_id) + self.assertEqual("deactivated", body['status']) + # reactivate image + self.admin_client.reactivate_image(image_id) + body = self.client.show_image(image_id) + self.assertEqual("active", body['status']) diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py index 00959d9455..dc38cabea7 100644 --- a/tempest/api/image/base.py +++ b/tempest/api/image/base.py @@ -158,3 +158,23 @@ class BaseV2MemberImageTest(BaseV2ImageTest): image_id = image['id'] self.addCleanup(self.os_img_client.delete_image, image_id) return image_id + + +class BaseV1ImageAdminTest(BaseImageTest): + credentials = ['admin', 'primary'] + + @classmethod + def setup_clients(cls): + super(BaseV1ImageAdminTest, cls).setup_clients() + cls.client = cls.os.image_client + cls.admin_client = cls.os_adm.image_client + + +class BaseV2ImageAdminTest(BaseImageTest): + credentials = ['admin', 'primary'] + + @classmethod + def setup_clients(cls): + super(BaseV2ImageAdminTest, cls).setup_clients() + cls.client = cls.os.image_client_v2 + cls.admin_client = cls.os_adm.image_client_v2 diff --git a/tempest/config.py b/tempest/config.py index 603ccd2796..69389bd0ac 100644 --- a/tempest/config.py +++ b/tempest/config.py @@ -433,6 +433,10 @@ ImageFeaturesGroup = [ cfg.BoolOpt('api_v1', default=True, help="Is the v1 image API enabled"), + cfg.BoolOpt('deactivate_image', + default=False, + help="Is the deactivate-image feature enabled." + " The feature has been integrated since Kilo."), ] network_group = cfg.OptGroup(name='network', diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py index a4cb48c4d1..5dedbd9838 100644 --- a/tempest/services/image/v2/json/image_client.py +++ b/tempest/services/image/v2/json/image_client.py @@ -96,6 +96,18 @@ class ImageClientV2JSON(service_client.ServiceClient): body = json.loads(body) return service_client.ResponseBody(resp, body) + def deactivate_image(self, image_id): + url = 'v2/images/%s/actions/deactivate' % image_id + resp, body = self.post(url, None) + self.expected_success(204, resp.status) + return service_client.ResponseBody(resp, body) + + def reactivate_image(self, image_id): + url = 'v2/images/%s/actions/reactivate' % image_id + resp, body = self.post(url, None) + self.expected_success(204, resp.status) + return service_client.ResponseBody(resp, body) + def delete_image(self, image_id): url = 'v2/images/%s' % image_id resp, _ = self.delete(url)