Add support for image metadata to be viewed, added, updated, and deleted.
This commit is contained in:
parent
d2905832fa
commit
14c2bd2d76
@ -56,3 +56,24 @@ class ImageManager(base.ManagerWithFind):
|
||||
:param image: The :class:`Image` (or its ID) to delete.
|
||||
"""
|
||||
self._delete("/images/%s" % base.getid(image))
|
||||
|
||||
def set_meta(self, image, metadata):
|
||||
"""
|
||||
Set an images metadata
|
||||
|
||||
:param image: The :class:`Image` to add metadata to
|
||||
:param metadata: A dict of metadata to add to the image
|
||||
"""
|
||||
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
|
||||
|
||||
:param image: The :class:`Image` to add metadata to
|
||||
:param keys: A list of metadata keys to delete from the image
|
||||
"""
|
||||
for k in keys:
|
||||
self._delete("/images/%s/metadata/%s" % (base.getid(image), k))
|
||||
|
@ -238,6 +238,52 @@ def do_image_list(cs, args):
|
||||
"""Print a list of available images to boot from."""
|
||||
utils.print_list(cs.images.list(), ['ID', 'Name', 'Status'])
|
||||
|
||||
@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)')
|
||||
def do_image_meta(cs, args):
|
||||
"""Set or Delete metadata on an image."""
|
||||
image = _find_image(cs, args.image)
|
||||
metadata = {}
|
||||
for metadatum in args.metadata[0]:
|
||||
# Can only pass the key in on 'delete'
|
||||
# So this doesn't have to have '='
|
||||
if metadatum.find('=') > -1:
|
||||
(key, value) = metadatum.split('=',1)
|
||||
else:
|
||||
key = metadatum
|
||||
value = None
|
||||
|
||||
metadata[key] = value
|
||||
|
||||
if args.action == 'set':
|
||||
cs.images.set_meta(image, metadata)
|
||||
elif args.action == 'delete':
|
||||
cs.images.delete_meta(image, metadata.keys())
|
||||
|
||||
def _print_image(image):
|
||||
links = image.links
|
||||
info = image._info.copy()
|
||||
info.pop('links')
|
||||
utils.print_dict(info)
|
||||
|
||||
@utils.arg('image',
|
||||
metavar='<image>',
|
||||
help="Name or ID of 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>', help='Name or ID of image.')
|
||||
def do_image_delete(cs, args):
|
||||
|
@ -338,7 +338,11 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
'name': 'CentOS 5.2',
|
||||
"updated": "2010-10-10T12:00:00Z",
|
||||
"created": "2010-08-10T12:00:00Z",
|
||||
"status": "ACTIVE"
|
||||
"status": "ACTIVE",
|
||||
"metadata": {
|
||||
"test_key": "test_value",
|
||||
},
|
||||
"links": {},
|
||||
},
|
||||
{
|
||||
"id": 743,
|
||||
@ -347,7 +351,8 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
"updated": "2010-10-10T12:00:00Z",
|
||||
"created": "2010-08-10T12:00:00Z",
|
||||
"status": "SAVING",
|
||||
"progress": 80
|
||||
"progress": 80,
|
||||
"links": {},
|
||||
}
|
||||
]})
|
||||
|
||||
@ -362,9 +367,19 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
fakes.assert_has_keys(body['image'], required=['serverId', 'name'])
|
||||
return (202, self.get_images_1()[1])
|
||||
|
||||
def post_images_1_metadata(self, body, **kw):
|
||||
assert body.keys() == ['metadata']
|
||||
fakes.assert_has_keys(body['metadata'],
|
||||
required=['test_key'])
|
||||
return (200,
|
||||
{'metadata': self.get_images_1()[1]['image']['metadata']})
|
||||
|
||||
def delete_images_1(self, **kw):
|
||||
return (204, None)
|
||||
|
||||
def delete_images_1_metadata_test_key(self, **kw):
|
||||
return (204, None)
|
||||
|
||||
#
|
||||
# Zones
|
||||
#
|
||||
|
@ -29,6 +29,15 @@ class ImagesTest(utils.TestCase):
|
||||
cs.images.delete(1)
|
||||
cs.assert_called('DELETE', '/images/1')
|
||||
|
||||
def test_delete_meta(self):
|
||||
cs.images.delete_meta(1, {'test_key': 'test_value'})
|
||||
cs.assert_called('DELETE', '/images/1/metadata/test_key')
|
||||
|
||||
def test_set_meta(self):
|
||||
cs.images.set_meta(1, {'test_key': 'test_value'})
|
||||
cs.assert_called('POST', '/images/1/metadata',
|
||||
{"metadata": {'test_key': 'test_value'}})
|
||||
|
||||
def test_find(self):
|
||||
i = cs.images.find(name="CentOS 5.2")
|
||||
self.assertEqual(i.id, 1)
|
||||
|
@ -1,5 +1,7 @@
|
||||
import os
|
||||
import mock
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from novaclient.shell import OpenStackComputeShell
|
||||
from novaclient import exceptions
|
||||
@ -157,6 +159,32 @@ class ShellTest(utils.TestCase):
|
||||
self.run_command('flavor-list')
|
||||
self.assert_called_anytime('GET', '/flavors/detail')
|
||||
|
||||
def test_image_show(self):
|
||||
self.run_command('image-show 1')
|
||||
self.assert_called('GET', '/images/1')
|
||||
|
||||
def test_image_meta_set(self):
|
||||
self.run_command('image-meta 1 set test_key=test_value')
|
||||
self.assert_called('POST', '/images/1/metadata',
|
||||
{'metadata': {'test_key': 'test_value'}})
|
||||
|
||||
def test_image_meta_del(self):
|
||||
self.run_command('image-meta 1 delete test_key=test_value')
|
||||
self.assert_called('DELETE', '/images/1/metadata/test_key')
|
||||
|
||||
def test_image_meta_bad_action(self):
|
||||
tmp = tempfile.TemporaryFile()
|
||||
|
||||
# Suppress stdout and stderr
|
||||
(stdout, stderr) = (sys.stdout, sys.stderr)
|
||||
(sys.stdout, sys.stderr) = (tmp, tmp)
|
||||
|
||||
self.assertRaises(SystemExit, self.run_command,
|
||||
'image-meta 1 BAD_ACTION test_key=test_value')
|
||||
|
||||
# Put stdout and stderr back
|
||||
sys.stdout, sys.stderr = (stdout, stderr)
|
||||
|
||||
def test_image_list(self):
|
||||
self.run_command('image-list')
|
||||
self.assert_called('GET', '/images/detail')
|
||||
|
Loading…
x
Reference in New Issue
Block a user