From 768a64aac5bd14f56c142faeec1793aac91947cb Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 17 Dec 2019 14:43:21 +0100 Subject: [PATCH] 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 --- openstackclient/image/client.py | 58 +----- openstackclient/image/v1/image.py | 138 +++++++------- openstackclient/tests/unit/image/v1/fakes.py | 10 +- .../tests/unit/image/v1/test_image.py | 173 +++++++----------- ...omplete_image_switch-203e0b3105a54674.yaml | 4 + requirements.txt | 1 - 6 files changed, 155 insertions(+), 229 deletions(-) create mode 100644 releasenotes/notes/complete_image_switch-203e0b3105a54674.yaml diff --git a/openstackclient/image/client.py b/openstackclient/image/client.py index 15bea17eb..9a0d7bacb 100644 --- a/openstackclient/image/client.py +++ b/openstackclient/image/client.py @@ -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): diff --git a/openstackclient/image/v1/image.py b/openstackclient/image/v1/image.py index a711a1288..cf1d68171 100644 --- a/openstackclient/image/v1/image.py +++ b/openstackclient/image/v1/image.py @@ -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) diff --git a/openstackclient/tests/unit/image/v1/fakes.py b/openstackclient/tests/unit/image/v1/fakes.py index de2322357..add3978d1 100644 --- a/openstackclient/tests/unit/image/v1/fakes.py +++ b/openstackclient/tests/unit/image/v1/fakes.py @@ -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) diff --git a/openstackclient/tests/unit/image/v1/test_image.py b/openstackclient/tests/unit/image/v1/test_image.py index 970b36c68..2f190a7a3 100644 --- a/openstackclient/tests/unit/image/v1/test_image.py +++ b/openstackclient/tests/unit/image/v1/test_image.py @@ -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') diff --git a/releasenotes/notes/complete_image_switch-203e0b3105a54674.yaml b/releasenotes/notes/complete_image_switch-203e0b3105a54674.yaml new file mode 100644 index 000000000..6878d1d98 --- /dev/null +++ b/releasenotes/notes/complete_image_switch-203e0b3105a54674.yaml @@ -0,0 +1,4 @@ +--- +features: + - | + Complete switch from glanceclient to the SDK for image service. diff --git a/requirements.txt b/requirements.txt index bf2a0590f..b17b6a559 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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