From 7bde7bf537e084c96e9e882f159346d4398657fe Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Mon, 15 Feb 2021 08:44:47 -0800 Subject: [PATCH] Add image task validation Glance is adding a /image/$image/tasks API to make it easier to consume the import API. This fetches the tasks after glance-direct import, and validates that they look like we expect. Because this is only supported after v2.12, we check for that before doing the validation. To make that easier, this adds a has_version() helper to the VersionsClient. Change-Id: I2850f0659e82bf5c5a1005de0a063e7fcacadb51 --- ...d-versions-and-tasks-ac289dbfe1c899cc.yaml | 6 +++ tempest/api/image/v2/test_images.py | 19 +++++++- .../lib/services/image/v2/images_client.py | 8 ++++ .../lib/services/image/v2/versions_client.py | 10 ++++ .../services/image/v2/test_images_client.py | 46 +++++++++++++++++++ .../services/image/v2/test_versions_client.py | 12 +++++ 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml diff --git a/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml b/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml new file mode 100644 index 0000000000..fde6193a17 --- /dev/null +++ b/releasenotes/notes/image-client-add-versions-and-tasks-ac289dbfe1c899cc.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Adds a method to images_client to get tasks relevant to a given image. Also adds + has_version() method to image versions_client to probe for availability of a given + API version. diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py index 8dba311bae..efa23bb83a 100644 --- a/tempest/api/image/v2/test_images.py +++ b/tempest/api/image/v2/test_images.py @@ -96,9 +96,26 @@ class ImportImagesTest(base.BaseV2ImageTest): image_id = self._stage_and_check() # import image from staging to backend - self.client.image_import(image_id, method='glance-direct') + resp = self.client.image_import(image_id, method='glance-direct') waiters.wait_for_image_imported_to_stores(self.client, image_id) + if not self.versions_client.has_version('2.12'): + # API is not new enough to support image/tasks API + LOG.info('Glance does not support v2.12, so I am unable to ' + 'validate the image/tasks API.') + return + + # Make sure we can access the task and that some of the key + # fields look legit. + tasks = self.client.show_image_tasks(image_id) + self.assertEqual(1, len(tasks['tasks'])) + task = tasks['tasks'][0] + self.assertEqual('success', task['status']) + self.assertEqual(resp.response['x-openstack-request-id'], + task['request_id']) + self.assertEqual('glance-direct', + task['input']['import_req']['method']['name']) + @decorators.idempotent_id('f6feb7a4-b04f-4706-a011-206129f83e62') def test_image_web_download_import(self): """Test 'web-download' import functionalities diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py index fa3bb8c5f5..abf427cd9c 100644 --- a/tempest/lib/services/image/v2/images_client.py +++ b/tempest/lib/services/image/v2/images_client.py @@ -121,6 +121,14 @@ class ImagesClient(rest_client.RestClient): body = json.loads(body) return rest_client.ResponseBody(resp, body) + def show_image_tasks(self, image_id): + """Show image tasks.""" + url = 'images/%s/tasks' % image_id + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + def is_resource_deleted(self, id): try: self.show_image(id) diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py index 1b7f8064f0..98b4fb6209 100644 --- a/tempest/lib/services/image/v2/versions_client.py +++ b/tempest/lib/services/image/v2/versions_client.py @@ -30,3 +30,13 @@ class VersionsClient(rest_client.RestClient): self.expected_success(300, resp.status) body = json.loads(body) return rest_client.ResponseBody(resp, body) + + def has_version(self, version): + """Return True if a version is supported.""" + version = 'v%s' % version + supported = ['SUPPORTED', 'CURRENT'] + versions = self.list_versions() + for version_struct in versions['versions']: + if version_struct['id'] == version: + return version_struct['status'] in supported + return False diff --git a/tempest/tests/lib/services/image/v2/test_images_client.py b/tempest/tests/lib/services/image/v2/test_images_client.py index 7ee61d2577..5b162f83c3 100644 --- a/tempest/tests/lib/services/image/v2/test_images_client.py +++ b/tempest/tests/lib/services/image/v2/test_images_client.py @@ -105,6 +105,44 @@ class TestImagesClient(base.BaseServiceTest): "first": "/v2/images" } + FAKE_SHOW_IMAGE_TASKS = { + "tasks": [ + { + "id": "ee22890e-8948-4ea6-9668-831f973c84f5", + "image_id": "dddddddd-dddd-dddd-dddd-dddddddddddd", + "request-id": "rrrrrrr-rrrr-rrrr-rrrr-rrrrrrrrrrrr", + "user": "uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu", + "type": "api_image_import", + "status": "processing", + "owner": "64f0efc9955145aeb06f297a8a6fe402", + "expires_at": None, + "created_at": "2020-12-18T05:20:38.000000", + "updated_at": "2020-12-18T05:25:39.000000", + "deleted_at": None, + "deleted": False, + "input": { + "image_id": "829c729b-ebc4-4cc7-a164-6f43f1149b17", + "import_req": { + "method": { + "name": "copy-image", + }, + "all_stores": True, + "all_stores_must_succeed": False, + }, + "backend": [ + "fast", + "cheap", + "slow", + "reliable", + "common", + ] + }, + "result": None, + "message": "Copied 15 MiB", + } + ] + } + FAKE_TAG_NAME = "fake tag" def setUp(self): @@ -230,3 +268,11 @@ class TestImagesClient(base.BaseServiceTest): def test_list_images_with_bytes_body(self): self._test_list_images(bytes_body=True) + + def test_show_image_tasks(self): + self.check_service_client_function( + self.client.show_image_tasks, + 'tempest.lib.common.rest_client.RestClient.get', + self.FAKE_SHOW_IMAGE_TASKS, + True, + image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8") diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py index 6234b0699d..98c558acd7 100644 --- a/tempest/tests/lib/services/image/v2/test_versions_client.py +++ b/tempest/tests/lib/services/image/v2/test_versions_client.py @@ -12,6 +12,8 @@ # License for the specific language governing permissions and limitations # under the License. +import fixtures + from tempest.lib.services.image.v2 import versions_client from tempest.tests.lib import fake_auth_provider from tempest.tests.lib.services import base @@ -92,3 +94,13 @@ class TestVersionsClient(base.BaseServiceTest): def test_list_versions_with_bytes_body(self): self._test_list_versions(bytes_body=True) + + def test_has_version(self): + mocked_r = self.create_response(self.FAKE_VERSIONS_INFO, False, + 300, None) + self.useFixture(fixtures.MockPatch( + 'tempest.lib.common.rest_client.RestClient.raw_request', + return_value=mocked_r)) + + self.assertTrue(self.client.has_version('2.1')) + self.assertFalse(self.client.has_version('9.9'))