Complete switch from glanceclient to SDK for image service
In https://review.opendev.org/#/c/650374/ a work has been started to switch image service support from glanceclient with all it's dependencies to the SDK version. With this change version 1 (anyway deprecated since ages) is also being switched to SDK. Change-Id: Ic391500af02a73d81d64a9e9113cca85c9e24390
This commit is contained in:
		 Artem Goncharov
					Artem Goncharov
				
			
				
					committed by
					
						 Monty Taylor
						Monty Taylor
					
				
			
			
				
	
			
			
			 Monty Taylor
						Monty Taylor
					
				
			
						parent
						
							60e7c51df4
						
					
				
				
					commit
					768a64aac5
				
			| @@ -26,64 +26,18 @@ DEFAULT_API_VERSION = '2' | ||||
| API_VERSION_OPTION = 'os_image_api_version' | ||||
| API_NAME = "image" | ||||
| API_VERSIONS = { | ||||
|     "1": "glanceclient.v1.client.Client", | ||||
|     "1": "openstack.connection.Connection", | ||||
|     "2": "openstack.connection.Connection", | ||||
| } | ||||
|  | ||||
| IMAGE_API_TYPE = 'image' | ||||
| IMAGE_API_VERSIONS = { | ||||
|     '1': 'openstackclient.api.image_v1.APIv1', | ||||
|     '2': 'openstackclient.api.image_v2.APIv2', | ||||
| } | ||||
|  | ||||
|  | ||||
| def make_client(instance): | ||||
|  | ||||
|     if instance._api_version[API_NAME] != '1': | ||||
|         LOG.debug( | ||||
|             'Image client initialized using OpenStack SDK: %s', | ||||
|             instance.sdk_connection.image, | ||||
|         ) | ||||
|         return instance.sdk_connection.image | ||||
|     else: | ||||
|         """Returns an image service client""" | ||||
|         image_client = utils.get_client_class( | ||||
|             API_NAME, | ||||
|             instance._api_version[API_NAME], | ||||
|             API_VERSIONS) | ||||
|         LOG.debug('Instantiating image client: %s', image_client) | ||||
|  | ||||
|         endpoint = instance.get_endpoint_for_service_type( | ||||
|             API_NAME, | ||||
|             region_name=instance.region_name, | ||||
|             interface=instance.interface, | ||||
|         ) | ||||
|  | ||||
|         client = image_client( | ||||
|             endpoint, | ||||
|             token=instance.auth.get_token(instance.session), | ||||
|             cacert=instance.cacert, | ||||
|             insecure=not instance.verify, | ||||
|         ) | ||||
|  | ||||
|         # Create the low-level API | ||||
|  | ||||
|         image_api = utils.get_client_class( | ||||
|             API_NAME, | ||||
|             instance._api_version[API_NAME], | ||||
|             IMAGE_API_VERSIONS) | ||||
|         LOG.debug('Instantiating image api: %s', image_api) | ||||
|  | ||||
|         client.api = image_api( | ||||
|             session=instance.session, | ||||
|             endpoint=instance.get_endpoint_for_service_type( | ||||
|                 IMAGE_API_TYPE, | ||||
|                 region_name=instance.region_name, | ||||
|                 interface=instance.interface, | ||||
|             ) | ||||
|         ) | ||||
|  | ||||
|         return client | ||||
|     LOG.debug( | ||||
|         'Image client initialized using OpenStack SDK: %s', | ||||
|         instance.sdk_connection.image, | ||||
|     ) | ||||
|     return instance.sdk_connection.image | ||||
|  | ||||
|  | ||||
| def build_option_parser(parser): | ||||
|   | ||||
| @@ -22,13 +22,13 @@ import os | ||||
| import sys | ||||
|  | ||||
| from cliff import columns as cliff_columns | ||||
| from glanceclient.common import utils as gc_utils | ||||
| from osc_lib.api import utils as api_utils | ||||
| from osc_lib.cli import format_columns | ||||
| from osc_lib.cli import parseractions | ||||
| from osc_lib.command import command | ||||
| from osc_lib import utils | ||||
|  | ||||
| from openstackclient.common import sdk_utils | ||||
| from openstackclient.i18n import _ | ||||
|  | ||||
| if os.name == "nt": | ||||
| @@ -47,6 +47,36 @@ DISK_CHOICES = ["ami", "ari", "aki", "vhd", "vmdk", "raw", "qcow2", "vhdx", | ||||
| LOG = logging.getLogger(__name__) | ||||
|  | ||||
|  | ||||
| def _get_columns(item): | ||||
|     # Trick sdk_utils to return URI attribute | ||||
|     column_map = { | ||||
|         'is_protected': 'protected', | ||||
|         'owner_id': 'owner' | ||||
|     } | ||||
|     hidden_columns = ['location', 'checksum', | ||||
|                       'copy_from', 'created_at', 'status', 'updated_at'] | ||||
|     return sdk_utils.get_osc_show_columns_for_sdk_resource( | ||||
|         item.to_dict(), column_map, hidden_columns) | ||||
|  | ||||
|  | ||||
| _formatters = { | ||||
| } | ||||
|  | ||||
|  | ||||
| class HumanReadableSizeColumn(cliff_columns.FormattableColumn): | ||||
|     def human_readable(self): | ||||
|         """Return a formatted visibility string | ||||
|  | ||||
|         :rtype: | ||||
|             A string formatted to public/private | ||||
|         """ | ||||
|  | ||||
|         if self._value: | ||||
|             return utils.format_size(self._value) | ||||
|         else: | ||||
|             return '' | ||||
|  | ||||
|  | ||||
| class VisibilityColumn(cliff_columns.FormattableColumn): | ||||
|     def human_readable(self): | ||||
|         """Return a formatted visibility string | ||||
| @@ -210,7 +240,7 @@ class CreateImage(command.ShowOne): | ||||
|         # Special case project option back to API attribute name 'owner' | ||||
|         val = getattr(parsed_args, 'project', None) | ||||
|         if val: | ||||
|             kwargs['owner'] = val | ||||
|             kwargs['owner_id'] = val | ||||
|  | ||||
|         # Handle exclusive booleans with care | ||||
|         # Avoid including attributes in kwargs if an option is not | ||||
| @@ -219,9 +249,9 @@ class CreateImage(command.ShowOne): | ||||
|         # to do nothing when no options are present as opposed to always | ||||
|         # setting a default. | ||||
|         if parsed_args.protected: | ||||
|             kwargs['protected'] = True | ||||
|             kwargs['is_protected'] = True | ||||
|         if parsed_args.unprotected: | ||||
|             kwargs['protected'] = False | ||||
|             kwargs['is_protected'] = False | ||||
|         if parsed_args.public: | ||||
|             kwargs['is_public'] = True | ||||
|         if parsed_args.private: | ||||
| @@ -250,27 +280,35 @@ class CreateImage(command.ShowOne): | ||||
|                 kwargs["data"] = io.open(parsed_args.file, "rb") | ||||
|             else: | ||||
|                 # Read file from stdin | ||||
|                 if sys.stdin.isatty() is not True: | ||||
|                 if not sys.stdin.isatty(): | ||||
|                     if msvcrt: | ||||
|                         msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) | ||||
|                     # Send an open file handle to glanceclient so it will | ||||
|                     # do a chunked transfer | ||||
|                     kwargs["data"] = sys.stdin | ||||
|                     if hasattr(sys.stdin, 'buffer'): | ||||
|                         kwargs['data'] = sys.stdin.buffer | ||||
|                     else: | ||||
|                         kwargs["data"] = sys.stdin | ||||
|  | ||||
|         if not parsed_args.volume: | ||||
|             # Wrap the call to catch exceptions in order to close files | ||||
|             try: | ||||
|                 image = image_client.images.create(**kwargs) | ||||
|                 image = image_client.create_image(**kwargs) | ||||
|             finally: | ||||
|                 # Clean up open files - make sure data isn't a string | ||||
|                 if ('data' in kwargs and hasattr(kwargs['data'], 'close') and | ||||
|                         kwargs['data'] != sys.stdin): | ||||
|                     kwargs['data'].close() | ||||
|  | ||||
|         if image: | ||||
|             display_columns, columns = _get_columns(image) | ||||
|             _formatters['properties'] = format_columns.DictColumn | ||||
|             data = utils.get_item_properties(image, columns, | ||||
|                                              formatters=_formatters) | ||||
|             return (display_columns, data) | ||||
|         elif info: | ||||
|             info.update(image._info) | ||||
|             info['properties'] = format_columns.DictColumn( | ||||
|                 info.get('properties', {})) | ||||
|         return zip(*sorted(info.items())) | ||||
|             return zip(*sorted(info.items())) | ||||
|  | ||||
|  | ||||
| class DeleteImage(command.Command): | ||||
| @@ -289,11 +327,8 @@ class DeleteImage(command.Command): | ||||
|     def take_action(self, parsed_args): | ||||
|         image_client = self.app.client_manager.image | ||||
|         for image in parsed_args.images: | ||||
|             image_obj = utils.find_resource( | ||||
|                 image_client.images, | ||||
|                 image, | ||||
|             ) | ||||
|             image_client.images.delete(image_obj.id) | ||||
|             image_obj = image_client.find_image(image) | ||||
|             image_client.delete_image(image_obj.id) | ||||
|  | ||||
|  | ||||
| class ListImage(command.Lister): | ||||
| @@ -359,15 +394,9 @@ class ListImage(command.Lister): | ||||
|  | ||||
|         kwargs = {} | ||||
|         if parsed_args.public: | ||||
|             kwargs['public'] = True | ||||
|             kwargs['is_public'] = True | ||||
|         if parsed_args.private: | ||||
|             kwargs['private'] = True | ||||
|         # Note: We specifically need to do that below to get the 'status' | ||||
|         #       column. | ||||
|         # | ||||
|         # Always set kwargs['detailed'] to True, and then filter the columns | ||||
|         # according to whether the --long option is specified or not. | ||||
|         kwargs['detailed'] = True | ||||
|             kwargs['is_private'] = True | ||||
|  | ||||
|         if parsed_args.long: | ||||
|             columns = ( | ||||
| @@ -379,8 +408,8 @@ class ListImage(command.Lister): | ||||
|                 'Checksum', | ||||
|                 'Status', | ||||
|                 'is_public', | ||||
|                 'protected', | ||||
|                 'owner', | ||||
|                 'is_protected', | ||||
|                 'owner_id', | ||||
|                 'properties', | ||||
|             ) | ||||
|             column_headers = ( | ||||
| @@ -401,16 +430,7 @@ class ListImage(command.Lister): | ||||
|             column_headers = columns | ||||
|  | ||||
|         # List of image data received | ||||
|         data = [] | ||||
|         # No pages received yet, so start the page marker at None. | ||||
|         marker = None | ||||
|         while True: | ||||
|             page = image_client.api.image_list(marker=marker, **kwargs) | ||||
|             if not page: | ||||
|                 break | ||||
|             data.extend(page) | ||||
|             # Set the marker to the id of the last item we received | ||||
|             marker = page[-1]['id'] | ||||
|         data = list(image_client.images(**kwargs)) | ||||
|  | ||||
|         if parsed_args.property: | ||||
|             # NOTE(dtroyer): coerce to a list to subscript it in py3 | ||||
| @@ -426,7 +446,7 @@ class ListImage(command.Lister): | ||||
|  | ||||
|         return ( | ||||
|             column_headers, | ||||
|             (utils.get_dict_properties( | ||||
|             (utils.get_item_properties( | ||||
|                 s, | ||||
|                 columns, | ||||
|                 formatters={ | ||||
| @@ -456,13 +476,9 @@ class SaveImage(command.Command): | ||||
|  | ||||
|     def take_action(self, parsed_args): | ||||
|         image_client = self.app.client_manager.image | ||||
|         image = utils.find_resource( | ||||
|             image_client.images, | ||||
|             parsed_args.image, | ||||
|         ) | ||||
|         data = image_client.images.data(image) | ||||
|         image = image_client.find_image(parsed_args.image) | ||||
|  | ||||
|         gc_utils.save_image(data, parsed_args.file) | ||||
|         image_client.download_image(image.id, output=parsed_args.file) | ||||
|  | ||||
|  | ||||
| class SetImage(command.Command): | ||||
| @@ -621,22 +637,17 @@ class SetImage(command.Command): | ||||
|         # to do nothing when no options are present as opposed to always | ||||
|         # setting a default. | ||||
|         if parsed_args.protected: | ||||
|             kwargs['protected'] = True | ||||
|             kwargs['is_protected'] = True | ||||
|         if parsed_args.unprotected: | ||||
|             kwargs['protected'] = False | ||||
|             kwargs['is_protected'] = False | ||||
|         if parsed_args.public: | ||||
|             kwargs['is_public'] = True | ||||
|         if parsed_args.private: | ||||
|             kwargs['is_public'] = False | ||||
|         if parsed_args.force: | ||||
|             kwargs['force'] = True | ||||
|  | ||||
|         # Wrap the call to catch exceptions in order to close files | ||||
|         try: | ||||
|             image = utils.find_resource( | ||||
|                 image_client.images, | ||||
|                 parsed_args.image, | ||||
|             ) | ||||
|             image = image_client.find_image(parsed_args.image) | ||||
|  | ||||
|             if not parsed_args.location and not parsed_args.copy_from: | ||||
|                 if parsed_args.volume: | ||||
| @@ -666,9 +677,10 @@ class SetImage(command.Command): | ||||
|                         if parsed_args.stdin: | ||||
|                             if msvcrt: | ||||
|                                 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY) | ||||
|                             # Send an open file handle to glanceclient so it | ||||
|                             # will do a chunked transfer | ||||
|                             kwargs["data"] = sys.stdin | ||||
|                             if hasattr(sys.stdin, 'buffer'): | ||||
|                                 kwargs['data'] = sys.stdin.buffer | ||||
|                             else: | ||||
|                                 kwargs["data"] = sys.stdin | ||||
|                         else: | ||||
|                             LOG.warning(_('Use --stdin to enable read image ' | ||||
|                                           'data from standard input')) | ||||
| @@ -677,7 +689,7 @@ class SetImage(command.Command): | ||||
|                 image.properties.update(kwargs['properties']) | ||||
|                 kwargs['properties'] = image.properties | ||||
|  | ||||
|             image = image_client.images.update(image.id, **kwargs) | ||||
|             image = image_client.update_image(image.id, **kwargs) | ||||
|         finally: | ||||
|             # Clean up open files - make sure data isn't a string | ||||
|             if ('data' in kwargs and hasattr(kwargs['data'], 'close') and | ||||
| @@ -705,16 +717,12 @@ class ShowImage(command.ShowOne): | ||||
|  | ||||
|     def take_action(self, parsed_args): | ||||
|         image_client = self.app.client_manager.image | ||||
|         image = utils.find_resource( | ||||
|             image_client.images, | ||||
|             parsed_args.image, | ||||
|         ) | ||||
|         image = image_client.find_image(parsed_args.image) | ||||
|  | ||||
|         info = {} | ||||
|         info.update(image._info) | ||||
|         if parsed_args.human_readable: | ||||
|             if 'size' in info: | ||||
|                 info['size'] = utils.format_size(info['size']) | ||||
|         info['properties'] = format_columns.DictColumn( | ||||
|             info.get('properties', {})) | ||||
|         return zip(*sorted(info.items())) | ||||
|             _formatters['size'] = HumanReadableSizeColumn | ||||
|         display_columns, columns = _get_columns(image) | ||||
|         _formatters['properties'] = format_columns.DictColumn | ||||
|         data = utils.get_item_properties(image, columns, | ||||
|                                          formatters=_formatters) | ||||
|         return (display_columns, data) | ||||
|   | ||||
| @@ -13,10 +13,11 @@ | ||||
| #   under the License. | ||||
| # | ||||
|  | ||||
| import copy | ||||
| from unittest import mock | ||||
| import uuid | ||||
|  | ||||
| from openstack.image.v1 import image | ||||
|  | ||||
| from openstackclient.tests.unit import fakes | ||||
| from openstackclient.tests.unit import utils | ||||
| from openstackclient.tests.unit.volume.v1 import fakes as volume_fakes | ||||
| @@ -111,13 +112,10 @@ class FakeImage(object): | ||||
|                 'Alpha': 'a', | ||||
|                 'Beta': 'b', | ||||
|                 'Gamma': 'g'}, | ||||
|             'status': 'status' + uuid.uuid4().hex | ||||
|         } | ||||
|  | ||||
|         # Overwrite default attributes if there are some attributes set | ||||
|         image_info.update(attrs) | ||||
|  | ||||
|         image = fakes.FakeResource( | ||||
|             info=copy.deepcopy(image_info), | ||||
|             loaded=True) | ||||
|  | ||||
|         return image | ||||
|         return image.Image(**image_info) | ||||
|   | ||||
| @@ -17,7 +17,6 @@ import copy | ||||
| from unittest import mock | ||||
|  | ||||
| from osc_lib.cli import format_columns | ||||
| from osc_lib import exceptions | ||||
|  | ||||
| from openstackclient.image.v1 import image | ||||
| from openstackclient.tests.unit import fakes | ||||
| @@ -29,9 +28,8 @@ class TestImage(image_fakes.TestImagev1): | ||||
|     def setUp(self): | ||||
|         super(TestImage, self).setUp() | ||||
|  | ||||
|         # Get a shortcut to the ServerManager Mock | ||||
|         self.images_mock = self.app.client_manager.image.images | ||||
|         self.images_mock.reset_mock() | ||||
|         self.app.client_manager.image = mock.Mock() | ||||
|         self.client = self.app.client_manager.image | ||||
|  | ||||
|  | ||||
| class TestImageCreate(TestImage): | ||||
| @@ -48,6 +46,7 @@ class TestImageCreate(TestImage): | ||||
|         'owner', | ||||
|         'properties', | ||||
|         'protected', | ||||
|         'size' | ||||
|     ) | ||||
|     data = ( | ||||
|         new_image.container_format, | ||||
| @@ -57,28 +56,24 @@ class TestImageCreate(TestImage): | ||||
|         new_image.min_disk, | ||||
|         new_image.min_ram, | ||||
|         new_image.name, | ||||
|         new_image.owner, | ||||
|         new_image.owner_id, | ||||
|         format_columns.DictColumn(new_image.properties), | ||||
|         new_image.protected, | ||||
|         new_image.is_protected, | ||||
|         new_image.size | ||||
|     ) | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(TestImageCreate, self).setUp() | ||||
|  | ||||
|         self.images_mock.create.return_value = self.new_image | ||||
|         # This is the return value for utils.find_resource() | ||||
|         self.images_mock.get.return_value = self.new_image | ||||
|         self.images_mock.update.return_value = self.new_image | ||||
|         self.client.create_image = mock.Mock(return_value=self.new_image) | ||||
|         self.client.find_image = mock.Mock(return_value=self.new_image) | ||||
|         self.client.update_image = mock.Mock(return_image=self.new_image) | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = image.CreateImage(self.app, None) | ||||
|  | ||||
|     def test_image_reserve_no_options(self): | ||||
|         mock_exception = { | ||||
|             'find.side_effect': exceptions.CommandError('x'), | ||||
|             'get.side_effect': exceptions.CommandError('x'), | ||||
|         } | ||||
|         self.images_mock.configure_mock(**mock_exception) | ||||
|     @mock.patch('sys.stdin', side_effect=[None]) | ||||
|     def test_image_reserve_no_options(self, raw_input): | ||||
|         arglist = [ | ||||
|             self.new_image.name, | ||||
|         ] | ||||
| @@ -95,25 +90,20 @@ class TestImageCreate(TestImage): | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         # ImageManager.create(name=, **) | ||||
|         self.images_mock.create.assert_called_with( | ||||
|         self.client.create_image.assert_called_with( | ||||
|             name=self.new_image.name, | ||||
|             container_format=image.DEFAULT_CONTAINER_FORMAT, | ||||
|             disk_format=image.DEFAULT_DISK_FORMAT, | ||||
|             data=mock.ANY, | ||||
|             disk_format=image.DEFAULT_DISK_FORMAT | ||||
|         ) | ||||
|  | ||||
|         # Verify update() was not called, if it was show the args | ||||
|         self.assertEqual(self.images_mock.update.call_args_list, []) | ||||
|         self.assertEqual(self.client.update_image.call_args_list, []) | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
|         self.assertItemEqual(self.data, data) | ||||
|  | ||||
|     def test_image_reserve_options(self): | ||||
|         mock_exception = { | ||||
|             'find.side_effect': exceptions.CommandError('x'), | ||||
|             'get.side_effect': exceptions.CommandError('x'), | ||||
|         } | ||||
|         self.images_mock.configure_mock(**mock_exception) | ||||
|     @mock.patch('sys.stdin', side_effect=[None]) | ||||
|     def test_image_reserve_options(self, raw_input): | ||||
|         arglist = [ | ||||
|             '--container-format', 'ovf', | ||||
|             '--disk-format', 'ami', | ||||
| @@ -144,20 +134,19 @@ class TestImageCreate(TestImage): | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         # ImageManager.create(name=, **) | ||||
|         self.images_mock.create.assert_called_with( | ||||
|         self.client.create_image.assert_called_with( | ||||
|             name=self.new_image.name, | ||||
|             container_format='ovf', | ||||
|             disk_format='ami', | ||||
|             min_disk=10, | ||||
|             min_ram=4, | ||||
|             protected=True, | ||||
|             is_protected=True, | ||||
|             is_public=False, | ||||
|             owner='q', | ||||
|             data=mock.ANY, | ||||
|             owner_id='q', | ||||
|         ) | ||||
|  | ||||
|         # Verify update() was not called, if it was show the args | ||||
|         self.assertEqual(self.images_mock.update.call_args_list, []) | ||||
|         self.assertEqual(self.client.update_image.call_args_list, []) | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
|         self.assertItemEqual(self.data, data) | ||||
| @@ -167,11 +156,6 @@ class TestImageCreate(TestImage): | ||||
|         mock_file = mock.Mock(name='File') | ||||
|         mock_open.return_value = mock_file | ||||
|         mock_open.read.return_value = self.data | ||||
|         mock_exception = { | ||||
|             'find.side_effect': exceptions.CommandError('x'), | ||||
|             'get.side_effect': exceptions.CommandError('x'), | ||||
|         } | ||||
|         self.images_mock.configure_mock(**mock_exception) | ||||
|  | ||||
|         arglist = [ | ||||
|             '--file', 'filer', | ||||
| @@ -203,15 +187,12 @@ class TestImageCreate(TestImage): | ||||
|         # Ensure the input file is closed | ||||
|         mock_file.close.assert_called_with() | ||||
|  | ||||
|         # ImageManager.get(name) not to be called since update action exists | ||||
|         self.images_mock.get.assert_not_called() | ||||
|  | ||||
|         # ImageManager.create(name=, **) | ||||
|         self.images_mock.create.assert_called_with( | ||||
|         self.client.create_image.assert_called_with( | ||||
|             name=self.new_image.name, | ||||
|             container_format=image.DEFAULT_CONTAINER_FORMAT, | ||||
|             disk_format=image.DEFAULT_DISK_FORMAT, | ||||
|             protected=False, | ||||
|             is_protected=False, | ||||
|             is_public=True, | ||||
|             properties={ | ||||
|                 'Alpha': '1', | ||||
| @@ -221,7 +202,7 @@ class TestImageCreate(TestImage): | ||||
|         ) | ||||
|  | ||||
|         # Verify update() was not called, if it was show the args | ||||
|         self.assertEqual(self.images_mock.update.call_args_list, []) | ||||
|         self.assertEqual(self.client.update_image.call_args_list, []) | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
|         self.assertItemEqual(self.data, data) | ||||
| @@ -235,8 +216,8 @@ class TestImageDelete(TestImage): | ||||
|         super(TestImageDelete, self).setUp() | ||||
|  | ||||
|         # This is the return value for utils.find_resource() | ||||
|         self.images_mock.get.return_value = self._image | ||||
|         self.images_mock.delete.return_value = None | ||||
|         self.client.find_image = mock.Mock(return_value=self._image) | ||||
|         self.client.delete_image = mock.Mock(return_value=None) | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = image.DeleteImage(self.app, None) | ||||
| @@ -252,7 +233,7 @@ class TestImageDelete(TestImage): | ||||
|  | ||||
|         result = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         self.images_mock.delete.assert_called_with(self._image.id) | ||||
|         self.client.delete_image.assert_called_with(self._image.id) | ||||
|         self.assertIsNone(result) | ||||
|  | ||||
|  | ||||
| @@ -269,7 +250,7 @@ class TestImageList(TestImage): | ||||
|         ( | ||||
|             _image.id, | ||||
|             _image.name, | ||||
|             '', | ||||
|             _image.status | ||||
|         ), | ||||
|     ) | ||||
|  | ||||
| @@ -277,13 +258,13 @@ class TestImageList(TestImage): | ||||
|     info = { | ||||
|         'id': _image.id, | ||||
|         'name': _image.name, | ||||
|         'owner': _image.owner, | ||||
|         'owner': _image.owner_id, | ||||
|         'container_format': _image.container_format, | ||||
|         'disk_format': _image.disk_format, | ||||
|         'min_disk': _image.min_disk, | ||||
|         'min_ram': _image.min_ram, | ||||
|         'is_public': _image.is_public, | ||||
|         'protected': _image.protected, | ||||
|         'protected': _image.is_protected, | ||||
|         'properties': _image.properties, | ||||
|     } | ||||
|     image_info = copy.deepcopy(info) | ||||
| @@ -291,11 +272,10 @@ class TestImageList(TestImage): | ||||
|     def setUp(self): | ||||
|         super(TestImageList, self).setUp() | ||||
|  | ||||
|         self.api_mock = mock.Mock() | ||||
|         self.api_mock.image_list.side_effect = [ | ||||
|             [self.image_info], [], | ||||
|         self.client.images = mock.Mock() | ||||
|         self.client.images.side_effect = [ | ||||
|             [self._image], [], | ||||
|         ] | ||||
|         self.app.client_manager.image.api = self.api_mock | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = image.ListImage(self.app, None) | ||||
| @@ -313,10 +293,7 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             marker=self._image.id, | ||||
|         ) | ||||
|         self.client.images.assert_called_with() | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
|         self.assertEqual(self.datalist, tuple(data)) | ||||
| @@ -336,10 +313,8 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             public=True, | ||||
|             marker=self._image.id, | ||||
|         self.client.images.assert_called_with( | ||||
|             is_public=True, | ||||
|         ) | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
| @@ -360,10 +335,8 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             private=True, | ||||
|             marker=self._image.id, | ||||
|         self.client.images.assert_called_with( | ||||
|             is_private=True, | ||||
|         ) | ||||
|  | ||||
|         self.assertEqual(self.columns, columns) | ||||
| @@ -382,10 +355,7 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             marker=self._image.id, | ||||
|         ) | ||||
|         self.client.images.assert_called_with() | ||||
|  | ||||
|         collist = ( | ||||
|             'ID', | ||||
| @@ -405,14 +375,14 @@ class TestImageList(TestImage): | ||||
|         datalist = (( | ||||
|             self._image.id, | ||||
|             self._image.name, | ||||
|             '', | ||||
|             '', | ||||
|             '', | ||||
|             '', | ||||
|             '', | ||||
|             image.VisibilityColumn(True), | ||||
|             False, | ||||
|             self._image.owner, | ||||
|             self._image.disk_format, | ||||
|             self._image.container_format, | ||||
|             self._image.size, | ||||
|             self._image.checksum, | ||||
|             self._image.status, | ||||
|             image.VisibilityColumn(self._image.is_public), | ||||
|             self._image.is_protected, | ||||
|             self._image.owner_id, | ||||
|             format_columns.DictColumn( | ||||
|                 {'Alpha': 'a', 'Beta': 'b', 'Gamma': 'g'}), | ||||
|         ), ) | ||||
| @@ -436,12 +406,9 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             marker=self._image.id, | ||||
|         ) | ||||
|         self.client.images.assert_called_with() | ||||
|         sf_mock.assert_called_with( | ||||
|             [self.image_info], | ||||
|             [self._image], | ||||
|             attr='a', | ||||
|             value='1', | ||||
|             property_field='properties', | ||||
| @@ -453,7 +420,7 @@ class TestImageList(TestImage): | ||||
|     @mock.patch('osc_lib.utils.sort_items') | ||||
|     def test_image_list_sort_option(self, si_mock): | ||||
|         si_mock.side_effect = [ | ||||
|             [self.image_info], [], | ||||
|             [self._image], [], | ||||
|         ] | ||||
|  | ||||
|         arglist = ['--sort', 'name:asc'] | ||||
| @@ -464,12 +431,9 @@ class TestImageList(TestImage): | ||||
|         # returns a tuple containing the column names and an iterable | ||||
|         # containing the data to be listed. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.api_mock.image_list.assert_called_with( | ||||
|             detailed=True, | ||||
|             marker=self._image.id, | ||||
|         ) | ||||
|         self.client.images.assert_called_with() | ||||
|         si_mock.assert_called_with( | ||||
|             [self.image_info], | ||||
|             [self._image], | ||||
|             'name:asc' | ||||
|         ) | ||||
|  | ||||
| @@ -485,8 +449,8 @@ class TestImageSet(TestImage): | ||||
|         super(TestImageSet, self).setUp() | ||||
|  | ||||
|         # This is the return value for utils.find_resource() | ||||
|         self.images_mock.get.return_value = self._image | ||||
|         self.images_mock.update.return_value = self._image | ||||
|         self.client.find_image = mock.Mock(return_value=self._image) | ||||
|         self.client.update_image = mock.Mock(return_value=self._image) | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = image.SetImage(self.app, None) | ||||
| @@ -502,8 +466,7 @@ class TestImageSet(TestImage): | ||||
|  | ||||
|         result = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         self.images_mock.update.assert_called_with(self._image.id, | ||||
|                                                    **{}) | ||||
|         self.client.update_image.assert_called_with(self._image.id, **{}) | ||||
|         self.assertIsNone(result) | ||||
|  | ||||
|     def test_image_set_options(self): | ||||
| @@ -541,7 +504,7 @@ class TestImageSet(TestImage): | ||||
|             'size': 35165824 | ||||
|         } | ||||
|         # ImageManager.update(image, **kwargs) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             **kwargs | ||||
|         ) | ||||
| @@ -565,11 +528,11 @@ class TestImageSet(TestImage): | ||||
|         result = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         kwargs = { | ||||
|             'protected': True, | ||||
|             'is_protected': True, | ||||
|             'is_public': False, | ||||
|         } | ||||
|         # ImageManager.update(image, **kwargs) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             **kwargs | ||||
|         ) | ||||
| @@ -593,11 +556,11 @@ class TestImageSet(TestImage): | ||||
|         result = self.cmd.take_action(parsed_args) | ||||
|  | ||||
|         kwargs = { | ||||
|             'protected': False, | ||||
|             'is_protected': False, | ||||
|             'is_public': True, | ||||
|         } | ||||
|         # ImageManager.update(image, **kwargs) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             **kwargs | ||||
|         ) | ||||
| @@ -625,7 +588,7 @@ class TestImageSet(TestImage): | ||||
|             }, | ||||
|         } | ||||
|         # ImageManager.update(image, **kwargs) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             **kwargs | ||||
|         ) | ||||
| @@ -683,7 +646,7 @@ class TestImageSet(TestImage): | ||||
|             '', | ||||
|         ) | ||||
|         # ImageManager.update(image_id, remove_props=, **) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             name='updated_image', | ||||
|             volume='volly', | ||||
| @@ -710,7 +673,7 @@ class TestImageSet(TestImage): | ||||
|             'min_ram': 0, | ||||
|         } | ||||
|         # ImageManager.update(image, **kwargs) | ||||
|         self.images_mock.update.assert_called_with( | ||||
|         self.client.update_image.assert_called_with( | ||||
|             self._image.id, | ||||
|             **kwargs | ||||
|         ) | ||||
| @@ -742,16 +705,16 @@ class TestImageShow(TestImage): | ||||
|         _image.min_disk, | ||||
|         _image.min_ram, | ||||
|         _image.name, | ||||
|         _image.owner, | ||||
|         _image.owner_id, | ||||
|         format_columns.DictColumn(_image.properties), | ||||
|         _image.protected, | ||||
|         _image.is_protected, | ||||
|         _image.size, | ||||
|     ) | ||||
|  | ||||
|     def setUp(self): | ||||
|         super(TestImageShow, self).setUp() | ||||
|  | ||||
|         self.images_mock.get.return_value = self._image | ||||
|         self.client.find_image = mock.Mock(return_value=self._image) | ||||
|  | ||||
|         # Get the command object to test | ||||
|         self.cmd = image.ShowImage(self.app, None) | ||||
| @@ -769,7 +732,7 @@ class TestImageShow(TestImage): | ||||
|         # returns a two-part tuple with a tuple of column names and a tuple of | ||||
|         # data to be shown. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.images_mock.get.assert_called_with( | ||||
|         self.client.find_image.assert_called_with( | ||||
|             self._image.id, | ||||
|         ) | ||||
|  | ||||
| @@ -791,9 +754,9 @@ class TestImageShow(TestImage): | ||||
|         # returns a two-part tuple with a tuple of column names and a tuple of | ||||
|         # data to be shown. | ||||
|         columns, data = self.cmd.take_action(parsed_args) | ||||
|         self.images_mock.get.assert_called_with( | ||||
|         self.client.find_image.assert_called_with( | ||||
|             self._image.id, | ||||
|         ) | ||||
|  | ||||
|         size_index = columns.index('size') | ||||
|         self.assertEqual(data[size_index], '2K') | ||||
|         self.assertEqual(data[size_index].human_readable(), '2K') | ||||
|   | ||||
| @@ -0,0 +1,4 @@ | ||||
| --- | ||||
| features: | ||||
|   - | | ||||
|    Complete switch from glanceclient to the SDK for image service. | ||||
| @@ -10,7 +10,6 @@ openstacksdk>=0.36.0 # Apache-2.0 | ||||
| osc-lib>=2.0.0 # Apache-2.0 | ||||
| oslo.i18n>=3.15.3 # Apache-2.0 | ||||
| oslo.utils>=3.33.0 # Apache-2.0 | ||||
| python-glanceclient>=2.8.0 # Apache-2.0 | ||||
| python-keystoneclient>=3.22.0 # Apache-2.0 | ||||
| python-novaclient>=15.1.0 # Apache-2.0 | ||||
| python-cinderclient>=3.3.0 # Apache-2.0 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user