summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSurya Seetharaman <suryaseetharaman.9@gmail.com>2019-03-29 11:34:04 +0100
committerSurya Seetharaman <suryaseetharaman.9@gmail.com>2019-05-13 14:37:43 +0200
commita1ac69c69a4fede8ac02b165d23f62b30a242a48 (patch)
treedbb61ffb46224c28a552c52881bc5d75f8ccf9e6
parentfe4138aea45da82c60259b5e4fd9cc18a50ab07b (diff)
downloadpython-novaclient-a1ac69c69a4fede8ac02b165d23f62b30a242a48.tar.gz
Microversion 2.73: Support adding the reason behind a server lock
This patch adds a new parameter ``--reason`` to ``nova lock`` command and ``--locked`` filtering/sorting parameter to ``nova list`` command. This can help users to provide a reason when locking the server and to filter/sort instances based on their locked or value from 2.73 microversion. Implements blueprint add-locked-reason Depends-On: https://review.opendev.org/#/c/648662/ Change-Id: I438e6db2dd5000ba388d0a0f1c8ab74b96b47a71
-rw-r--r--novaclient/__init__.py2
-rw-r--r--novaclient/tests/unit/fixture_data/servers.py2
-rw-r--r--novaclient/tests/unit/v2/fakes.py18
-rw-r--r--novaclient/tests/unit/v2/test_servers.py23
-rw-r--r--novaclient/tests/unit/v2/test_shell.py34
-rw-r--r--novaclient/v2/servers.py28
-rw-r--r--novaclient/v2/shell.py25
-rw-r--r--releasenotes/notes/bp-add-locked-reason-3f136db97b820c73.yaml6
8 files changed, 135 insertions, 3 deletions
diff --git a/novaclient/__init__.py b/novaclient/__init__.py
index 8b6111de..304660c9 100644
--- a/novaclient/__init__.py
+++ b/novaclient/__init__.py
@@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
# when client supported the max version, and bumped sequentially, otherwise
# the client may break due to server side new version may include some
# backward incompatible change.
-API_MAX_VERSION = api_versions.APIVersion("2.72")
+API_MAX_VERSION = api_versions.APIVersion("2.73")
diff --git a/novaclient/tests/unit/fixture_data/servers.py b/novaclient/tests/unit/fixture_data/servers.py
index 6df4129b..d3354469 100644
--- a/novaclient/tests/unit/fixture_data/servers.py
+++ b/novaclient/tests/unit/fixture_data/servers.py
@@ -454,6 +454,8 @@ class V1(Base):
pass
elif action == 'migrate':
return None
+ elif action == 'lock':
+ return None
elif action == 'rebuild':
body = body[action]
adminPass = body.get('adminPass', 'randompassword')
diff --git a/novaclient/tests/unit/v2/fakes.py b/novaclient/tests/unit/v2/fakes.py
index a32e2258..29ec8887 100644
--- a/novaclient/tests/unit/v2/fakes.py
+++ b/novaclient/tests/unit/v2/fakes.py
@@ -774,7 +774,7 @@ class FakeSessionClient(base_client.SessionClient):
none_actions = ['revertResize', 'os-stop', 'os-start',
'forceDelete', 'restore', 'pause', 'unpause', 'unlock',
- 'unrescue', 'resume', 'suspend', 'lock', 'shelve',
+ 'unrescue', 'resume', 'suspend', 'shelve',
'shelveOffload', 'unshelve', 'resetNetwork']
type_actions = ['os-getVNCConsole', 'os-getSPICEConsole',
'os-getRDPConsole']
@@ -836,6 +836,22 @@ class FakeSessionClient(base_client.SessionClient):
# host can be optional
expected.add('host')
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':
body = body[action]
adminPass = body.get('adminPass', 'randompassword')
diff --git a/novaclient/tests/unit/v2/test_servers.py b/novaclient/tests/unit/v2/test_servers.py
index 529fd389..43dbf2c2 100644
--- a/novaclient/tests/unit/v2/test_servers.py
+++ b/novaclient/tests/unit/v2/test_servers.py
@@ -1703,3 +1703,26 @@ class ServersV268Test(ServersV267Test):
ex = self.assertRaises(TypeError, self.cs.servers.live_migrate,
host='hostname', force=True)
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))
diff --git a/novaclient/tests/unit/v2/test_shell.py b/novaclient/tests/unit/v2/test_shell.py
index 447a7229..4f2ee258 100644
--- a/novaclient/tests/unit/v2/test_shell.py
+++ b/novaclient/tests/unit/v2/test_shell.py
@@ -2092,6 +2092,24 @@ class ShellTest(utils.TestCase):
self.run_command('lock sample-server')
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):
self.run_command('unlock sample-server')
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', '/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):
@mock.patch("novaclient.v2.shell.time")
diff --git a/novaclient/v2/servers.py b/novaclient/v2/servers.py
index a37c1b38..afbd5536 100644
--- a/novaclient/v2/servers.py
+++ b/novaclient/v2/servers.py
@@ -214,6 +214,7 @@ class Server(base.Resource):
"""
return self.manager.unpause(self)
+ @api_versions.wraps("2.0", "2.72")
def lock(self):
"""
Lock -- Lock the instance from certain operations.
@@ -222,6 +223,16 @@ class Server(base.Resource):
"""
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):
"""
Unlock -- Remove instance lock.
@@ -1097,6 +1108,7 @@ class ServerManager(base.BootingManagerWithFind):
"""
return self._action('unpause', server, None)
+ @api_versions.wraps("2.0", "2.72")
def lock(self, server):
"""
Lock the server.
@@ -1106,6 +1118,22 @@ class ServerManager(base.BootingManagerWithFind):
"""
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):
"""
Unlock the server.
diff --git a/novaclient/v2/shell.py b/novaclient/v2/shell.py
index f7d59dfa..4e8a730d 100644
--- a/novaclient/v2/shell.py
+++ b/novaclient/v2/shell.py
@@ -1563,6 +1563,13 @@ def _print_flavor(flavor):
"case is 'NOT(t1 OR t2)'. Tags must be separated by commas: "
"--not-tags-any <tag1,tag2>"),
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):
"""List servers."""
imageid = None
@@ -1639,6 +1646,11 @@ def do_list(cs, args):
raise exceptions.CommandError(_('Invalid changes-before value: %s')
% 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,
search_opts=search_opts,
sort_keys=sort_keys,
@@ -2155,12 +2167,23 @@ def do_start(cs, args):
_("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(
+ '--reason',
+ metavar='<reason>',
+ help=_('Reason for locking the server.'),
+ start_version='2.73')
def do_lock(cs, args):
"""Lock a server. A normal (non-admin) user will not be able to execute
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.'))
diff --git a/releasenotes/notes/bp-add-locked-reason-3f136db97b820c73.yaml b/releasenotes/notes/bp-add-locked-reason-3f136db97b820c73.yaml
new file mode 100644
index 00000000..60e19bfc
--- /dev/null
+++ b/releasenotes/notes/bp-add-locked-reason-3f136db97b820c73.yaml
@@ -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.