Skip to content

Commit 17611a7

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "Microversion 2.73: Support adding the reason behind a server lock"
2 parents e5cb150 + 187be0a commit 17611a7

5 files changed

Lines changed: 206 additions & 7 deletions

File tree

lower-constraints.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ python-mimeparse==1.6.0
100100
python-mistralclient==3.1.0
101101
python-muranoclient==0.8.2
102102
python-neutronclient==6.7.0
103-
python-novaclient==10.0.0
103+
python-novaclient==14.1.0
104104
python-octaviaclient==1.3.0
105105
python-rsdclient==0.1.0
106106
python-saharaclient==1.4.0

openstackclient/compute/v2/server.py

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,21 @@ def get_parser(self, prog_name):
11601160
" The provided time should be an ISO 8061 formatted time"
11611161
" (e.g., 2016-03-04T06:27:59Z).")
11621162
)
1163+
lock_group = parser.add_mutually_exclusive_group()
1164+
lock_group.add_argument(
1165+
'--locked',
1166+
action='store_true',
1167+
default=False,
1168+
help=_('Only display locked servers. '
1169+
'Requires ``--os-compute-api-version`` 2.73 or greater.'),
1170+
)
1171+
lock_group.add_argument(
1172+
'--unlocked',
1173+
action='store_true',
1174+
default=False,
1175+
help=_('Only display unlocked servers. '
1176+
'Requires ``--os-compute-api-version`` 2.73 or greater.'),
1177+
)
11631178
return parser
11641179

11651180
def take_action(self, parsed_args):
@@ -1215,6 +1230,18 @@ def take_action(self, parsed_args):
12151230
'changes-before': parsed_args.changes_before,
12161231
'changes-since': parsed_args.changes_since,
12171232
}
1233+
support_locked = (compute_client.api_version >=
1234+
api_versions.APIVersion('2.73'))
1235+
if not support_locked and (parsed_args.locked or parsed_args.unlocked):
1236+
msg = _('--os-compute-api-version 2.73 or greater is required to '
1237+
'use the (un)locked filter option.')
1238+
raise exceptions.CommandError(msg)
1239+
elif support_locked:
1240+
# Only from 2.73.
1241+
if parsed_args.locked:
1242+
search_opts['locked'] = True
1243+
if parsed_args.unlocked:
1244+
search_opts['locked'] = False
12181245
LOG.debug('search options: %s', search_opts)
12191246

12201247
if search_opts['changes-before']:
@@ -1412,16 +1439,28 @@ def get_parser(self, prog_name):
14121439
nargs='+',
14131440
help=_('Server(s) to lock (name or ID)'),
14141441
)
1442+
parser.add_argument(
1443+
'--reason',
1444+
metavar='<reason>',
1445+
default=None,
1446+
help=_("Reason for locking the server(s). Requires "
1447+
"``--os-compute-api-version`` 2.73 or greater.")
1448+
)
14151449
return parser
14161450

14171451
def take_action(self, parsed_args):
14181452

14191453
compute_client = self.app.client_manager.compute
1454+
support_reason = compute_client.api_version >= api_versions.APIVersion(
1455+
'2.73')
1456+
if not support_reason and parsed_args.reason:
1457+
msg = _('--os-compute-api-version 2.73 or greater is required to '
1458+
'use the --reason option.')
1459+
raise exceptions.CommandError(msg)
14201460
for server in parsed_args.server:
1421-
utils.find_resource(
1422-
compute_client.servers,
1423-
server,
1424-
).lock()
1461+
serv = utils.find_resource(compute_client.servers, server)
1462+
(serv.lock(reason=parsed_args.reason) if support_reason
1463+
else serv.lock())
14251464

14261465

14271466
# FIXME(dtroyer): Here is what I want, how with argparse/cliff?

openstackclient/tests/unit/compute/v2/test_server.py

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,14 @@ def run_method_with_servers(self, method_name, server_count):
9191

9292
for s in servers:
9393
method = getattr(s, method_name)
94-
method.assert_called_with()
94+
if method_name == 'lock':
95+
version = self.app.client_manager.compute.api_version
96+
if version >= api_versions.APIVersion('2.73'):
97+
method.assert_called_with(reason=None)
98+
else:
99+
method.assert_called_with()
100+
else:
101+
method.assert_called_with()
95102
self.assertIsNone(result)
96103

97104

@@ -2296,6 +2303,80 @@ def test_server_list_with_image(self):
22962303
self.assertEqual(self.columns, columns)
22972304
self.assertEqual(tuple(self.data), tuple(data))
22982305

