Skip to content

Commit 55ddaf7

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Add "--read-only" and "--read-write" options in "volume set""
2 parents b37ad99 + daffce3 commit 55ddaf7

6 files changed

Lines changed: 176 additions & 28 deletions

File tree

doc/source/command-objects/volume.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ Set volume properties
255255
[--image-property <key=value> [...] ]
256256
[--state <state>]
257257
[--bootable | --non-bootable]
258+
[--read-only | --read-write]
258259
<volume>
259260
260261
.. option:: --name <name>
@@ -281,6 +282,14 @@ Set volume properties
281282
282283
Mark volume as non-bootable
283284
285+
.. option:: --read-only
286+
287+
Set volume to read-only access mode
288+
289+
.. option:: --read-write
290+
291+
Set volume to read-write access mode
292+
284293
.. option:: --image-property <key=value>
285294
286295
Set an image property on this volume

openstackclient/tests/unit/volume/v1/test_volume.py

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -906,8 +906,7 @@ def test_volume_set_size(self):
906906
)
907907
self.assertIsNone(result)
908908

909-
@mock.patch.object(volume.LOG, 'error')
910-
def test_volume_set_size_smaller(self, mock_log_error):
909+
def test_volume_set_size_smaller(self):
911910
self._volume.status = 'available'
912911
arglist = [
913912
'--size', '1',
@@ -922,15 +921,11 @@ def test_volume_set_size_smaller(self, mock_log_error):
922921
]
923922
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
924923

925-
result = self.cmd.take_action(parsed_args)
926-
927-
mock_log_error.assert_called_with("New size must be greater "
928-
"than %s GB",
929-
self._volume.size)
930-
self.assertIsNone(result)
924+
self.assertRaises(exceptions.CommandError,
925+
self.cmd.take_action,
926+
parsed_args)
931927

932-
@mock.patch.object(volume.LOG, 'error')
933-
def test_volume_set_size_not_available(self, mock_log_error):
928+
def test_volume_set_size_not_available(self):
934929
self._volume.status = 'error'
935930
arglist = [
936931
'--size', '130',
@@ -945,19 +940,18 @@ def test_volume_set_size_not_available(self, mock_log_error):
945940
]
946941
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
947942

948-
result = self.cmd.take_action(parsed_args)
949-
950-
mock_log_error.assert_called_with("Volume is in %s state, it must be "
951-
"available before size can be "
952-
"extended", 'error')
953-
self.assertIsNone(result)
943+
self.assertRaises(exceptions.CommandError,
944+
self.cmd.take_action,
945+
parsed_args)
954946

955947
def test_volume_set_property(self):
956948
arglist = [
957949
'--property', 'myprop=myvalue',
958950
self._volume.display_name,
959951
]
960952
verifylist = [
953+
('read_only', False),
954+
('read_write', False),
961955
('name', None),
962956
('description', None),
963957
('size', None),
@@ -978,6 +972,7 @@ def test_volume_set_property(self):
978972
self._volume.id,
979973
metadata
980974
)
975+
self.volumes_mock.update_readonly_flag.assert_not_called()
981976
self.assertIsNone(result)
982977

983978
def test_volume_set_bootable(self):
@@ -1005,6 +1000,44 @@ def test_volume_set_bootable(self):
10051000
self.volumes_mock.set_bootable.assert_called_with(
10061001
self._volume.id, verifylist[index][0][1])
10071002

