Add 'meta' command to allow set/delete of metadata items on servers.

Added ability to run multiple assert_called tests from one test function.
This commit is contained in:
William Wolf 2011-09-01 11:40:16 -04:00
parent 44bf2079ca
commit 6b4791bf48
6 changed files with 103 additions and 9 deletions

View File

@ -461,6 +461,25 @@ class ServerManager(local_base.BootingManagerWithFind):
self._action('createImage', server,
{'name': image_name, 'metadata': metadata or {}})
def set_meta(self, server, metadata):
"""
Set a servers metadata
:param server: The :class:`Server` to add metadata to
:param metadata: A dict of metadata to add to the server
"""
body = {'metadata': metadata}
return self._create("/servers/%s/metadata" % base.getid(server),
body, "metadata")
def delete_meta(self, server, keys):
"""
Delete metadata from an server
:param server: The :class:`Server` to add metadata to
:param keys: A list of metadata keys to delete from the server
"""
for k in keys:
self._delete("/servers/%s/metadata/%s" % (base.getid(server), k))
def _action(self, action, server, info=None):
"""
Perform a server "action" -- reboot/rebuild/resize/etc.

View File

@ -478,6 +478,38 @@ def do_image_create(cs, args):
server = _find_server(cs, args.server)
cs.servers.create_image(server, args.name)
@utils.arg('server',
metavar='<server>',
help="Name or ID of server")
@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 set or delete (only key is necessary on delete)')
def do_meta(cs, args):
"""Set or Delete metadata on a server."""
server = _find_server(cs, args.server)
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.servers.set_meta(server, metadata)
elif args.action == 'delete':
cs.servers.delete_meta(server, metadata.keys())
def _print_server(cs, server):
networks = server.networks

View File

@ -23,12 +23,12 @@ def assert_has_keys(dict, required=[], optional=[]):
class FakeClient(object):
def assert_called(self, method, url, body=None):
def assert_called(self, method, url, body=None, pos=-1):
"""
Assert than an API method was just called.
"""
expected = (method, url)
called = self.client.callstack[-1][0:2]
called = self.client.callstack[pos][0:2]
assert self.client.callstack, \
"Expected %s %s but no calls were made." % expected
@ -37,9 +37,7 @@ class FakeClient(object):
(expected + called)
if body is not None:
assert self.client.callstack[-1][2] == body
self.client.callstack = []
assert self.client.callstack[pos][2] == body
def assert_called_anytime(self, method, url, body=None):
"""
@ -70,5 +68,8 @@ class FakeClient(object):
self.client.callstack = []
def clear_callstack(self):
self.client.callstack = []
def authenticate(self):
pass

View File

@ -213,6 +213,18 @@ class FakeHTTPClient(base_client.HTTPClient):
def delete_servers_1234(self, **kw):
return (202, None)
def delete_servers_1234_metadata_test_key(self, **kw):
return (204, None)
def delete_servers_1234_metadata_key1(self, **kw):
return (204, None)
def delete_servers_1234_metadata_key2(self, **kw):
return (204, None)
def post_servers_1234_metadata(self, **kw):
return (204, {'metadata': { 'test_key': 'test_value'}})
#
# Server Addresses
#

View File

@ -66,6 +66,15 @@ class ServersTest(utils.TestCase):
cs.servers.delete(s)
cs.assert_called('DELETE', '/servers/1234')
def test_delete_server_meta(self):
s = cs.servers.delete_meta(1234, ['test_key'])
cs.assert_called('DELETE', '/servers/1234/metadata/test_key')
def test_set_server_meta(self):
s = cs.servers.set_meta(1234, {'test_key': 'test_value'})
reval = cs.assert_called('POST', '/servers/1234/metadata',
{'metadata': { 'test_key': 'test_value' }})
def test_find(self):
s = cs.servers.find(name='sample-server')
cs.assert_called('GET', '/servers/detail')

View File

@ -25,12 +25,13 @@ class ShellTest(utils.TestCase):
def tearDown(self):
os.environ = self.old_environment
self.shell.cs.clear_callstack()
def run_command(self, cmd):
self.shell.main(cmd.split())
def assert_called(self, method, url, body=None):
return self.shell.cs.assert_called(method, url, body)
def assert_called(self, method, url, body=None, **kwargs):
return self.shell.cs.assert_called(method, url, body, **kwargs)
def assert_called_anytime(self, method, url, body=None):
return self.shell.cs.assert_called_anytime(method, url, body)
@ -226,12 +227,32 @@ class ShellTest(utils.TestCase):
def test_show(self):
self.run_command('show 1234')
# XXX need a way to test multiple calls
# assert_called('GET', '/servers/1234')
self.assert_called('GET', '/servers/1234', pos=-3)
self.assert_called('GET', '/flavors/1', pos=-2)
self.assert_called('GET', '/images/2')
def test_show_bad_id(self):
self.assertRaises(exceptions.CommandError,
self.run_command, 'show xxx')
def test_delete(self):
self.run_command('delete 1234')
self.assert_called('DELETE', '/servers/1234')
self.run_command('delete sample-server')
self.assert_called('DELETE', '/servers/1234')
def test_set_meta_set(self):
self.run_command('meta 1234 set key1=val1 key2=val2')
self.assert_called('POST', '/servers/1234/metadata',
{'metadata': {'key1': 'val1', 'key2': 'val2'}})
def test_set_meta_delete_dict(self):
self.run_command('meta 1234 delete key1=val1 key2=val2')
self.assert_called('DELETE', '/servers/1234/metadata/key1')
self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)
def test_set_meta_delete_keys(self):
self.run_command('meta 1234 delete key1 key2')
self.assert_called('DELETE', '/servers/1234/metadata/key1')
self.assert_called('DELETE', '/servers/1234/metadata/key2', pos=-2)