From 9ea493060f36e5a369d29148bc7797e31d5964fd Mon Sep 17 00:00:00 2001 From: Feodor Tersin Date: Fri, 4 Sep 2015 16:04:49 +0300 Subject: [PATCH] Translate Glance and internal image statuses to valid EC2 states Glance image statuses are not compatible with AWS EC2. Now they will be translated to appropriated EC2 states. Also following to Nova EC2, ec2api uses internal states to indicate progress of image registration. These states must be translated to valid EC2 states, but this had been forgotten when image operations was ported to ec2api. Change-Id: I3e4bdaa84e654ffe6f7a8ed0b1e461f161829d90 --- ec2api/api/image.py | 29 +++++++++++++++++++++----- ec2api/tests/unit/test_image.py | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) diff --git a/ec2api/api/image.py b/ec2api/api/image.py index 85ae522c..c7215ca1 100644 --- a/ec2api/api/image.py +++ b/ec2api/api/image.py @@ -91,6 +91,13 @@ CONTAINER_TO_KIND = {'aki': 'aki', IMAGE_TYPES = {'aki': 'kernel', 'ari': 'ramdisk', 'ami': 'machine'} +GLANCE_STATUS_TO_EC2 = {'queued': 'pending', + 'saving': 'pending', + 'active': 'available', + 'killed': 'deregistered', + 'pending_delete': 'deregistered', + 'deleted': 'deregistered', + 'deactivated': 'invalid'} EPHEMERAL_PREFIX_LEN = len('ephemeral') @@ -532,11 +539,11 @@ def _format_image(context, image, os_image, images_dict, ids_dict, } if 'description' in image: ec2_image['description'] = image['description'] - state = os_image.status - # NOTE(vish): fallback status if image_state isn't set - if state == 'active': - state = 'available' - ec2_image['imageState'] = os_image.properties.get('image_state', state) + state = GLANCE_STATUS_TO_EC2.get(os_image.status, 'error') + if state in ('available', 'pending'): + state = _s3_image_state_map.get(os_image.properties.get('image_state'), + state) + ec2_image['imageState'] = state kernel_id = os_image.properties.get('kernel_id') if kernel_id: @@ -692,6 +699,18 @@ ec2utils.register_auto_create_db_item_extension( # NOTE(ft): following functions are copied from various parts of Nova +# translate our internal state to states valid by the EC2 API documentation +_s3_image_state_map = {'downloading': 'pending', + 'failed_download': 'failed', + 'decrypting': 'pending', + 'failed_decrypt': 'failed', + 'untarring': 'pending', + 'failed_untar': 'failed', + 'uploading': 'pending', + 'failed_upload': 'failed', + 'available': 'available'} + + def _s3_create(context, metadata): """Gets a manifest from s3 and makes an image.""" image_location = metadata['properties']['image_location'].lstrip('/') diff --git a/ec2api/tests/unit/test_image.py b/ec2api/tests/unit/test_image.py index 8d5c774d..bdbbdc3a 100644 --- a/ec2api/tests/unit/test_image.py +++ b/ec2api/tests/unit/test_image.py @@ -482,6 +482,43 @@ class ImagePrivateTestCase(test_base.BaseTestCase): self.assertEqual('instance-store', image['rootDeviceType']) self.assertNotIn('blockDeviceMapping', image) + # check Glance status translation + os_image = fakes.OSImage({'id': fakes.ID_OS_IMAGE_1}) + + def check_status_translation(status, expected): + os_image.status = status + image = image_api._format_image( + 'fake_context', fakes.DB_IMAGE_1, os_image, None, None) + self.assertEqual(expected, image['imageState'], + "Wrong '%s' Glance status translation" % status) + check_status_translation('queued', 'pending') + check_status_translation('saving', 'pending') + check_status_translation('active', 'available') + check_status_translation('killed', 'deregistered') + check_status_translation('pending_delete', 'deregistered') + check_status_translation('deleted', 'deregistered') + check_status_translation('deactivated', 'invalid') + check_status_translation('unknown-status', 'error') + + # check internal state translation + os_image.status = 'queued' + + def check_state_translation(state, expected): + os_image.properties['image_state'] = state + image = image_api._format_image( + 'fake_context', fakes.DB_IMAGE_1, os_image, None, None) + self.assertEqual(expected, image['imageState'], + "Wrong '%s' internal state translation" % state) + + for state in ('downloading', 'decrypting', 'untarring', 'uploading'): + check_state_translation(state, 'pending') + for state in ('failed_download', 'failed_decrypt', 'failed_untar', + 'failed_upload'): + check_state_translation(state, 'failed') + os_image.status = 'active' + check_state_translation('available', 'available') + check_state_translation('unknown-state', 'available') + @mock.patch('ec2api.db.api.IMPL') def test_format_mappings(self, db_api): # check virtual mapping formatting