1003+
def test_volume_set_readonly(self):
1004+
arglist = [
1005+
'--read-only',
1006+
self._volume.id
1007+
]
1008+
verifylist = [
1009+
('read_only', True),
1010+
('read_write', False),
1011+
('volume', self._volume.id)
1012+
]
1013+
1014+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1015+
1016+
result = self.cmd.take_action(parsed_args)
1017+
self.volumes_mock.update_readonly_flag.assert_called_once_with(
1018+
self._volume.id,
1019+
True)
1020+
self.assertIsNone(result)
1021+
1022+
def test_volume_set_read_write(self):
1023+
arglist = [
1024+
'--read-write',
1025+
self._volume.id
1026+
]
1027+
verifylist = [
1028+
('read_only', False),
1029+
('read_write', True),
1030+
('volume', self._volume.id)
1031+
]
1032+
1033+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1034+
1035+
result = self.cmd.take_action(parsed_args)
1036+
self.volumes_mock.update_readonly_flag.assert_called_once_with(
1037+
self._volume.id,
1038+
False)
1039+
self.assertIsNone(result)
1040+
10081041

10091042
class TestVolumeShow(TestVolume):
10101043

openstackclient/tests/unit/volume/v2/test_volume.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1123,6 +1123,8 @@ def test_volume_set_state(self):
11231123
self.new_volume.id
11241124
]
11251125
verifylist = [
1126+
('read_only', False),
1127+
('read_write', False),
11261128
('state', 'error'),
11271129
('volume', self.new_volume.id)
11281130
]
@@ -1132,6 +1134,7 @@ def test_volume_set_state(self):
11321134
result = self.cmd.take_action(parsed_args)
11331135
self.volumes_mock.reset_state.assert_called_with(
11341136
self.new_volume.id, 'error')
1137+
self.volumes_mock.update_readonly_flag.assert_not_called()
11351138
self.assertIsNone(result)
11361139

11371140
def test_volume_set_state_failed(self):
@@ -1180,6 +1183,44 @@ def test_volume_set_bootable(self):
11801183
self.volumes_mock.set_bootable.assert_called_with(
11811184
self.new_volume.id, verifylist[index][0][1])
11821185

1186+
def test_volume_set_readonly(self):
1187+
arglist = [
1188+
'--read-only',
1189+
self.new_volume.id
1190+
]
1191+
verifylist = [
1192+
('read_only', True),
1193+
('read_write', False),
1194+
('volume', self.new_volume.id)
1195+
]
1196+
1197+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1198+
1199+
result = self.cmd.take_action(parsed_args)
1200+
self.volumes_mock.update_readonly_flag.assert_called_once_with(
1201+
self.new_volume.id,
1202+
True)
1203+
self.assertIsNone(result)
1204+
1205+
def test_volume_set_read_write(self):
1206+
arglist = [
1207+
'--read-write',
1208+
self.new_volume.id
1209+
]
1210+
verifylist = [
1211+
('read_only', False),
1212+
('read_write', True),
1213+
('volume', self.new_volume.id)
1214+
]
1215+
1216+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
1217+
1218+
result = self.cmd.take_action(parsed_args)
1219+
self.volumes_mock.update_readonly_flag.assert_called_once_with(
1220+
self.new_volume.id,
1221+
False)
1222+
self.assertIsNone(result)
1223+
11831224

11841225
class TestVolumeShow(TestVolume):
11851226

openstackclient/volume/v1/volume.py

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -419,38 +419,78 @@ def get_parser(self, prog_name):
419419
action="store_true",
420420
help=_("Mark volume as non-bootable")
421421
)
422+
readonly_group = parser.add_mutually_exclusive_group()
423+
readonly_group.add_argument(
424+
"--read-only",
425+
action="store_true",
426+
help=_("Set volume to read-only access mode")
427+
)
428+
readonly_group.add_argument(
429+
"--read-write",
430+
action="store_true",
431+
help=_("Set volume to read-write access mode")
432+
)
422433
return parser
423434

424435
def take_action(self, parsed_args):
425436
volume_client = self.app.client_manager.volume
426437
volume = utils.find_resource(volume_client.volumes, parsed_args.volume)
427438

