Add "--read-only" and "--read-write" options in "volume set"

Add "--read-only" and "--read-write" options in "volume set"
command to set volume access mode.

Implements: bp cinder-command-support
Change-Id: I76ba85c7d3ff0eb026a9cbd794368d8b2b0d17fe
This commit is contained in:
Huanxuan Ao 2016-09-28 09:27:32 +08:00
parent 5e3ec1b42f
commit daffce3a6a
6 changed files with 176 additions and 28 deletions

View File

@ -213,6 +213,7 @@ Set volume properties
[--image-property <key=value> [...] ] [--image-property <key=value> [...] ]
[--state <state>] [--state <state>]
[--bootable | --non-bootable] [--bootable | --non-bootable]
[--read-only | --read-write]
<volume> <volume>
.. option:: --name <name> .. option:: --name <name>
@ -239,6 +240,14 @@ Set volume properties
Mark volume as non-bootable Mark volume as non-bootable
.. option:: --read-only
Set volume to read-only access mode
.. option:: --read-write
Set volume to read-write access mode
.. option:: --image-property <key=value> .. option:: --image-property <key=value>
Set an image property on this volume Set an image property on this volume

View File

@ -844,8 +844,7 @@ class TestVolumeSet(TestVolume):
) )
self.assertIsNone(result) self.assertIsNone(result)
@mock.patch.object(volume.LOG, 'error') def test_volume_set_size_smaller(self):
def test_volume_set_size_smaller(self, mock_log_error):
self._volume.status = 'available' self._volume.status = 'available'
arglist = [ arglist = [
'--size', '1', '--size', '1',
@ -860,15 +859,11 @@ class TestVolumeSet(TestVolume):
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args) self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
parsed_args)
mock_log_error.assert_called_with("New size must be greater " def test_volume_set_size_not_available(self):
"than %s GB",
self._volume.size)
self.assertIsNone(result)
@mock.patch.object(volume.LOG, 'error')
def test_volume_set_size_not_available(self, mock_log_error):
self._volume.status = 'error' self._volume.status = 'error'
arglist = [ arglist = [
'--size', '130', '--size', '130',
@ -883,12 +878,9 @@ class TestVolumeSet(TestVolume):
] ]
parsed_args = self.check_parser(self.cmd, arglist, verifylist) parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args) self.assertRaises(exceptions.CommandError,
self.cmd.take_action,
mock_log_error.assert_called_with("Volume is in %s state, it must be " parsed_args)
"available before size can be "
"extended", 'error')
self.assertIsNone(result)
def test_volume_set_property(self): def test_volume_set_property(self):
arglist = [ arglist = [
@ -896,6 +888,8 @@ class TestVolumeSet(TestVolume):
self._volume.display_name, self._volume.display_name,
] ]
verifylist = [ verifylist = [
('read_only', False),
('read_write', False),
('name', None), ('name', None),
('description', None), ('description', None),
('size', None), ('size', None),
@ -916,6 +910,7 @@ class TestVolumeSet(TestVolume):
self._volume.id, self._volume.id,
metadata metadata
) )
self.volumes_mock.update_readonly_flag.assert_not_called()
self.assertIsNone(result) self.assertIsNone(result)
def test_volume_set_bootable(self): def test_volume_set_bootable(self):
@ -943,6 +938,44 @@ class TestVolumeSet(TestVolume):
self.volumes_mock.set_bootable.assert_called_with( self.volumes_mock.set_bootable.assert_called_with(
self._volume.id, verifylist[index][0][1]) self._volume.id, verifylist[index][0][1])
def test_volume_set_readonly(self):
arglist = [
'--read-only',
self._volume.id
]
verifylist = [
('read_only', True),
('read_write', False),
('volume', self._volume.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.volumes_mock.update_readonly_flag.assert_called_once_with(
self._volume.id,
True)
self.assertIsNone(result)
def test_volume_set_read_write(self):
arglist = [
'--read-write',
self._volume.id
]
verifylist = [
('read_only', False),
('read_write', True),
('volume', self._volume.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.volumes_mock.update_readonly_flag.assert_called_once_with(
self._volume.id,
False)
self.assertIsNone(result)
class TestVolumeShow(TestVolume): class TestVolumeShow(TestVolume):

View File

@ -1033,6 +1033,8 @@ class TestVolumeSet(TestVolume):
self.new_volume.id self.new_volume.id
] ]
verifylist = [ verifylist = [
('read_only', False),
('read_write', False),
('state', 'error'), ('state', 'error'),
('volume', self.new_volume.id) ('volume', self.new_volume.id)
] ]
@ -1042,6 +1044,7 @@ class TestVolumeSet(TestVolume):
result = self.cmd.take_action(parsed_args) result = self.cmd.take_action(parsed_args)
self.volumes_mock.reset_state.assert_called_with( self.volumes_mock.reset_state.assert_called_with(
self.new_volume.id, 'error') self.new_volume.id, 'error')
self.volumes_mock.update_readonly_flag.assert_not_called()
self.assertIsNone(result) self.assertIsNone(result)
def test_volume_set_state_failed(self): def test_volume_set_state_failed(self):
@ -1090,6 +1093,44 @@ class TestVolumeSet(TestVolume):
self.volumes_mock.set_bootable.assert_called_with( self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, verifylist[index][0][1]) self.new_volume.id, verifylist[index][0][1])
def test_volume_set_readonly(self):
arglist = [
'--read-only',
self.new_volume.id
]
verifylist = [
('read_only', True),
('read_write', False),
('volume', self.new_volume.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.volumes_mock.update_readonly_flag.assert_called_once_with(
self.new_volume.id,
True)
self.assertIsNone(result)
def test_volume_set_read_write(self):
arglist = [
'--read-write',
self.new_volume.id
]
verifylist = [
('read_only', False),
('read_write', True),
('volume', self.new_volume.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.volumes_mock.update_readonly_flag.assert_called_once_with(
self.new_volume.id,
False)
self.assertIsNone(result)
class TestVolumeShow(TestVolume): class TestVolumeShow(TestVolume):

View File

@ -388,38 +388,78 @@ class SetVolume(command.Command):
action="store_true", action="store_true",
help=_("Mark volume as non-bootable") help=_("Mark volume as non-bootable")
) )
readonly_group = parser.add_mutually_exclusive_group()
readonly_group.add_argument(
"--read-only",
action="store_true",
help=_("Set volume to read-only access mode")
)
readonly_group.add_argument(
"--read-write",
action="store_true",
help=_("Set volume to read-write access mode")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume volume_client = self.app.client_manager.volume
volume = utils.find_resource(volume_client.volumes, parsed_args.volume) volume = utils.find_resource(volume_client.volumes, parsed_args.volume)
result = 0
if parsed_args.size: if parsed_args.size:
if volume.status != 'available': try:
LOG.error(_("Volume is in %s state, it must be available " if volume.status != 'available':
"before size can be extended"), volume.status) msg = (_("Volume is in %s state, it must be available "
return "before size can be extended") % volume.status)
if parsed_args.size <= volume.size: raise exceptions.CommandError(msg)
LOG.error(_("New size must be greater than %s GB"), if parsed_args.size <= volume.size:
volume.size) msg = (_("New size must be greater than %s GB")
return % volume.size)
volume_client.volumes.extend(volume.id, parsed_args.size) raise exceptions.CommandError(msg)
volume_client.volumes.extend(volume.id, parsed_args.size)
except Exception as e:
LOG.error(_("Failed to set volume size: %s"), e)
result += 1
if parsed_args.property: if parsed_args.property:
volume_client.volumes.set_metadata(volume.id, parsed_args.property) try:
volume_client.volumes.set_metadata(
volume.id,
parsed_args.property)
except Exception as e:
LOG.error(_("Failed to set volume property: %s"), e)
result += 1
if parsed_args.bootable or parsed_args.non_bootable: if parsed_args.bootable or parsed_args.non_bootable:
try: try:
volume_client.volumes.set_bootable( volume_client.volumes.set_bootable(
volume.id, parsed_args.bootable) volume.id, parsed_args.bootable)
except Exception as e: except Exception as e:
LOG.error(_("Failed to set volume bootable property: %s"), e) LOG.error(_("Failed to set volume bootable property: %s"), e)
result += 1
if parsed_args.read_only or parsed_args.read_write:
try:
volume_client.volumes.update_readonly_flag(
volume.id,
parsed_args.read_only)
except Exception as e:
LOG.error(_("Failed to set volume read-only access "
"mode flag: %s"), e)
result += 1
kwargs = {} kwargs = {}
if parsed_args.name: if parsed_args.name:
kwargs['display_name'] = parsed_args.name kwargs['display_name'] = parsed_args.name
if parsed_args.description: if parsed_args.description:
kwargs['display_description'] = parsed_args.description kwargs['display_description'] = parsed_args.description
if kwargs: if kwargs:
volume_client.volumes.update(volume.id, **kwargs) try:
volume_client.volumes.update(volume.id, **kwargs)
except Exception as e:
LOG.error(_("Failed to update volume display name "
"or display description: %s"), e)
result += 1
if result > 0:
raise exceptions.CommandError(_("One or more of the "
"set operations failed"))
class ShowVolume(command.ShowOne): class ShowVolume(command.ShowOne):

View File

@ -473,6 +473,17 @@ class SetVolume(command.Command):
action="store_true", action="store_true",
help=_("Mark volume as non-bootable") help=_("Mark volume as non-bootable")
) )
readonly_group = parser.add_mutually_exclusive_group()
readonly_group.add_argument(
"--read-only",
action="store_true",
help=_("Set volume to read-only access mode")
)
readonly_group.add_argument(
"--read-write",
action="store_true",
help=_("Set volume to read-write access mode")
)
return parser return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
@ -523,6 +534,15 @@ class SetVolume(command.Command):
except Exception as e: except Exception as e:
LOG.error(_("Failed to set volume bootable property: %s"), e) LOG.error(_("Failed to set volume bootable property: %s"), e)
result += 1 result += 1
if parsed_args.read_only or parsed_args.read_write:
try:
volume_client.volumes.update_readonly_flag(
volume.id,
parsed_args.read_only)
except Exception as e:
LOG.error(_("Failed to set volume read-only access "
"mode flag: %s"), e)
result += 1
kwargs = {} kwargs = {}
if parsed_args.name: if parsed_args.name:

View File

@ -0,0 +1,5 @@
---
features:
- |
Add ``--read-only`` and ``--read-write`` options to ``volume set`` command.
[Blueprint `cinder-command-support <https://blueprints.launchpad.net/python-openstackclient/+spec/cinder-command-support>`_]