Deprecate image list/show/delete/update CLIs/APIs
This deprecates all of the image CLIs/python API bindings that use the Nova os-images API which is a proxy to the Glance v1 API. This will emit a warning each time a deprecated CLI/API is used and also updates the help docs for the deprecated CLIs and docstrings for APIs. The plan is to do a release once this is merged so people start seeing it and then we'll actually remove the deprecated CLIs/APIs in the first python-novaclient release after the Nova server 15.0.0 'O' release. Depends-On: Iff5fb3180855de7adb3399f6be16bedc8543b4ec Change-Id: I3f60cc7f4c6e27861c4a84b925d573f35f1a1848
This commit is contained in:
parent
77f214bdbd
commit
a602e59806
@ -88,7 +88,8 @@ class SimpleReadOnlyNovaClientTest(base.ClientTestBase):
|
||||
self.nova('hypervisor-list')
|
||||
|
||||
def test_admin_image_list(self):
|
||||
self.nova('image-list')
|
||||
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):
|
||||
|
@ -11,6 +11,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import warnings
|
||||
|
||||
import mock
|
||||
|
||||
from novaclient.tests.unit.fixture_data import client
|
||||
from novaclient.tests.unit.fixture_data import images as data
|
||||
from novaclient.tests.unit import utils
|
||||
@ -23,13 +27,15 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
client_fixture_class = client.V1
|
||||
data_fixture_class = data.V1
|
||||
|
||||
def test_list_images(self):
|
||||
@mock.patch.object(warnings, 'warn')
|
||||
def test_list_images(self, mock_warn):
|
||||
il = self.cs.images.list()
|
||||
self.assert_request_id(il, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images/detail')
|
||||
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)
|
||||
@ -43,35 +49,48 @@ class ImagesTest(utils.FixturedTestCase):
|
||||
self.assert_request_id(il, fakes.FAKE_REQUEST_ID_LIST)
|
||||
self.assert_called('GET', '/images/detail?limit=4&marker=1234')
|
||||
|
||||
def test_get_image_details(self):
|
||||
@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)
|
||||
|
||||
def test_delete_image(self):
|
||||
@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)
|
||||
|
||||
def test_delete_meta(self):
|
||||
@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)
|
||||
|
||||
def test_set_meta(self):
|
||||
@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)
|
||||
|
||||
def test_find(self):
|
||||
@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)
|
||||
|
@ -883,11 +883,13 @@ class ShellTest(utils.TestCase):
|
||||
{'removeTenantAccess': {'tenant': 'proj2'}})
|
||||
|
||||
def test_image_show(self):
|
||||
self.run_command('image-show 1')
|
||||
_, err = self.run_command('image-show 1')
|
||||
self.assertIn('Command image-show is deprecated', err)
|
||||
self.assert_called('GET', '/images/1')
|
||||
|
||||
def test_image_meta_set(self):
|
||||
self.run_command('image-meta 1 set test_key=test_value')
|
||||
_, err = self.run_command('image-meta 1 set test_key=test_value')
|
||||
self.assertIn('Command image-meta is deprecated', err)
|
||||
self.assert_called('POST', '/images/1/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
|
||||
@ -950,7 +952,8 @@ class ShellTest(utils.TestCase):
|
||||
'image-create sample-server mysnapshot_deleted --poll')
|
||||
|
||||
def test_image_delete(self):
|
||||
self.run_command('image-delete 1')
|
||||
_, err = self.run_command('image-delete 1')
|
||||
self.assertIn('Command image-delete is deprecated', err)
|
||||
self.assert_called('DELETE', '/images/1')
|
||||
|
||||
def test_image_delete_multiple(self):
|
||||
|
@ -13,9 +13,11 @@
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
Image interface.
|
||||
DEPRECATED: Image interface.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
|
||||
from six.moves.urllib import parse
|
||||
|
||||
from novaclient import base
|
||||
@ -23,7 +25,8 @@ from novaclient import base
|
||||
|
||||
class Image(base.Resource):
|
||||
"""
|
||||
An image is a collection of files used to create or rebuild a server.
|
||||
DEPRECATED: An image is a collection of files used to create or rebuild a
|
||||
server.
|
||||
"""
|
||||
HUMAN_ID = True
|
||||
|
||||
@ -32,7 +35,7 @@ class Image(base.Resource):
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete this image.
|
||||
DEPRECATED: Delete this image.
|
||||
|
||||
:returns: An instance of novaclient.base.TupleWithMeta
|
||||
"""
|
||||
@ -41,28 +44,36 @@ class Image(base.Resource):
|
||||
|
||||
class ImageManager(base.ManagerWithFind):
|
||||
"""
|
||||
Manage :class:`Image` resources.
|
||||
DEPRECATED: Manage :class:`Image` resources.
|
||||
"""
|
||||
resource_class = Image
|
||||
|
||||
def get(self, image):
|
||||
"""
|
||||
Get an image.
|
||||
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):
|
||||
"""
|
||||
Get a list of all images.
|
||||
DEPRECATED: Get a 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).
|
||||
"""
|
||||
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:
|
||||
@ -77,7 +88,7 @@ class ImageManager(base.ManagerWithFind):
|
||||
|
||||
def delete(self, image):
|
||||
"""
|
||||
Delete an image.
|
||||
DEPRECATED: Delete an image.
|
||||
|
||||
It should go without saying that you can't delete an image
|
||||
that you didn't create.
|
||||
@ -85,27 +96,39 @@ class ImageManager(base.ManagerWithFind):
|
||||
: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))
|
||||
|
||||
def set_meta(self, image, metadata):
|
||||
"""
|
||||
Set an images 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")
|
||||
|
||||
def delete_meta(self, image, keys):
|
||||
"""
|
||||
Delete metadata from an image
|
||||
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" %
|
||||
|
@ -66,6 +66,14 @@ CLIENT_BDM2_KEYS = {
|
||||
}
|
||||
|
||||
|
||||
# NOTE(mriedem): Remove this along with the deprecated commands in the first
|
||||
# python-novaclient release AFTER the nova server 15.0.0 'O' release.
|
||||
def emit_image_deprecation_warning(command_name):
|
||||
print('WARNING: Command %s is deprecated and will be removed after Nova '
|
||||
'15.0.0 is released. Use python-glanceclient or openstackclient '
|
||||
'instead.' % command_name, file=sys.stderr)
|
||||
|
||||
|
||||
def _key_value_pairing(text):
|
||||
try:
|
||||
(k, v) = text.split('=', 1)
|
||||
@ -1201,7 +1209,8 @@ def do_network_create(cs, args):
|
||||
metavar="<limit>",
|
||||
help=_('Number of images to return per request.'))
|
||||
def do_image_list(cs, _args):
|
||||
"""Print a list of available images to boot from."""
|
||||
"""DEPRECATED: Print a list of available images to boot from."""
|
||||
emit_image_deprecation_warning('image-list')
|
||||
limit = _args.limit
|
||||
image_list = cs.images.list(limit=limit)
|
||||
|
||||
@ -1234,7 +1243,8 @@ def do_image_list(cs, _args):
|
||||
help=_('Metadata to add/update or delete (only key is necessary on '
|
||||
'delete).'))
|
||||
def do_image_meta(cs, args):
|
||||
"""Set or delete metadata on an image."""
|
||||
"""DEPRECATED: Set or delete metadata on an image."""
|
||||
emit_image_deprecation_warning('image-meta')
|
||||
image = _find_image(cs, args.image)
|
||||
metadata = _extract_metadata(args)
|
||||
|
||||
@ -1297,7 +1307,8 @@ def _print_flavor(flavor):
|
||||
metavar='<image>',
|
||||
help=_("Name or ID of image."))
|
||||
def do_image_show(cs, args):
|
||||
"""Show details about the given image."""
|
||||
"""DEPRECATED: Show details about the given image."""
|
||||
emit_image_deprecation_warning('image-show')
|
||||
image = _find_image(cs, args.image)
|
||||
_print_image(image)
|
||||
|
||||
@ -1306,7 +1317,8 @@ def do_image_show(cs, args):
|
||||
'image', metavar='<image>', nargs='+',
|
||||
help=_('Name or ID of image(s).'))
|
||||
def do_image_delete(cs, args):
|
||||
"""Delete specified image(s)."""
|
||||
"""DEPRECATED: Delete specified image(s)."""
|
||||
emit_image_deprecation_warning('image-delete')
|
||||
for image in args.image:
|
||||
try:
|
||||
_find_image(cs, image).delete()
|
||||
|
@ -0,0 +1,14 @@
|
||||
---
|
||||
deprecations:
|
||||
- |
|
||||
The following CLIs and python API bindings are now deprecated for removal:
|
||||
|
||||
* nova image-delete
|
||||
* nova image-list
|
||||
* nova image-meta
|
||||
* nova image-show
|
||||
|
||||
These will be removed in the first major python-novaclient release after
|
||||
the Nova 15.0.0 Ocata release. Use python-glanceclient or
|
||||
python-openstackclient for CLI and python-glanceclient or openstacksdk
|
||||
for python API bindings.
|
Loading…
Reference in New Issue
Block a user