Add some options to "volume create" command

Add "--bootable", "--non-bootable", "--read-only" and "--read-write" options
to "volume create" command for setting some attributes at the time of crration.

Change-Id: I71b4e9fccb4ee0ab1a90e7179d6d2d34dbbae909
Implements: bp cinder-command-support
This commit is contained in:
jiahui.qiang 2016-12-04 00:29:03 +08:00
parent 29587eaa66
commit 7e5a98bca9
6 changed files with 383 additions and 0 deletions

View File

@ -24,6 +24,8 @@ Create new volume
[--property <key=value> [...] ]
[--hint <key=value> [...] ]
[--multi-attach]
[--bootable | --non-bootable]
[--read-only | --read-write]
<name>
.. option:: --size <size>
@ -89,6 +91,22 @@ Create new volume
Allow volume to be attached more than once (default to False)
.. option:: --bootable
Mark volume as bootable
.. option:: --non-bootable
Mark volume as non-bootable (default)
.. option:: --read-only
Set volume to read-only access mode
.. option:: --read-write
Set volume to read-write access mode (default)
.. _volume_create-name:
.. describe:: <name>

View File

@ -431,6 +431,142 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_volume_create_with_bootable_and_readonly(self):
arglist = [
'--bootable',
'--read-only',
'--size', str(self.new_volume.size),
self.new_volume.display_name,
]
verifylist = [
('bootable', True),
('non_bootable', False),
('read_only', True),
('read_write', False),
('size', self.new_volume.size),
('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
self.new_volume.size,
None,
None,
self.new_volume.display_name,
None,
None,
None,
None,
None,
None,
None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, True)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, True)
def test_volume_create_with_nonbootable_and_readwrite(self):
arglist = [
'--non-bootable',
'--read-write',
'--size', str(self.new_volume.size),
self.new_volume.display_name,
]
verifylist = [
('bootable', False),
('non_bootable', True),
('read_only', False),
('read_write', True),
('size', self.new_volume.size),
('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
self.new_volume.size,
None,
None,
self.new_volume.display_name,
None,
None,
None,
None,
None,
None,
None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, False)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, False)
@mock.patch.object(volume.LOG, 'error')
def test_volume_create_with_bootable_and_readonly_fail(
self, mock_error):
self.volumes_mock.set_bootable.side_effect = (
exceptions.CommandError())
self.volumes_mock.update_readonly_flag.side_effect = (
exceptions.CommandError())
arglist = [
'--bootable',
'--read-only',
'--size', str(self.new_volume.size),
self.new_volume.display_name,
]
verifylist = [
('bootable', True),
('non_bootable', False),
('read_only', True),
('read_write', False),
('size', self.new_volume.size),
('name', self.new_volume.display_name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
self.new_volume.size,
None,
None,
self.new_volume.display_name,
None,
None,
None,
None,
None,
None,
None,
)
self.assertEqual(2, mock_error.call_count)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, True)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, True)
def test_volume_create_without_size(self):
arglist = [
self.new_volume.display_name,

View File

@ -450,6 +450,154 @@ class TestVolumeCreate(TestVolume):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_volume_create_with_bootable_and_readonly(self):
arglist = [
'--bootable',
'--read-only',
'--size', str(self.new_volume.size),
self.new_volume.name,
]
verifylist = [
('bootable', True),
('non_bootable', False),
('read_only', True),
('read_write', False),
('size', self.new_volume.size),
('name', self.new_volume.name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
size=self.new_volume.size,
snapshot_id=None,
name=self.new_volume.name,
description=None,
volume_type=None,
user_id=None,
project_id=None,
availability_zone=None,
metadata=None,
imageRef=None,
source_volid=None,
consistencygroup_id=None,
source_replica=None,
multiattach=False,
scheduler_hints=None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, True)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, True)
def test_volume_create_with_nonbootable_and_readwrite(self):
arglist = [
'--non-bootable',
'--read-write',
'--size', str(self.new_volume.size),
self.new_volume.name,
]
verifylist = [
('bootable', False),
('non_bootable', True),
('read_only', False),
('read_write', True),
('size', self.new_volume.size),
('name', self.new_volume.name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
size=self.new_volume.size,
snapshot_id=None,
name=self.new_volume.name,
description=None,
volume_type=None,
user_id=None,
project_id=None,
availability_zone=None,
metadata=None,
imageRef=None,
source_volid=None,
consistencygroup_id=None,
source_replica=None,
multiattach=False,
scheduler_hints=None,
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, False)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, False)
@mock.patch.object(volume.LOG, 'error')
def test_volume_create_with_bootable_and_readonly_fail(
self, mock_error):
self.volumes_mock.set_bootable.side_effect = (
exceptions.CommandError())
self.volumes_mock.update_readonly_flag.side_effect = (
exceptions.CommandError())
arglist = [
'--bootable',
'--read-only',
'--size', str(self.new_volume.size),
self.new_volume.name,
]
verifylist = [
('bootable', True),
('non_bootable', False),
('read_only', True),
('read_write', False),
('size', self.new_volume.size),
('name', self.new_volume.name),
]
parsed_args = self.check_parser(
self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.volumes_mock.create.assert_called_with(
size=self.new_volume.size,
snapshot_id=None,
name=self.new_volume.name,
description=None,
volume_type=None,
user_id=None,
project_id=None,
availability_zone=None,
metadata=None,
imageRef=None,
source_volid=None,
consistencygroup_id=None,
source_replica=None,
multiattach=False,
scheduler_hints=None,
)
self.assertEqual(2, mock_error.call_count)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
self.volumes_mock.set_bootable.assert_called_with(
self.new_volume.id, True)
self.volumes_mock.update_readonly_flag.assert_called_with(
self.new_volume.id, True)
def test_volume_create_with_source_replicated(self):
self.volumes_mock.get.return_value = self.new_volume
arglist = [

View File

@ -114,6 +114,28 @@ class CreateVolume(command.ShowOne):
help=_('Set a property on this volume '
'(repeat option to set multiple properties)'),
)
bootable_group = parser.add_mutually_exclusive_group()
bootable_group.add_argument(
"--bootable",
action="store_true",
help=_("Mark volume as bootable")
)
bootable_group.add_argument(
"--non-bootable",
action="store_true",
help=_("Mark volume as non-bootable (default)")
)
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 (default)")
)
return parser
@ -166,6 +188,22 @@ class CreateVolume(command.ShowOne):
parsed_args.property,
image,
)
if parsed_args.bootable or parsed_args.non_bootable:
try:
volume_client.volumes.set_bootable(
volume.id, parsed_args.bootable)
except Exception as e:
LOG.error(_("Failed to set volume bootable property: %s"), e)
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)
# Map 'metadata' column to 'properties'
volume._info.update(
{

View File

@ -132,6 +132,28 @@ class CreateVolume(command.ShowOne):
help=_("Allow volume to be attached more than once "
"(default to False)")
)
bootable_group = parser.add_mutually_exclusive_group()
bootable_group.add_argument(
"--bootable",
action="store_true",
help=_("Mark volume as bootable")
)
bootable_group.add_argument(
"--non-bootable",
action="store_true",
help=_("Mark volume as non-bootable (default)")
)
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 (default)")
)
return parser
def take_action(self, parsed_args):
@ -199,6 +221,22 @@ class CreateVolume(command.ShowOne):
multiattach=parsed_args.multi_attach,
scheduler_hints=parsed_args.hint,
)
if parsed_args.bootable or parsed_args.non_bootable:
try:
volume_client.volumes.set_bootable(
volume.id, parsed_args.bootable)
except Exception as e:
LOG.error(_("Failed to set volume bootable property: %s"), e)
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)
# Remove key links from being displayed
volume._info.update(
{

View File

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