439+
result = 0
428440
if parsed_args.size:
429-
if volume.status != 'available':
430-
LOG.error(_("Volume is in %s state, it must be available "
431-
"before size can be extended"), volume.status)
432-
return
433-
if parsed_args.size <= volume.size:
434-
LOG.error(_("New size must be greater than %s GB"),
435-
volume.size)
436-
return
437-
volume_client.volumes.extend(volume.id, parsed_args.size)
438-
441+
try:
442+
if volume.status != 'available':
443+
msg = (_("Volume is in %s state, it must be available "
444+
"before size can be extended") % volume.status)
445+
raise exceptions.CommandError(msg)
446+
if parsed_args.size <= volume.size:
447+
msg = (_("New size must be greater than %s GB")
448+
% volume.size)
449+
raise exceptions.CommandError(msg)
450+
volume_client.volumes.extend(volume.id, parsed_args.size)
451+
except Exception as e:
452+
LOG.error(_("Failed to set volume size: %s"), e)
453+
result += 1
439454
if parsed_args.property:
440-
volume_client.volumes.set_metadata(volume.id, parsed_args.property)
455+
try:
456+
volume_client.volumes.set_metadata(
457+
volume.id,
458+
parsed_args.property)
459+
except Exception as e:
460+
LOG.error(_("Failed to set volume property: %s"), e)
461+
result += 1
441462
if parsed_args.bootable or parsed_args.non_bootable:
442463
try:
443464
volume_client.volumes.set_bootable(
444465
volume.id, parsed_args.bootable)
445466
except Exception as e:
446467
LOG.error(_("Failed to set volume bootable property: %s"), e)
468+
result += 1
469+
if parsed_args.read_only or parsed_args.read_write:
470+
try:
471+
volume_client.volumes.update_readonly_flag(
472+
volume.id,
473+
parsed_args.read_only)
474+
except Exception as e:
475+
LOG.error(_("Failed to set volume read-only access "
476+
"mode flag: %s"), e)
477+
result += 1
447478
kwargs = {}
448479
if parsed_args.name:
449480
kwargs['display_name'] = parsed_args.name
450481
if parsed_args.description:
451482
kwargs['display_description'] = parsed_args.description
452483
if kwargs:
453-
volume_client.volumes.update(volume.id, **kwargs)
484+
try:
485+
volume_client.volumes.update(volume.id, **kwargs)
486+
except Exception as e:
487+
LOG.error(_("Failed to update volume display name "
488+
"or display description: %s"), e)
489+
result += 1
490+
491+
if result > 0:
492+
raise exceptions.CommandError(_("One or more of the "
493+
"set operations failed"))
454494

455495

456496
class ShowVolume(command.ShowOne):

openstackclient/volume/v2/volume.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,17 @@ def get_parser(self, prog_name):
520520
action="store_true",
521521
help=_("Mark volume as non-bootable")
522522
)
523+
readonly_group = parser.add_mutually_exclusive_group()
524+
readonly_group.add_argument(
525+
"--read-only",
526+
action="store_true",
527+
help=_("Set volume to read-only access mode")
528+
)
529+
readonly_group.add_argument(
530+
"--read-write",
531+
action="store_true",
532+
help=_("Set volume to read-write access mode")
533+
)
523534
return parser
524535

525536
def take_action(self, parsed_args):
@@ -570,6 +581,15 @@ def take_action(self, parsed_args):
570581
except Exception as e:
571582
LOG.error(_("Failed to set volume bootable property: %s"), e)
572583
result += 1
584+
if parsed_args.read_only or parsed_args.read_write:
585+
try:
586+
volume_client.volumes.update_readonly_flag(
587+
volume.id,
588+
parsed_args.read_only)
589+
except Exception as e:
590+
LOG.error(_("Failed to set volume read-only access "
591+
"mode flag: %s"), e)
592+
result += 1
573593

574594
kwargs = {}
575595
if parsed_args.name:
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
features:
3+
- |
4+
Add ``--read-only`` and ``--read-write`` options to ``volume set`` command.
5+
[Blueprint `cinder-command-support <https://blueprints.launchpad.net/python-openstackclient/+spec/cinder-command-support>`_]

0 commit comments

Comments
 (0)