Skip to content

Commit 187be0a

Browse files
tssuryaDean Troyer
authored andcommitted
Microversion 2.73: Support adding the reason behind a server lock
This patch adds a new parameter ``--reason`` to ``openstack server lock`` command and ``--locked``, ``unlocked`` filtering parameters to ``openstack server list`` command. This can help users to provide a reason when locking the server and to filter instances based on their locked value from 2.73 microversion. Implements blueprint add-locked-reason Depends-On: https://review.opendev.org/#/c/661785/ Change-Id: Ib2714f98b24d47e570da8a6c231e765acd2ff595
1 parent 1bc44fc commit 187be0a

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
@@ -1136,6 +1136,21 @@ def get_parser(self, prog_name):
11361136
" The provided time should be an ISO 8061 formatted time."
11371137
" ex 2016-03-04T06:27:59Z .")
11381138
)
1139+
lock_group = parser.add_mutually_exclusive_group()
1140+
lock_group.add_argument(
1141+
'--locked',
1142+
action='store_true',
1143+
default=False,
1144+
help=_('Only display locked servers. '
1145+
'Requires ``--os-compute-api-version`` 2.73 or greater.'),
1146+
)
1147+
lock_group.add_argument(
1148+
'--unlocked',
1149+
action='store_true',
1150+
default=False,
1151+
help=_('Only display unlocked servers. '
1152+
'Requires ``--os-compute-api-version`` 2.73 or greater.'),
1153+
)
11391154
return parser
11401155

11411156
def take_action(self, parsed_args):
@@ -1190,6 +1205,18 @@ def take_action(self, parsed_args):
11901205
'deleted': parsed_args.deleted,
11911206
'changes-since': parsed_args.changes_since,
11921207
}
1208+
support_locked = (compute_client.api_version >=
1209+
api_versions.APIVersion('2.73'))
1210+
if not support_locked and (parsed_args.locked or parsed_args.unlocked):
1211+
msg = _('--os-compute-api-version 2.73 or greater is required to '
1212+
'use the (un)locked filter option.')
1213+
raise exceptions.CommandError(msg)
1214+
elif support_locked:
1215+
# Only from 2.73.
1216+
if parsed_args.locked:
1217+
search_opts['locked'] = True
1218+
if parsed_args.unlocked:
1219+
search_opts['locked'] = False
11931220
LOG.debug('search options: %s', search_opts)
11941221

11951222
if search_opts['changes-since']:
@@ -1374,16 +1401,28 @@ def get_parser(self, prog_name):
13741401
nargs='+',
13751402
help=_('Server(s) to lock (name or ID)'),
13761403
)
1404+
parser.add_argument(
1405+
'--reason',
1406+
metavar='<reason>',
1407+
default=None,
1408+
help=_("Reason for locking the server(s). Requires "
1409+
"``--os-compute-api-version`` 2.73 or greater.")
1410+
)
13771411
return parser
13781412

13791413
def take_action(self, parsed_args):
13801414

13811415
compute_client = self.app.client_manager.compute
1416+
support_reason = compute_client.api_version >= api_versions.APIVersion(
1417+
'2.73')
1418+
if not support_reason and parsed_args.reason:
1419+
msg = _('--os-compute-api-version 2.73 or greater is required to '
1420+
'use the --reason option.')
1421+
raise exceptions.CommandError(msg)
13821422
for server in parsed_args.server:
1383-
utils.find_resource(
1384-
compute_client.servers,
1385-
server,
1386-
).lock()
1423+
serv = utils.find_resource(compute_client.servers, server)
1424+
(serv.lock(reason=parsed_args.reason) if support_reason
1425+
else serv.lock())
13871426

13881427

13891428
# 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
@@ -90,7 +90,14 @@ def run_method_with_servers(self, method_name, server_count):
9090

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

96103

@@ -2210,6 +2217,80 @@ def test_server_list_with_image(self):
22102217
self.assertEqual(self.columns, columns)
22112218
self.assertEqual(tuple(self.data), tuple(data))
22122219

