From 98b9bc10d1ab6c205dee7ca3813034ccd1de1005 Mon Sep 17 00:00:00 2001 From: Huanxuan Ao Date: Thu, 10 Nov 2016 21:26:19 +0800 Subject: [PATCH] Add "consistency group create" command Add "consistency group create" command in volume v2 (v2 only). Change-Id: I2e9affe390b1012aa18459e64d04afcdfc15e27d Implements: bp cinder-command-support Partial-Bug: #1613964 --- .../command-objects/consistency-group.rst | 36 +++++ .../unit/volume/v2/test_consistency_group.py | 132 ++++++++++++++++++ .../volume/v2/consistency_group.py | 77 ++++++++++ .../notes/bug-1613964-837196399be16b3d.yaml | 4 + setup.cfg | 1 + 5 files changed, 250 insertions(+) create mode 100644 releasenotes/notes/bug-1613964-837196399be16b3d.yaml diff --git a/doc/source/command-objects/consistency-group.rst b/doc/source/command-objects/consistency-group.rst index f24df0d11..c8c4577cc 100644 --- a/doc/source/command-objects/consistency-group.rst +++ b/doc/source/command-objects/consistency-group.rst @@ -4,6 +4,42 @@ consistency group Block Storage v2 +consistency group create +------------------------ + +Create new consistency group. + +.. program:: consistency group create +.. code:: bash + + os consistency group create + --volume-type | --consistency-group-source + [--description ] + [--availability-zone ] + [] + +.. option:: --volume-type + + Volume type of this consistency group (name or ID) + +.. option:: --consistency-group-source + + Existing consistency group (name or ID) + +.. option:: --description + + Description of this consistency group + +.. option:: --availability-zone + + Availability zone for this consistency group + (not available if creating consistency group from source) + +.. _consistency_group_create-name: +.. option:: + + Name of new consistency group (default to None) + consistency group list ---------------------- diff --git a/openstackclient/tests/unit/volume/v2/test_consistency_group.py b/openstackclient/tests/unit/volume/v2/test_consistency_group.py index 00e1b60e8..e00564216 100644 --- a/openstackclient/tests/unit/volume/v2/test_consistency_group.py +++ b/openstackclient/tests/unit/volume/v2/test_consistency_group.py @@ -28,6 +28,138 @@ class TestConsistencyGroup(volume_fakes.TestVolume): self.app.client_manager.volume.consistencygroups) self.consistencygroups_mock.reset_mock() + self.types_mock = self.app.client_manager.volume.volume_types + self.types_mock.reset_mock() + + +class TestConsistencyGroupCreate(TestConsistencyGroup): + + volume_type = volume_fakes.FakeType.create_one_type() + new_consistency_group = ( + volume_fakes.FakeConsistencyGroup.create_one_consistency_group()) + + columns = ( + 'availability_zone', + 'created_at', + 'description', + 'id', + 'name', + 'status', + 'volume_types', + ) + data = ( + new_consistency_group.availability_zone, + new_consistency_group.created_at, + new_consistency_group.description, + new_consistency_group.id, + new_consistency_group.name, + new_consistency_group.status, + new_consistency_group.volume_types, + ) + + def setUp(self): + super(TestConsistencyGroupCreate, self).setUp() + self.consistencygroups_mock.create.return_value = ( + self.new_consistency_group) + self.consistencygroups_mock.create_from_src.return_value = ( + self.new_consistency_group) + self.consistencygroups_mock.get.return_value = ( + self.new_consistency_group) + self.types_mock.get.return_value = self.volume_type + + # Get the command object to test + self.cmd = consistency_group.CreateConsistencyGroup(self.app, None) + + def test_consistency_group_create(self): + arglist = [ + '--volume-type', self.volume_type.id, + '--description', self.new_consistency_group.description, + '--availability-zone', + self.new_consistency_group.availability_zone, + self.new_consistency_group.name, + ] + verifylist = [ + ('volume_type', self.volume_type.id), + ('description', self.new_consistency_group.description), + ('availability_zone', + self.new_consistency_group.availability_zone), + ('name', self.new_consistency_group.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.types_mock.get.assert_called_once_with( + self.volume_type.id) + self.consistencygroups_mock.get.assert_not_called() + self.consistencygroups_mock.create.assert_called_once_with( + self.volume_type.id, + name=self.new_consistency_group.name, + description=self.new_consistency_group.description, + availability_zone=self.new_consistency_group.availability_zone, + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_consistency_group_create_without_name(self): + arglist = [ + '--volume-type', self.volume_type.id, + '--description', self.new_consistency_group.description, + '--availability-zone', + self.new_consistency_group.availability_zone, + ] + verifylist = [ + ('volume_type', self.volume_type.id), + ('description', self.new_consistency_group.description), + ('availability_zone', + self.new_consistency_group.availability_zone), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.types_mock.get.assert_called_once_with( + self.volume_type.id) + self.consistencygroups_mock.get.assert_not_called() + self.consistencygroups_mock.create.assert_called_once_with( + self.volume_type.id, + name=None, + description=self.new_consistency_group.description, + availability_zone=self.new_consistency_group.availability_zone, + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_consistency_group_create_from_source(self): + arglist = [ + '--consistency-group-source', self.new_consistency_group.id, + '--description', self.new_consistency_group.description, + self.new_consistency_group.name, + ] + verifylist = [ + ('consistency_group_source', self.new_consistency_group.id), + ('description', self.new_consistency_group.description), + ('name', self.new_consistency_group.name), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.types_mock.get.assert_not_called() + self.consistencygroups_mock.get.assert_called_once_with( + self.new_consistency_group.id) + self.consistencygroups_mock.create_from_src.assert_called_with( + None, + self.new_consistency_group.id, + name=self.new_consistency_group.name, + description=self.new_consistency_group.description, + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + class TestConsistencyGroupList(TestConsistencyGroup): diff --git a/openstackclient/volume/v2/consistency_group.py b/openstackclient/volume/v2/consistency_group.py index 0754fdc70..9316f2873 100644 --- a/openstackclient/volume/v2/consistency_group.py +++ b/openstackclient/volume/v2/consistency_group.py @@ -14,12 +14,89 @@ """Volume v2 consistency group action implementations""" +import logging + from osc_lib.command import command from osc_lib import utils +import six from openstackclient.i18n import _ +LOG = logging.getLogger(__name__) + + +class CreateConsistencyGroup(command.ShowOne): + _description = _("Create new consistency group.") + + def get_parser(self, prog_name): + parser = super(CreateConsistencyGroup, self).get_parser(prog_name) + parser.add_argument( + "name", + metavar="", + nargs="?", + help=_("Name of new consistency group (default to None)") + ) + exclusive_group = parser.add_mutually_exclusive_group(required=True) + exclusive_group.add_argument( + "--volume-type", + metavar="", + help=_("Volume type of this consistency group (name or ID)") + ) + exclusive_group.add_argument( + "--consistency-group-source", + metavar="", + help=_("Existing consistency group (name or ID)") + ) + parser.add_argument( + "--description", + metavar="", + help=_("Description of this consistency group") + ) + parser.add_argument( + "--availability-zone", + metavar="", + help=_("Availability zone for this consistency group " + "(not available if creating consistency group " + "from source)"), + ) + return parser + + def take_action(self, parsed_args): + volume_client = self.app.client_manager.volume + if parsed_args.volume_type: + volume_type_id = utils.find_resource( + volume_client.volume_types, + parsed_args.volume_type).id + consistency_group = volume_client.consistencygroups.create( + volume_type_id, + name=parsed_args.name, + description=parsed_args.description, + availability_zone=parsed_args.availability_zone + ) + elif parsed_args.consistency_group_source: + if parsed_args.availability_zone: + msg = _("'--availability-zone' option will not work " + "if creating consistency group from source") + LOG.warning(msg) + consistency_group_id = utils.find_resource( + volume_client.consistencygroups, + parsed_args.consistency_group_source).id + consistency_group_snapshot = None + # TODO(Huanxuan Ao): Support for creating from consistency group + # snapshot after adding "consistency_group_snapshot" resource + consistency_group = ( + volume_client.consistencygroups.create_from_src( + consistency_group_snapshot, + consistency_group_id, + name=parsed_args.name, + description=parsed_args.description + ) + ) + + return zip(*sorted(six.iteritems(consistency_group._info))) + + class ListConsistencyGroup(command.Lister): _description = _("List consistency groups.") diff --git a/releasenotes/notes/bug-1613964-837196399be16b3d.yaml b/releasenotes/notes/bug-1613964-837196399be16b3d.yaml new file mode 100644 index 000000000..0f17930eb --- /dev/null +++ b/releasenotes/notes/bug-1613964-837196399be16b3d.yaml @@ -0,0 +1,4 @@ +--- +features: + - Add ``consistency group create`` command in volume v2. + [Bug `1613964 `_] diff --git a/setup.cfg b/setup.cfg index c94437393..e86eba4d8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -506,6 +506,7 @@ openstack.volume.v2 = backup_restore = openstackclient.volume.v2.backup:RestoreBackup backup_show = openstackclient.volume.v2.backup:ShowBackup + consistency_group_create = openstackclient.volume.v2.consistency_group:CreateConsistencyGroup consistency_group_list = openstackclient.volume.v2.consistency_group:ListConsistencyGroup snapshot_create = openstackclient.volume.v2.snapshot:CreateSnapshot