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:
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
|
||||
|
Loading…
Reference in New Issue
Block a user