2220+
def test_server_list_with_locked_pre_v273(self):
2221+
2222+
arglist = [
2223+
'--locked'
2224+
]
2225+
verifylist = [
2226+
('locked', True)
2227+
]
2228+
2229+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2230+
ex = self.assertRaises(exceptions.CommandError,
2231+
self.cmd.take_action,
2232+
parsed_args)
2233+
self.assertIn(
2234+
'--os-compute-api-version 2.73 or greater is required', str(ex))
2235+
2236+
def test_server_list_with_locked_v273(self):
2237+
2238+
self.app.client_manager.compute.api_version = \
2239+
api_versions.APIVersion('2.73')
2240+
arglist = [
2241+
'--locked'
2242+
]
2243+
verifylist = [
2244+
('locked', True)
2245+
]
2246+
2247+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2248+
columns, data = self.cmd.take_action(parsed_args)
2249+
2250+
self.search_opts['locked'] = True
2251+
self.servers_mock.list.assert_called_with(**self.kwargs)
2252+
2253+
self.assertEqual(self.columns, columns)
2254+
self.assertEqual(tuple(self.data), tuple(data))
2255+
2256+
def test_server_list_with_unlocked_v273(self):
2257+
2258+
self.app.client_manager.compute.api_version = \
2259+
api_versions.APIVersion('2.73')
2260+
arglist = [
2261+
'--unlocked'
2262+
]
2263+
verifylist = [
2264+
('unlocked', True)
2265+
]
2266+
2267+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2268+
columns, data = self.cmd.take_action(parsed_args)
2269+
2270+
self.search_opts['locked'] = False
2271+
self.servers_mock.list.assert_called_with(**self.kwargs)
2272+
2273+
self.assertEqual(self.columns, columns)
2274+
self.assertEqual(tuple(self.data), tuple(data))
2275+
2276+
def test_server_list_with_locked_and_unlocked_v273(self):
2277+
2278+
self.app.client_manager.compute.api_version = \
2279+
api_versions.APIVersion('2.73')
2280+
arglist = [
2281+
'--locked',
2282+
'--unlocked'
2283+
]
2284+
verifylist = [
2285+
('locked', True),
2286+
('unlocked', True)
2287+
]
2288+
2289+
ex = self.assertRaises(
2290+
utils.ParserException,
2291+
self.check_parser, self.cmd, arglist, verifylist)
2292+
self.assertIn('Argument parse failed', str(ex))
2293+
22132294
def test_server_list_with_flavor(self):
22142295

22152296
arglist = [
@@ -2336,6 +2417,72 @@ def test_server_lock_one_server(self):
23362417
def test_server_lock_multi_servers(self):
23372418
self.run_method_with_servers('lock', 3)
23382419

2420+
def test_server_lock_with_reason(self):
2421+
server = compute_fakes.FakeServer.create_one_server()
2422+
arglist = [
2423+
server.id,
2424+
'--reason', "blah",
2425+
]
2426+
verifylist = [
2427+
('reason', "blah"),
2428+
('server', [server.id])
2429+
]
2430+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2431+
ex = self.assertRaises(exceptions.CommandError,
2432+
self.cmd.take_action,
2433+
parsed_args)
2434+
self.assertIn(
2435+
'--os-compute-api-version 2.73 or greater is required', str(ex))
2436+
2437+
2438+
class TestServerLockV273(TestServerLock):
2439+
2440+
def setUp(self):
2441+
super(TestServerLockV273, self).setUp()
2442+
2443+
self.server = compute_fakes.FakeServer.create_one_server(
2444+
methods=self.methods)
2445+
2446+
# This is the return value for utils.find_resource()
2447+
self.servers_mock.get.return_value = self.server
2448+
2449+
self.app.client_manager.compute.api_version = \
2450+
api_versions.APIVersion('2.73')
2451+
2452+
# Get the command object to test
2453+
self.cmd = server.LockServer(self.app, None)
2454+
2455+
def test_server_lock_with_reason(self):
2456+
arglist = [
2457+
self.server.id,
2458+
'--reason', "blah",
2459+
]
2460+
verifylist = [
2461+
('reason', "blah"),
2462+
('server', [self.server.id])
2463+
]
2464+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2465+
self.cmd.take_action(parsed_args)
2466+
self.servers_mock.get.assert_called_with(self.server.id)
2467+
self.server.lock.assert_called_with(reason="blah")
2468+
2469+
def test_server_lock_multi_servers_with_reason(self):
2470+
server2 = compute_fakes.FakeServer.create_one_server(
2471+
methods=self.methods)
2472+
arglist = [
2473+
self.server.id, server2.id,
2474+
'--reason', "choo..choo",
2475+
]
2476+
verifylist = [
2477+
('reason', "choo..choo"),
2478+
('server', [self.server.id, server2.id])
2479+
]
2480+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
2481+
self.cmd.take_action(parsed_args)
2482+
self.assertEqual(2, self.servers_mock.get.call_count)
2483+
self.server.lock.assert_called_with(reason="choo..choo")
2484+
self.assertEqual(2, self.server.lock.call_count)
2485+
23392486

23402487
class TestServerMigrate(TestServer):
23412488

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)