Merge "Microversion 2.73: Support adding the reason behind a server lock"
This commit is contained in:
commit
a1d3a181d1
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
|||||||
# when client supported the max version, and bumped sequentially, otherwise
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# backward incompatible change.
|
||||||
API_MAX_VERSION = api_versions.APIVersion("2.72")
|
API_MAX_VERSION = api_versions.APIVersion("2.73")
|
||||||
|
@ -454,6 +454,8 @@ class V1(Base):
|
|||||||
pass
|
pass
|
||||||
elif action == 'migrate':
|
elif action == 'migrate':
|
||||||
return None
|
return None
|
||||||
|
elif action == 'lock':
|
||||||
|
return None
|
||||||
elif action == 'rebuild':
|
elif action == 'rebuild':
|
||||||
body = body[action]
|
body = body[action]
|
||||||
adminPass = body.get('adminPass', 'randompassword')
|
adminPass = body.get('adminPass', 'randompassword')
|
||||||
|
@ -774,7 +774,7 @@ class FakeSessionClient(base_client.SessionClient):
|
|||||||
|
|
||||||
none_actions = ['revertResize', 'os-stop', 'os-start',
|
none_actions = ['revertResize', 'os-stop', 'os-start',
|
||||||
'forceDelete', 'restore', 'pause', 'unpause', 'unlock',
|
'forceDelete', 'restore', 'pause', 'unpause', 'unlock',
|
||||||
'unrescue', 'resume', 'suspend', 'lock', 'shelve',
|
'unrescue', 'resume', 'suspend', 'shelve',
|
||||||
'shelveOffload', 'unshelve', 'resetNetwork']
|
'shelveOffload', 'unshelve', 'resetNetwork']
|
||||||
type_actions = ['os-getVNCConsole', 'os-getSPICEConsole',
|
type_actions = ['os-getVNCConsole', 'os-getSPICEConsole',
|
||||||
'os-getRDPConsole']
|
'os-getRDPConsole']
|
||||||
@ -836,6 +836,22 @@ class FakeSessionClient(base_client.SessionClient):
|
|||||||
# host can be optional
|
# host can be optional
|
||||||
expected.add('host')
|
expected.add('host')
|
||||||
assert set(body[action].keys()) == expected
|
assert set(body[action].keys()) == expected
|
||||||
|
elif action == 'lock':
|
||||||
|
if self.api_version < api_versions.APIVersion("2.73"):
|
||||||
|
assert body[action] is None
|
||||||
|
else:
|
||||||
|
# In 2.73 and above, we allow body to be one of these:
|
||||||
|
# a) {'lock': None}
|
||||||
|
# b) {'lock': {}}
|
||||||
|
# c) {'lock': {locked_reason': 'blah'}}
|
||||||
|
if body[action] is not None:
|
||||||
|
expected = set()
|
||||||
|
if 'locked_reason' in body[action].keys():
|
||||||
|
# reason can be optional
|
||||||
|
expected.add('locked_reason')
|
||||||
|
assert set(body[action].keys()) == expected
|
||||||
|
else:
|
||||||
|
assert body[action] is None
|
||||||
elif action == 'rebuild':
|
elif action == 'rebuild':
|
||||||
body = body[action]
|
body = body[action]
|
||||||
adminPass = body.get('adminPass', 'randompassword')
|
adminPass = body.get('adminPass', 'randompassword')
|
||||||
|
@ -1703,3 +1703,26 @@ class ServersV268Test(ServersV267Test):
|
|||||||
ex = self.assertRaises(TypeError, self.cs.servers.live_migrate,
|
ex = self.assertRaises(TypeError, self.cs.servers.live_migrate,
|
||||||
host='hostname', force=True)
|
host='hostname', force=True)
|
||||||
self.assertIn('force', six.text_type(ex))
|
self.assertIn('force', six.text_type(ex))
|
||||||
|
|
||||||
|
|
||||||
|
class ServersV273Test(ServersV268Test):
|
||||||
|
|
||||||
|
api_version = "2.73"
|
||||||
|
|
||||||
|
def test_lock_server(self):
|
||||||
|
s = self.cs.servers.get(1234)
|
||||||
|
ret = s.lock()
|
||||||
|
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
|
self.assert_called('POST', '/servers/1234/action',
|
||||||
|
{'lock': None})
|
||||||
|
ret = s.lock(reason='zombie-apocalypse')
|
||||||
|
self.assert_request_id(ret, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
|
self.assert_called('POST', '/servers/1234/action',
|
||||||
|
{'lock': {'locked_reason': 'zombie-apocalypse'}})
|
||||||
|
|
||||||
|
def test_lock_server_pre_273_fails_with_reason(self):
|
||||||
|
self.cs.api_version = api_versions.APIVersion('2.72')
|
||||||
|
s = self.cs.servers.get(1234)
|
||||||
|
e = self.assertRaises(TypeError,
|
||||||
|
s.lock, reason='blah')
|
||||||
|
self.assertIn("unexpected keyword argument 'reason'", six.text_type(e))
|
||||||
|
@ -2092,6 +2092,24 @@ class ShellTest(utils.TestCase):
|
|||||||
self.run_command('lock sample-server')
|
self.run_command('lock sample-server')
|
||||||
self.assert_called('POST', '/servers/1234/action', {'lock': None})
|
self.assert_called('POST', '/servers/1234/action', {'lock': None})
|
||||||
|
|
||||||
|
def test_lock_pre_v273(self):
|
||||||
|
exp = self.assertRaises(SystemExit,
|
||||||
|
self.run_command,
|
||||||
|
'lock sample-server --reason zombies',
|
||||||
|
api_version='2.72')
|
||||||
|
self.assertIn('2', six.text_type(exp))
|
||||||
|
|
||||||
|
def test_lock_v273(self):
|
||||||
|
self.run_command('lock sample-server',
|
||||||
|
api_version='2.73')
|
||||||
|
self.assert_called('POST', '/servers/1234/action',
|
||||||
|
{'lock': None})
|
||||||
|
|
||||||
|
self.run_command('lock sample-server --reason zombies',
|
||||||
|
api_version='2.73')
|
||||||
|
self.assert_called('POST', '/servers/1234/action',
|
||||||
|
{'lock': {'locked_reason': 'zombies'}})
|
||||||
|
|
||||||
def test_unlock(self):
|
def test_unlock(self):
|
||||||
self.run_command('unlock sample-server')
|
self.run_command('unlock sample-server')
|
||||||
self.assert_called('POST', '/servers/1234/action', {'unlock': None})
|
self.assert_called('POST', '/servers/1234/action', {'unlock': None})
|
||||||
@ -4280,6 +4298,22 @@ class ShellTest(utils.TestCase):
|
|||||||
self.assert_called('GET', '/servers/9015', pos=2)
|
self.assert_called('GET', '/servers/9015', pos=2)
|
||||||
self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=3)
|
self.assert_called('GET', '/v2/images/%s' % FAKE_UUID_2, pos=3)
|
||||||
|
|
||||||
|
def test_list_pre_v273(self):
|
||||||
|
exp = self.assertRaises(SystemExit,
|
||||||
|
self.run_command,
|
||||||
|
'list --locked t',
|
||||||
|
api_version='2.72')
|
||||||
|
self.assertEqual(2, exp.code)
|
||||||
|
|
||||||
|
def test_list_v273(self):
|
||||||
|
self.run_command('list --locked t', api_version='2.73')
|
||||||
|
self.assert_called('GET', '/servers/detail?locked=t')
|
||||||
|
|
||||||
|
def test_list_v273_with_sort_key_dir(self):
|
||||||
|
self.run_command('list --sort locked:asc', api_version='2.73')
|
||||||
|
self.assert_called(
|
||||||
|
'GET', '/servers/detail?sort_dir=asc&sort_key=locked')
|
||||||
|
|
||||||
|
|
||||||
class PollForStatusTestCase(utils.TestCase):
|
class PollForStatusTestCase(utils.TestCase):
|
||||||
@mock.patch("novaclient.v2.shell.time")
|
@mock.patch("novaclient.v2.shell.time")
|
||||||
|
@ -214,6 +214,7 @@ class Server(base.Resource):
|
|||||||
"""
|
"""
|
||||||
return self.manager.unpause(self)
|
return self.manager.unpause(self)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.72")
|
||||||
def lock(self):
|
def lock(self):
|
||||||
"""
|
"""
|
||||||
Lock -- Lock the instance from certain operations.
|
Lock -- Lock the instance from certain operations.
|
||||||
@ -222,6 +223,16 @@ class Server(base.Resource):
|
|||||||
"""
|
"""
|
||||||
return self.manager.lock(self)
|
return self.manager.lock(self)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.73")
|
||||||
|
def lock(self, reason=None):
|
||||||
|
"""
|
||||||
|
Lock -- Lock the instance from certain operations.
|
||||||
|
|
||||||
|
:param reason: (Optional) The lock reason.
|
||||||
|
:returns: An instance of novaclient.base.TupleWithMeta
|
||||||
|
"""
|
||||||
|
return self.manager.lock(self, reason=reason)
|
||||||
|
|
||||||
def unlock(self):
|
def unlock(self):
|
||||||
"""
|
"""
|
||||||
Unlock -- Remove instance lock.
|
Unlock -- Remove instance lock.
|
||||||
@ -1097,6 +1108,7 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
"""
|
"""
|
||||||
return self._action('unpause', server, None)
|
return self._action('unpause', server, None)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.72")
|
||||||
def lock(self, server):
|
def lock(self, server):
|
||||||
"""
|
"""
|
||||||
Lock the server.
|
Lock the server.
|
||||||
@ -1106,6 +1118,22 @@ class ServerManager(base.BootingManagerWithFind):
|
|||||||
"""
|
"""
|
||||||
return self._action('lock', server, None)
|
return self._action('lock', server, None)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.73")
|
||||||
|
def lock(self, server, reason=None):
|
||||||
|
"""
|
||||||
|
Lock the server.
|
||||||
|
|
||||||
|
:param server: The :class:`Server` (or its ID) to lock
|
||||||
|
:param reason: (Optional) The lock reason.
|
||||||
|
:returns: An instance of novaclient.base.TupleWithMeta
|
||||||
|
"""
|
||||||
|
info = None
|
||||||
|
|
||||||
|
if reason:
|
||||||
|
info = {'locked_reason': reason}
|
||||||
|
|
||||||
|
return self._action('lock', server, info)
|
||||||
|
|
||||||
def unlock(self, server):
|
def unlock(self, server):
|
||||||
"""
|
"""
|
||||||
Unlock the server.
|
Unlock the server.
|
||||||
|
@ -1563,6 +1563,13 @@ def _print_flavor(flavor):
|
|||||||
"case is 'NOT(t1 OR t2)'. Tags must be separated by commas: "
|
"case is 'NOT(t1 OR t2)'. Tags must be separated by commas: "
|
||||||
"--not-tags-any <tag1,tag2>"),
|
"--not-tags-any <tag1,tag2>"),
|
||||||
start_version="2.26")
|
start_version="2.26")
|
||||||
|
@utils.arg(
|
||||||
|
'--locked',
|
||||||
|
dest='locked',
|
||||||
|
metavar='<locked>',
|
||||||
|
default=None,
|
||||||
|
help=_('Display servers based on their locked value'),
|
||||||
|
start_version="2.73")
|
||||||
def do_list(cs, args):
|
def do_list(cs, args):
|
||||||
"""List servers."""
|
"""List servers."""
|
||||||
imageid = None
|
imageid = None
|
||||||
@ -1639,6 +1646,11 @@ def do_list(cs, args):
|
|||||||
raise exceptions.CommandError(_('Invalid changes-before value: %s')
|
raise exceptions.CommandError(_('Invalid changes-before value: %s')
|
||||||
% search_opts['changes-before'])
|
% search_opts['changes-before'])
|
||||||
|
|
||||||
|
# In microversion 2.73 we added ``locked`` option in server details.
|
||||||
|
have_added_locked = cs.api_version >= api_versions.APIVersion('2.73')
|
||||||
|
if have_added_locked and args.locked:
|
||||||
|
search_opts['locked'] = args.locked
|
||||||
|
|
||||||
servers = cs.servers.list(detailed=detailed,
|
servers = cs.servers.list(detailed=detailed,
|
||||||
search_opts=search_opts,
|
search_opts=search_opts,
|
||||||
sort_keys=sort_keys,
|
sort_keys=sort_keys,
|
||||||
@ -2155,12 +2167,23 @@ def do_start(cs, args):
|
|||||||
_("Unable to start the specified server(s)."))
|
_("Unable to start the specified server(s)."))
|
||||||
|
|
||||||
|
|
||||||
|
# From microversion 2.73, we can specify a reason for locking the server.
|
||||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||||
|
@utils.arg(
|
||||||
|
'--reason',
|
||||||
|
metavar='<reason>',
|
||||||
|
help=_('Reason for locking the server.'),
|
||||||
|
start_version='2.73')
|
||||||
def do_lock(cs, args):
|
def do_lock(cs, args):
|
||||||
"""Lock a server. A normal (non-admin) user will not be able to execute
|
"""Lock a server. A normal (non-admin) user will not be able to execute
|
||||||
actions on a locked server.
|
actions on a locked server.
|
||||||
"""
|
"""
|
||||||
_find_server(cs, args.server).lock()
|
update_kwargs = {}
|
||||||
|
if 'reason' in args and args.reason is not None:
|
||||||
|
update_kwargs['reason'] = args.reason
|
||||||
|
|
||||||
|
server = _find_server(cs, args.server)
|
||||||
|
server.lock(**update_kwargs)
|
||||||
|
|
||||||
|
|
||||||
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
@utils.arg('server', metavar='<server>', help=_('Name or ID of server.'))
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Added a ``--reason`` option to ``nova lock`` command that enables users
|
||||||
|
to specify a reason when locking a server and a ``locked``
|
||||||
|
filtering/sorting option to ``nova list`` command which enables users to
|
||||||
|
filter/sort servers based on their ``locked`` value in microversion 2.73.
|
Loading…
x
Reference in New Issue
Block a user