2306+
def test_server_list_with_locked_pre_v273(self):
2307+
2308+
arglist = [
2309+
'--locked'
2310+
]
2311+
verifylist = [
2312+
('locked', True)
2313+
]
2314+
2315+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2316+
ex = self.assertRaises(exceptions.CommandError,
2317+
self.cmd.take_action,
2318+
parsed_args)
2319+
self.assertIn(
2320+
'--os-compute-api-version 2.73 or greater is required', str(ex))
2321+
2322+
def test_server_list_with_locked_v273(self):
2323+
2324+
self.app.client_manager.compute.api_version = \
2325+
api_versions.APIVersion('2.73')
2326+
arglist = [
2327+
'--locked'
2328+
]
2329+
verifylist = [
2330+
('locked', True)
2331+
]
2332+
2333+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2334+
columns, data = self.cmd.take_action(parsed_args)
2335+
2336+
self.search_opts['locked'] = True
2337+
self.servers_mock.list.assert_called_with(**self.kwargs)
2338+
2339+
self.assertEqual(self.columns, columns)
2340+
self.assertEqual(tuple(self.data), tuple(data))
2341+
2342+
def test_server_list_with_unlocked_v273(self):
2343+
2344+
self.app.client_manager.compute.api_version = \
2345+
api_versions.APIVersion('2.73')
2346+
arglist = [
2347+
'--unlocked'
2348+
]
2349+
verifylist = [
2350+
('unlocked', True)
2351+
]
2352+
2353+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2354+
columns, data = self.cmd.take_action(parsed_args)
2355+
2356+
self.search_opts['locked'] = False
2357+
self.servers_mock.list.assert_called_with(**self.kwargs)
2358+
2359+
self.assertEqual(self.columns, columns)
2360+
self.assertEqual(tuple(self.data), tuple(data))
2361+
2362+
def test_server_list_with_locked_and_unlocked_v273(self):
2363+
2364+
self.app.client_manager.compute.api_version = \
2365+
api_versions.APIVersion('2.73')
2366+
arglist = [
2367+
'--locked',
2368+
'--unlocked'
2369+
]
2370+
verifylist = [
2371+
('locked', True),
2372+
('unlocked', True)
2373+
]
2374+
2375+
ex = self.assertRaises(
2376+
utils.ParserException,
2377+
self.check_parser, self.cmd, arglist, verifylist)
2378+
self.assertIn('Argument parse failed', str(ex))
2379+
22992380
def test_server_list_with_flavor(self):
23002381

23012382
arglist = [
@@ -2487,6 +2568,72 @@ def test_server_lock_one_server(self):
24872568
def test_server_lock_multi_servers(self):
24882569
self.run_method_with_servers('lock', 3)
24892570

2571+
def test_server_lock_with_reason(self):
2572+
server = compute_fakes.FakeServer.create_one_server()
2573+
arglist = [
2574+
server.id,
2575+
'--reason', "blah",
2576+
]
2577+
verifylist = [
2578+
('reason', "blah"),
2579+
('server', [server.id])
2580+
]
2581+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2582+
ex = self.assertRaises(exceptions.CommandError,
2583+
self.cmd.take_action,
2584+
parsed_args)
2585+
self.assertIn(
2586+
'--os-compute-api-version 2.73 or greater is required', str(ex))
2587+
2588+
2589+
class TestServerLockV273(TestServerLock):
2590+
2591+
def setUp(self):
2592+
super(TestServerLockV273, self).setUp()
2593+
2594+
self.server = compute_fakes.FakeServer.create_one_server(
2595+
methods=self.methods)
2596+
2597+
# This is the return value for utils.find_resource()
2598+
self.servers_mock.get.return_value = self.server
2599+
2600+
self.app.client_manager.compute.api_version = \
2601+
api_versions.APIVersion('2.73')
2602+
2603+
# Get the command object to test
2604+
self.cmd = server.LockServer(self.app, None)
2605+
2606+
def test_server_lock_with_reason(self):
2607+
arglist = [
2608+
self.server.id,
2609+
'--reason', "blah",
2610+
]
2611+
verifylist = [
2612+
('reason', "blah"),
2613+
('server', [self.server.id])
2614+
]
2615+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2616+
self.cmd.take_action(parsed_args)
2617+
self.servers_mock.get.assert_called_with(self.server.id)
2618+
self.server.lock.assert_called_with(reason="blah")
2619+
2620+
def test_server_lock_multi_servers_with_reason(self):
2621+
server2 = compute_fakes.FakeServer.create_one_server(
2622+
methods=self.methods)
2623+
arglist = [
2624+
self.server.id, server2.id,
2625+
'--reason', "choo..choo",
2626+
]
2627+
verifylist = [
2628+
('reason', "choo..choo"),
2629+
('server', [self.server.id, server2.id])
2630+
]
2631+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2632+
self.cmd.take_action(parsed_args)
2633+
self.assertEqual(2, self.servers_mock.get.call_count)
2634+
self.server.lock.assert_called_with(reason="choo..choo")
2635+
self.assertEqual(2, self.server.lock.call_count)
2636+
24902637

24912638
class TestServerMigrate(TestServer):
24922639

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
features:
3+
- Add ``--reason`` option to the ``server lock`` command to specify a reason
4+
when locking a server.
5+
Requires ``–os-compute-api-version`` 2.73 or greater.
6+
- Add ``--locked`` option to the ``server list`` command to list only locked
7+
servers.
8+
Requires ``–os-compute-api-version`` 2.73 or greater.
9+
- Add ``--unlocked`` option to the ``server list`` command list only unlocked
10+
servers.
11+
Requires ``–os-compute-api-version`` 2.73 or greater.
12+
[Blueprint `add-locked-reason <https://blueprints.launchpad.net/nova/+spec/add-locked-reason>`_]
13+

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ oslo.i18n>=3.15.3 # Apache-2.0
1313
oslo.utils>=3.33.0 # Apache-2.0
1414
python-glanceclient>=2.8.0 # Apache-2.0
1515
python-keystoneclient>=3.17.0 # Apache-2.0
16-
python-novaclient>=10.0.0 # Apache-2.0
16+
python-novaclient>=14.1.0 # Apache-2.0
1717
python-cinderclient>=3.3.0 # Apache-2.0

0 commit comments

Comments
 (0)