Remove deprecated image commands/API bindings
We deprecated the image proxy commands and APIs in Newton due to the 2.36 microversion. We said after Ocata 15.0.0 we would remove these, which we can do now in Pike. Note that the list() method on the ImageManager has to be moved to the GlanceManager since we still need to list images for the --image-with option on the boot command. The _match_image method in the shell has to be updated for a glance v2 response where custom metadata properties are flat in the image body. This needs to be released with a major version bump. Change-Id: I2d9fd0243d42538bd1417a42357c17b09368d2a5
This commit is contained in:
parent
e7df023d31
commit
41f66d15aa
@ -79,10 +79,6 @@ class SimpleReadOnlyNovaClientTest(base.ClientTestBase):
|
||||
def test_admin_hypervisor_list(self):
|
||||
self.nova('hypervisor-list')
|
||||
|
||||
def test_admin_image_list(self):
|
||||
out = self.nova('image-list', merge_stderr=True)
|
||||
self.assertIn('Command image-list is deprecated', out)
|
||||
|
||||
@decorators.skip_because(bug="1157349")
|
||||
def test_admin_interface_list(self):
|
||||
self.nova('interface-list')
|
||||
|
@ -21,15 +21,6 @@ class TestImageMetaV239(base.ClientTestBase):
|
||||
# fallback to 2.35 and emit a warning.
|
||||
COMPUTE_API_VERSION = "2.39"
|
||||
|
||||
def test_command_deprecation(self):
|
||||
output = self.nova('image-meta %s set test_key=test_value' %
|
||||
self.image.id, merge_stderr=True)
|
||||
self.assertIn('is deprecated', output)
|
||||
|
||||
output = self.nova('image-meta %s delete test_key' %
|
||||
self.image.id, merge_stderr=True)
|
||||
self.assertIn('is deprecated', output)
|
||||
|
||||
def test_limits(self):
|
||||
"""Tests that 2.39 won't return 'maxImageMeta' resource limit and
|
||||
the CLI output won't show it.
|
||||
|
@ -13,8 +13,6 @@
|
||||
import random
|
||||
import string
|
||||
|
||||
import novaclient
|
||||
from novaclient import api_versions
|
||||
from novaclient.tests.functional import base
|
||||
from novaclient.tests.functional.v2.legacy import test_servers
|
||||
from novaclient.v2 import shell
|
||||
@ -25,18 +23,6 @@ class TestServersBootNovaClient(test_servers.TestServersBootNovaClient):
|
||||
|
||||
COMPUTE_API_VERSION = "2.latest"
|
||||
|
||||
def test_boot_server_using_image_with(self):
|
||||
# --image-with relies on listing images via the compute image proxy
|
||||
# API which does not work after 2.35 so we have to cap for this test.
|
||||
try:
|
||||
self.COMPUTE_API_VERSION = (
|
||||
min(novaclient.API_MAX_VERSION,
|
||||
api_versions.APIVersion('2.35')).get_string())
|
||||
super(TestServersBootNovaClient,
|
||||
self).test_boot_server_using_image_with()
|
||||
finally:
|
||||
self.COMPUTE_API_VERSION = '2.latest'
|
||||
|
||||
|
||||
class TestServersListNovaClient(test_servers.TestServersListNovaClient):
|
||||
"""Servers list functional tests."""
|
||||
|
@ -16,7 +16,7 @@ from novaclient.tests.unit.fixture_data import base
|
||||
|
||||
class V1(base.Fixture):
|
||||
|
||||
base_url = 'images'
|
||||
base_url = 'v2/images'
|
||||
|
||||
def setUp(self):
|
||||
super(V1, self).setUp()
|
||||
@ -78,8 +78,3 @@ class V1(base.Fixture):
|
||||
for u in (1, '1/metadata/test_key'):
|
||||
self.requests_mock.delete(self.url(u), status_code=204,
|
||||
headers=headers)
|
||||
|
||||
|
||||
class V3(V1):
|
||||
|
||||
base_url = 'v1/images'
|
||||
|
@ -1103,7 +1103,7 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
#
|
||||
# Images
|
||||
#
|
||||
def get_images_detail(self, **kw):
|
||||
def get_images(self, **kw):
|
||||
return (200, {}, {'images': [
|
||||
{
|
||||
"id": FAKE_IMAGE_UUID_SNAPSHOT,
|
||||
@ -1131,9 +1131,7 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
"updated": "2010-10-10T12:00:00Z",
|
||||
"created": "2010-08-10T12:00:00Z",
|
||||
"status": "ACTIVE",
|
||||
"metadata": {
|
||||
"test_key": "test_value",
|
||||
},
|
||||
"test_key": "test_value",
|
||||
"links": {},
|
||||
},
|
||||
{
|
||||
@ -1149,41 +1147,20 @@ class FakeSessionClient(base_client.SessionClient):
|
||||
]})
|
||||
|
||||
def get_images_555cae93_fb41_4145_9c52_f5b923538a26(self, **kw):
|
||||
return (200, {}, {'image': self.get_images_detail()[2]['images'][0]})
|
||||
return (200, {}, {'image': self.get_images()[2]['images'][0]})
|
||||
|
||||
def get_images_55bb23af_97a4_4068_bdf8_f10c62880ddf(self, **kw):
|
||||
return (200, {}, {'image': self.get_images_detail()[2]['images'][1]})
|
||||
return (200, {}, {'image': self.get_images()[2]['images'][1]})
|
||||
|
||||
def get_images_c99d7632_bd66_4be9_aed5_3dd14b223a76(self, **kw):
|
||||
return (200, {}, {'image': self.get_images_detail()[2]['images'][2]})
|
||||
return (200, {}, {'image': self.get_images()[2]['images'][2]})
|
||||
|
||||
def get_images_f27f479a_ddda_419a_9bbc_d6b56b210161(self, **kw):
|
||||
return (200, {}, {'image': self.get_images_detail()[2]['images'][3]})
|
||||
return (200, {}, {'image': self.get_images()[2]['images'][3]})
|
||||
|
||||
def get_images_3e861307_73a6_4d1f_8d68_f68b03223032(self):
|
||||
raise exceptions.NotFound('404')
|
||||
|
||||
def post_images_c99d7632_bd66_4be9_aed5_3dd14b223a76_metadata(
|
||||
self, body, **kw):
|
||||
assert list(body) == ['metadata']
|
||||
fakes.assert_has_keys(body['metadata'],
|
||||
required=['test_key'])
|
||||
get_image = self.get_images_c99d7632_bd66_4be9_aed5_3dd14b223a76
|
||||
return (
|
||||
200,
|
||||
{},
|
||||
{'metadata': get_image()[2]['image']['metadata']})
|
||||
|
||||
def delete_images_c99d7632_bd66_4be9_aed5_3dd14b223a76(self, **kw):
|
||||
return (204, {}, None)
|
||||
|
||||
def delete_images_f27f479a_ddda_419a_9bbc_d6b56b210161(self, **kw):
|
||||
return (204, {}, None)
|
||||
|
||||
def delete_images_c99d7632_bd66_4be9_aed5_3dd14b223a76_metadata_test_key(
|
||||
self, **kw):
|
||||
return (204, {}, None)
|
||||
|
||||
#
|
||||
# Keypairs
|
||||
#
|
||||
|
@ -11,12 +11,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import warnings
|
||||
|
||||
import mock
|
||||
|
||||
from novaclient import api_versions
|
||||
from novaclient import exceptions
|
||||
from novaclient.tests.unit.fixture_data import client
|
||||
from novaclient.tests.unit.fixture_data import images as data
|
||||
from novaclient.tests.unit import utils
|
||||
@ -29,95 +25,13 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
client_fixture_class = client.V1
|
||||
data_fixture_class = data.V1
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_list_images(self, mock_warn):
|
||||
il = self.cs.images.list()
|
||||
@mock.patch('novaclient.base.Manager.alternate_service_type')
|
||||
def test_list_images(self, mock_alternate_service_type):
|
||||
il = self.cs.glance.list()
|
||||
self.assert_request_id(il, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images/detail')
|
||||
self.assert_called('GET', '/v2/images')
|
||||
for i in il:
|
||||
self.assertIsInstance(i, images.Image)
|
||||
self.assertEqual(2, len(il))
|
||||
self.assertEqual(1, mock_warn.call_count)
|
||||
|
||||
def test_list_images_undetailed(self):
|
||||
il = self.cs.images.list(detailed=False)
|
||||
self.assert_request_id(il, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images')
|
||||
for i in il:
|
||||
self.assertIsInstance(i, images.Image)
|
||||
|
||||
def test_list_images_with_marker_limit(self):
|
||||
il = self.cs.images.list(marker=1234, limit=4)
|
||||
self.assert_request_id(il, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images/detail?limit=4&marker=1234')
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_get_image_details(self, mock_warn):
|
||||
i = self.cs.images.get(1)
|
||||
self.assert_request_id(i, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images/1')
|
||||
self.assertIsInstance(i, images.Image)
|
||||
self.assertEqual(1, i.id)
|
||||
self.assertEqual('CentOS 5.2', i.name)
|
||||
self.assertEqual(1, mock_warn.call_count)
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_delete_image(self, mock_warn):
|
||||
i = self.cs.images.delete(1)
|
||||
self.assert_request_id(i, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('DELETE', '/images/1')
|
||||
self.assertEqual(1, mock_warn.call_count)
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_delete_meta(self, mock_warn):
|
||||
i = self.cs.images.delete_meta(1, {'test_key': 'test_value'})
|
||||
self.assert_request_id(i, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('DELETE', '/images/1/metadata/test_key')
|
||||
self.assertEqual(1, mock_warn.call_count)
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_set_meta(self, mock_warn):
|
||||
i = self.cs.images.set_meta(1, {'test_key': 'test_value'})
|
||||
self.assert_request_id(i, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('POST', '/images/1/metadata',
|
||||
{"metadata": {'test_key': 'test_value'}})
|
||||
self.assertEqual(1, mock_warn.call_count)
|
||||
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_find(self, mock_warn):
|
||||
i = self.cs.images.find(name="CentOS 5.2")
|
||||
self.assert_request_id(i, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assertEqual(1, i.id)
|
||||
self.assert_called('GET', '/images/1')
|
||||
# This is two warnings because find calls findall which calls list
|
||||
# which is the first warning, which finds one results and then calls
|
||||
# get on that, which is the second warning.
|
||||
self.assertEqual(2, mock_warn.call_count)
|
||||
|
||||
iml = self.cs.images.findall(status='SAVING')
|
||||
self.assert_request_id(iml, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assertEqual(1, len(iml))
|
||||
self.assertEqual('My Server Backup', iml[0].name)
|
||||
|
||||
def test_find_2_36(self):
|
||||
"""Tests that using the find method fails after microversion 2.35.
|
||||
"""
|
||||
self.cs.api_version = api_versions.APIVersion('2.36')
|
||||
self.assertRaises(exceptions.VersionNotFoundForAPIMethod,
|
||||
self.cs.images.find, name="CentOS 5.2")
|
||||
|
||||
def test_delete_meta_2_39(self):
|
||||
"""Tests that 'delete_meta' method fails after microversion 2.39.
|
||||
"""
|
||||
self.cs.api_version = api_versions.APIVersion('2.39')
|
||||
self.assertRaises(exceptions.VersionNotFoundForAPIMethod,
|
||||
self.cs.images.delete_meta, 1,
|
||||
{'test_key': 'test_value'})
|
||||
|
||||
def test_set_meta_2_39(self):
|
||||
"""Tests that 'set_meta' method fails after microversion 2.39.
|
||||
"""
|
||||
self.cs.api_version = api_versions.APIVersion('2.39')
|
||||
self.assertRaises(exceptions.VersionNotFoundForAPIMethod,
|
||||
self.cs.images.set_meta, 1,
|
||||
{'test_key': 'test_value'})
|
||||
mock_alternate_service_type.assert_called_once_with(
|
||||
'image', allowed_types=('image',))
|
||||
|
@ -1199,35 +1199,6 @@ class ShellTest(utils.TestCase):
|
||||
self.assert_called('POST', '/flavors/2/action',
|
||||
{'removeTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
def test_image_show(self):
|
||||
_out, err = self.run_command('image-show %s' % FAKE_UUID_1)
|
||||
self.assertIn('Command image-show is deprecated', err)
|
||||
self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_1)
|
||||
|
||||
def test_image_meta_set(self):
|
||||
_out, err = self.run_command('image-meta %s set test_key=test_value' %
|
||||
FAKE_UUID_1)
|
||||
self.assertIn('Command image-meta is deprecated', err)
|
||||
self.assert_called('POST', '/images/%s/metadata' % FAKE_UUID_1,
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
|
||||
def test_image_meta_del(self):
|
||||
_out, err = self.run_command('image-meta %s delete test_key' %
|
||||
FAKE_UUID_1)
|
||||
self.assertIn('Command image-meta is deprecated', err)
|
||||
self.assert_called('DELETE', '/images/%s/metadata/test_key' %
|
||||
FAKE_UUID_1)
|
||||
|
||||
@mock.patch('sys.stdout', six.StringIO())
|
||||
@mock.patch('sys.stderr', six.StringIO())
|
||||
def test_image_meta_bad_action(self):
|
||||
self.assertRaises(SystemExit, self.run_command,
|
||||
'image-meta 1 BAD_ACTION test_key=test_value')
|
||||
|
||||
def test_image_list(self):
|
||||
self.run_command('image-list')
|
||||
self.assert_called('GET', '/images/detail')
|
||||
|
||||
def test_create_image(self):
|
||||
self.run_command('image-create sample-server mysnapshot')
|
||||
self.assert_called(
|
||||
@ -1273,18 +1244,6 @@ class ShellTest(utils.TestCase):
|
||||
exceptions.InstanceInDeletedState, self.run_command,
|
||||
'image-create sample-server mysnapshot_deleted --poll')
|
||||
|
||||
def test_image_delete(self):
|
||||
_out, err = self.run_command('image-delete %s' % FAKE_UUID_1)
|
||||
self.assertIn('Command image-delete is deprecated', err)
|
||||
self.assert_called('DELETE', '/images/%s' % FAKE_UUID_1)
|
||||
|
||||
def test_image_delete_multiple(self):
|
||||
self.run_command('image-delete %s %s' % (FAKE_UUID_1, FAKE_UUID_2))
|
||||
self.assert_called('GET', '/v2/images/' + FAKE_UUID_1, pos=0)
|
||||
self.assert_called('DELETE', '/images/' + FAKE_UUID_1, pos=1)
|
||||
self.assert_called('GET', '/v2/images/' + FAKE_UUID_2, pos=2)
|
||||
self.assert_called('DELETE', '/images/' + FAKE_UUID_2, pos=3)
|
||||
|
||||
def test_list(self):
|
||||
self.run_command('list')
|
||||
self.assert_called('GET', '/servers/detail')
|
||||
@ -3545,39 +3504,3 @@ class ShellNetworkUtilTest(utils.TestCase):
|
||||
# the deprecated_network decorator will set cs.client.api_version
|
||||
# after calling the wrapped function
|
||||
self.assertEqual(cs.api_version, cs.api_version)
|
||||
|
||||
|
||||
class ShellImageUtilTest(utils.TestCase):
|
||||
def test_deprecated_image_newer(self):
|
||||
@novaclient.v2.shell.deprecated_image
|
||||
def tester(cs):
|
||||
'foo'
|
||||
self.assertEqual(api_versions.APIVersion('2.35'),
|
||||
cs.api_version)
|
||||
|
||||
cs = mock.MagicMock()
|
||||
cs.api_version = api_versions.APIVersion('2.9999')
|
||||
tester(cs)
|
||||
self.assertEqual('DEPRECATED: foo', tester.__doc__)
|
||||
|
||||
def test_deprecated_image_older(self):
|
||||
@novaclient.v2.shell.deprecated_image
|
||||
def tester(cs):
|
||||
'foo'
|
||||
# since we didn't need to adjust the api_version the mock won't
|
||||
# have cs.client.api_version set on it
|
||||
self.assertFalse(hasattr(cs, 'client'))
|
||||
# we have to set the attribute back on cs so the decorator can
|
||||
# set the value on it when we return from this wrapped function
|
||||
setattr(cs, 'client', mock.MagicMock())
|
||||
|
||||
cs = mock.MagicMock()
|
||||
cs.api_version = api_versions.APIVersion('2.1')
|
||||
# we have to delete the cs.client attribute so hasattr won't return a
|
||||
# false positive in the wrapped function
|
||||
del cs.client
|
||||
tester(cs)
|
||||
self.assertEqual('DEPRECATED: foo', tester.__doc__)
|
||||
# the deprecated_network decorator will set cs.client.api_version
|
||||
# after calling the wrapped function
|
||||
self.assertEqual(cs.api_version, cs.api_version)
|
||||
|
@ -153,7 +153,6 @@ class Client(object):
|
||||
self.user_id = user_id
|
||||
self.flavors = flavors.FlavorManager(self)
|
||||
self.flavor_access = flavor_access.FlavorAccessManager(self)
|
||||
self.images = images.ImageManager(self)
|
||||
self.glance = images.GlanceManager(self)
|
||||
self.limits = limits.LimitsManager(self)
|
||||
self.servers = servers.ServerManager(self)
|
||||
|
@ -12,44 +12,25 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
DEPRECATED: Image interface.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import api_versions
|
||||
from novaclient import base
|
||||
from novaclient import exceptions
|
||||
from novaclient.i18n import _
|
||||
|
||||
|
||||
class Image(base.Resource):
|
||||
"""
|
||||
DEPRECATED: An image is a collection of files used to create or rebuild a
|
||||
server.
|
||||
"""
|
||||
HUMAN_ID = True
|
||||
|
||||
def __repr__(self):
|
||||
return "<Image: %s>" % self.name
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
DEPRECATED: Delete this image.
|
||||
|
||||
:returns: An instance of novaclient.base.TupleWithMeta
|
||||
"""
|
||||
return self.manager.delete(self)
|
||||
|
||||
|
||||
class GlanceManager(base.Manager):
|
||||
"""Use glance directly from service catalog.
|
||||
|
||||
This is used to do name to id lookups for images. Do not use it
|
||||
This is used to do name to id lookups for images and listing images for
|
||||
the --image-with option to the 'boot' command. Do not use it
|
||||
for anything else besides that. You have been warned.
|
||||
|
||||
"""
|
||||
@ -85,110 +66,11 @@ class GlanceManager(base.Manager):
|
||||
matches[0].append_request_ids(matches.request_ids)
|
||||
return matches[0]
|
||||
|
||||
|
||||
class ImageManager(base.ManagerWithFind):
|
||||
"""
|
||||
DEPRECATED: Manage :class:`Image` resources.
|
||||
"""
|
||||
resource_class = Image
|
||||
|
||||
@api_versions.wraps('2.0', '2.35')
|
||||
def get(self, image):
|
||||
def list(self):
|
||||
"""
|
||||
DEPRECATED: Get an image.
|
||||
|
||||
:param image: The ID of the image to get.
|
||||
:rtype: :class:`Image`
|
||||
"""
|
||||
warnings.warn(
|
||||
'The novaclient.v2.images module is deprecated and will be '
|
||||
'removed after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or python-openstacksdk instead.', DeprecationWarning)
|
||||
return self._get("/images/%s" % base.getid(image), "image")
|
||||
|
||||
def list(self, detailed=True, limit=None, marker=None):
|
||||
"""
|
||||
DEPRECATED: Get a list of all images.
|
||||
Get a detailed list of all images.
|
||||
|
||||
:rtype: list of :class:`Image`
|
||||
:param limit: maximum number of images to return.
|
||||
:param marker: Begin returning images that appear later in the image
|
||||
list than that represented by this image id (optional).
|
||||
"""
|
||||
# FIXME(mriedem): Should use the api_versions.wraps decorator but that
|
||||
# breaks the ManagerWithFind.findall method which checks the argspec
|
||||
# on this function looking for the 'detailed' arg, and it's getting
|
||||
# tripped up if you use the wraps decorator. This is all deprecated for
|
||||
# removal anyway so we probably don't care too much about this.
|
||||
if self.api.api_version > api_versions.APIVersion('2.35'):
|
||||
raise exceptions.VersionNotFoundForAPIMethod(
|
||||
self.api.api_version, 'list')
|
||||
warnings.warn(
|
||||
'The novaclient.v2.images module is deprecated and will be '
|
||||
'removed after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or python-openstacksdk instead.', DeprecationWarning)
|
||||
params = {}
|
||||
detail = ''
|
||||
if detailed:
|
||||
detail = '/detail'
|
||||
if limit:
|
||||
params['limit'] = int(limit)
|
||||
if marker:
|
||||
params['marker'] = str(marker)
|
||||
params = sorted(params.items(), key=lambda x: x[0])
|
||||
query = '?%s' % parse.urlencode(params) if params else ''
|
||||
return self._list('/images%s%s' % (detail, query), 'images')
|
||||
|
||||
@api_versions.wraps('2.0', '2.35')
|
||||
def delete(self, image):
|
||||
"""
|
||||
DEPRECATED: Delete an image.
|
||||
|
||||
It should go without saying that you can't delete an image
|
||||
that you didn't create.
|
||||
|
||||
:param image: The :class:`Image` (or its ID) to delete.
|
||||
:returns: An instance of novaclient.base.TupleWithMeta
|
||||
"""
|
||||
warnings.warn(
|
||||
'The novaclient.v2.images module is deprecated and will be '
|
||||
'removed after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or python-openstacksdk instead.', DeprecationWarning)
|
||||
return self._delete("/images/%s" % base.getid(image))
|
||||
|
||||
@api_versions.wraps('2.0', '2.38')
|
||||
def set_meta(self, image, metadata):
|
||||
"""
|
||||
DEPRECATED: Set an images metadata
|
||||
|
||||
:param image: The :class:`Image` to add metadata to
|
||||
:param metadata: A dict of metadata to add to the image
|
||||
"""
|
||||
warnings.warn(
|
||||
'The novaclient.v2.images module is deprecated and will be '
|
||||
'removed after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or python-openstacksdk instead.', DeprecationWarning)
|
||||
body = {'metadata': metadata}
|
||||
return self._create("/images/%s/metadata" % base.getid(image),
|
||||
body, "metadata")
|
||||
|
||||
@api_versions.wraps('2.0', '2.38')
|
||||
def delete_meta(self, image, keys):
|
||||
"""
|
||||
DEPRECATED: Delete metadata from an image
|
||||
|
||||
:param image: The :class:`Image` to delete metadata
|
||||
:param keys: A list of metadata keys to delete from the image
|
||||
:returns: An instance of novaclient.base.TupleWithMeta
|
||||
"""
|
||||
warnings.warn(
|
||||
'The novaclient.v2.images module is deprecated and will be '
|
||||
'removed after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or python-openstacksdk instead.', DeprecationWarning)
|
||||
result = base.TupleWithMeta((), None)
|
||||
for k in keys:
|
||||
ret = self._delete("/images/%s/metadata/%s" %
|
||||
(base.getid(image), k))
|
||||
result.append_request_ids(ret.request_ids)
|
||||
|
||||
return result
|
||||
with self.alternate_service_type('image', allowed_types=('image',)):
|
||||
return self._list('/v2/images', 'images')
|
||||
|
@ -72,10 +72,6 @@ msg_deprecate_net = ('WARNING: Command %s is deprecated and will be removed '
|
||||
'after Nova 15.0.0 is released. Use python-neutronclient '
|
||||
'or openstackclient instead.')
|
||||
|
||||
msg_deprecate_img = ('WARNING: Command %s is deprecated and will be removed '
|
||||
'after Nova 15.0.0 is released. Use python-glanceclient '
|
||||
'or openstackclient instead')
|
||||
|
||||
|
||||
def deprecated_proxy(fn, msg_format):
|
||||
@functools.wraps(fn)
|
||||
@ -100,9 +96,6 @@ def deprecated_proxy(fn, msg_format):
|
||||
deprecated_network = functools.partial(deprecated_proxy,
|
||||
msg_format=msg_deprecate_net)
|
||||
|
||||
deprecated_image = functools.partial(deprecated_proxy,
|
||||
msg_format=msg_deprecate_img)
|
||||
|
||||
|
||||
def _key_value_pairing(text):
|
||||
try:
|
||||
@ -118,15 +111,21 @@ def _meta_parsing(metadata):
|
||||
|
||||
|
||||
def _match_image(cs, wanted_properties):
|
||||
image_list = cs.images.list()
|
||||
image_list = cs.glance.list()
|
||||
images_matched = []
|
||||
match = set(wanted_properties)
|
||||
for img in image_list:
|
||||
try:
|
||||
if match == match.intersection(set(img.metadata.items())):
|
||||
images_matched.append(img)
|
||||
except AttributeError:
|
||||
pass
|
||||
img_dict = {}
|
||||
# exclude any unhashable entries
|
||||
for key, value in img.to_dict().items():
|
||||
try:
|
||||
set([key, value])
|
||||
except TypeError:
|
||||
pass
|
||||
else:
|
||||
img_dict[key] = value
|
||||
if match == match.intersection(set(img_dict.items())):
|
||||
images_matched.append(img)
|
||||
return images_matched
|
||||
|
||||
|
||||
@ -1350,57 +1349,6 @@ def do_network_create(cs, args):
|
||||
cs.networks.create(**kwargs)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'--limit',
|
||||
dest="limit",
|
||||
metavar="<limit>",
|
||||
help=_('Number of images to return per request.'))
|
||||
@deprecated_image
|
||||
def do_image_list(cs, _args):
|
||||
"""Print a list of available images to boot from."""
|
||||
limit = _args.limit
|
||||
image_list = cs.images.list(limit=limit)
|
||||
|
||||
def parse_server_name(image):
|
||||
try:
|
||||
return image.server['id']
|
||||
except (AttributeError, KeyError):
|
||||
return ''
|
||||
|
||||
fmts = {'Server': parse_server_name}
|
||||
utils.print_list(image_list, ['ID', 'Name', 'Status', 'Server'],
|
||||
fmts, sortby_index=1)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'image',
|
||||
metavar='<image>',
|
||||
help=_("Name or ID of image."))
|
||||
@utils.arg(
|
||||
'action',
|
||||
metavar='<action>',
|
||||
choices=['set', 'delete'],
|
||||
help=_("Actions: 'set' or 'delete'."))
|
||||
@utils.arg(
|
||||
'metadata',
|
||||
metavar='<key=value>',
|
||||
nargs='+',
|
||||
action='append',
|
||||
default=[],
|
||||
help=_('Metadata to add/update or delete (only key is necessary on '
|
||||
'delete).'))
|
||||
@deprecated_image
|
||||
def do_image_meta(cs, args):
|
||||
"""Set or delete metadata on an image."""
|
||||
image = _find_image(cs, args.image)
|
||||
metadata = _extract_metadata(args)
|
||||
|
||||
if args.action == 'set':
|
||||
cs.images.set_meta(image, metadata)
|
||||
elif args.action == 'delete':
|
||||
cs.images.delete_meta(image, metadata.keys())
|
||||
|
||||
|
||||
def _extract_metadata(args):
|
||||
metadata = {}
|
||||
for metadatum in args.metadata[0]:
|
||||
@ -1449,34 +1397,6 @@ def _print_flavor(flavor):
|
||||
utils.print_dict(info)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'image',
|
||||
metavar='<image>',
|
||||
help=_("Name or ID of image."))
|
||||
@deprecated_image
|
||||
def do_image_show(cs, args):
|
||||
"""Show details about the given image."""
|
||||
image = _find_image(cs, args.image)
|
||||
_print_image(image)
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'image', metavar='<image>', nargs='+',
|
||||
help=_('Name or ID of image(s).'))
|
||||
@deprecated_image
|
||||
def do_image_delete(cs, args):
|
||||
"""Delete specified image(s)."""
|
||||
for image in args.image:
|
||||
try:
|
||||
# _find_image is using the GlanceManager which doesn't implement
|
||||
# the delete() method so use the ImagesManager for that.
|
||||
image = _find_image(cs, image)
|
||||
cs.images.delete(image)
|
||||
except Exception as e:
|
||||
print(_("Delete for image %(image)s failed: %(e)s") %
|
||||
{'image': image, 'e': e})
|
||||
|
||||
|
||||
@utils.arg(
|
||||
'--reservation-id',
|
||||
dest='reservation_id',
|
||||
|
@ -0,0 +1,13 @@
|
||||
---
|
||||
prelude: >
|
||||
Deprecated image commands and python API bindings have been removed.
|
||||
upgrade:
|
||||
- |
|
||||
The following deprecated image commands have been removed::
|
||||
|
||||
* nova image-list
|
||||
* nova image-show
|
||||
* nova image-meta
|
||||
* nova image-delete
|
||||
|
||||
Along with the related python API bindings in ``novaclient.v2.images``.
|
Loading…
x
Reference in New Issue
Block a user