summaryrefslogtreecommitdiff
path: root/openstackclient
diff options
context:
space:
mode:
authorzhiyong.dai <zhiyong.dai@easystack.cn>2016-12-06 19:08:49 +0800
committerzhiyong.dai <zhiyong.dai@easystack.cn>2016-12-13 15:32:04 +0800
commit2f2603d90896d0765e1bb2bb1cfb223fdba75835 (patch)
treefc0d629b2355479898e557b6c1f0558e7d27ad91 /openstackclient
parent29587eaa6661493b7df9357ad818bf058e820730 (diff)
downloadpython-openstackclient-2f2603d90896d0765e1bb2bb1cfb223fdba75835.tar.gz
Add two consistency group commands
Add commands: consistency group add volume consistency group remove volume in volume v2 (v2 only) Change-Id: I70ff287d3b5df78196b8f4b9e50402c471aef284 Implements: bp cinder-command-support Closes-Bug: #1613964
Diffstat (limited to 'openstackclient')
-rw-r--r--openstackclient/tests/unit/volume/v2/test_consistency_group.py206
-rw-r--r--openstackclient/volume/v2/consistency_group.py92
2 files changed, 298 insertions, 0 deletions
diff --git a/openstackclient/tests/unit/volume/v2/test_consistency_group.py b/openstackclient/tests/unit/volume/v2/test_consistency_group.py
index bc99ca8d..6eeeae39 100644
--- a/openstackclient/tests/unit/volume/v2/test_consistency_group.py
+++ b/openstackclient/tests/unit/volume/v2/test_consistency_group.py
@@ -36,10 +36,115 @@ class TestConsistencyGroup(volume_fakes.TestVolume):
self.app.client_manager.volume.cgsnapshots)
self.cgsnapshots_mock.reset_mock()
+ self.volumes_mock = (
+ self.app.client_manager.volume.volumes)
+ self.volumes_mock.reset_mock()
+
self.types_mock = self.app.client_manager.volume.volume_types
self.types_mock.reset_mock()
+class TestConsistencyGroupAddVolume(TestConsistencyGroup):
+
+ _consistency_group = (
+ volume_fakes.FakeConsistencyGroup.create_one_consistency_group())
+
+ def setUp(self):
+ super(TestConsistencyGroupAddVolume, self).setUp()
+
+ self.consistencygroups_mock.get.return_value = (
+ self._consistency_group)
+ # Get the command object to test
+ self.cmd = \
+ consistency_group.AddVolumeToConsistencyGroup(self.app, None)
+
+ def test_add_one_volume_to_consistency_group(self):
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = volume
+ arglist = [
+ self._consistency_group.id,
+ volume.id,
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volume.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'add_volumes': volume.id,
+ }
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_add_multiple_volumes_to_consistency_group(self):
+ volumes = volume_fakes.FakeVolume.create_volumes(count=2)
+ self.volumes_mock.get = volume_fakes.FakeVolume.get_volumes(volumes)
+ arglist = [
+ self._consistency_group.id,
+ volumes[0].id,
+ volumes[1].id,
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volumes[0].id, volumes[1].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'add_volumes': volumes[0].id + ',' + volumes[1].id,
+ }
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ @mock.patch.object(consistency_group.LOG, 'error')
+ def test_add_multiple_volumes_to_consistency_group_with_exception(
+ self, mock_error):
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ arglist = [
+ self._consistency_group.id,
+ volume.id,
+ 'unexist_volume',
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volume.id, 'unexist_volume']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [volume,
+ exceptions.CommandError,
+ self._consistency_group]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ result = self.cmd.take_action(parsed_args)
+ mock_error.assert_called_with("1 of 2 volumes failed to add.")
+ self.assertIsNone(result)
+ find_mock.assert_any_call(self.consistencygroups_mock,
+ self._consistency_group.id)
+ find_mock.assert_any_call(self.volumes_mock,
+ volume.id)
+ find_mock.assert_any_call(self.volumes_mock,
+ 'unexist_volume')
+ self.assertEqual(3, find_mock.call_count)
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id, add_volumes=volume.id
+ )
+
+
class TestConsistencyGroupCreate(TestConsistencyGroup):
volume_type = volume_fakes.FakeType.create_one_type()
@@ -394,6 +499,107 @@ class TestConsistencyGroupList(TestConsistencyGroup):
self.assertEqual(self.data_long, list(data))
+class TestConsistencyGroupRemoveVolume(TestConsistencyGroup):
+
+ _consistency_group = (
+ volume_fakes.FakeConsistencyGroup.create_one_consistency_group())
+
+ def setUp(self):
+ super(TestConsistencyGroupRemoveVolume, self).setUp()
+
+ self.consistencygroups_mock.get.return_value = (
+ self._consistency_group)
+ # Get the command object to test
+ self.cmd = \
+ consistency_group.RemoveVolumeFromConsistencyGroup(self.app, None)
+
+ def test_remove_one_volume_from_consistency_group(self):
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ self.volumes_mock.get.return_value = volume
+ arglist = [
+ self._consistency_group.id,
+ volume.id,
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volume.id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remove_volumes': volume.id,
+ }
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ def test_remove_multi_volumes_from_consistency_group(self):
+ volumes = volume_fakes.FakeVolume.create_volumes(count=2)
+ self.volumes_mock.get = volume_fakes.FakeVolume.get_volumes(volumes)
+ arglist = [
+ self._consistency_group.id,
+ volumes[0].id,
+ volumes[1].id,
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volumes[0].id, volumes[1].id]),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'remove_volumes': volumes[0].id + ',' + volumes[1].id,
+ }
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id,
+ **kwargs
+ )
+ self.assertIsNone(result)
+
+ @mock.patch.object(consistency_group.LOG, 'error')
+ def test_remove_multiple_volumes_from_consistency_group_with_exception(
+ self, mock_error):
+ volume = volume_fakes.FakeVolume.create_one_volume()
+ arglist = [
+ self._consistency_group.id,
+ volume.id,
+ 'unexist_volume',
+ ]
+ verifylist = [
+ ('consistency_group', self._consistency_group.id),
+ ('volumes', [volume.id, 'unexist_volume']),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ find_mock_result = [volume,
+ exceptions.CommandError,
+ self._consistency_group]
+ with mock.patch.object(utils, 'find_resource',
+ side_effect=find_mock_result) as find_mock:
+ result = self.cmd.take_action(parsed_args)
+ mock_error.assert_called_with("1 of 2 volumes failed to remove.")
+ self.assertIsNone(result)
+ find_mock.assert_any_call(self.consistencygroups_mock,
+ self._consistency_group.id)
+ find_mock.assert_any_call(self.volumes_mock,
+ volume.id)
+ find_mock.assert_any_call(self.volumes_mock,
+ 'unexist_volume')
+ self.assertEqual(3, find_mock.call_count)
+ self.consistencygroups_mock.update.assert_called_once_with(
+ self._consistency_group.id, remove_volumes=volume.id
+ )
+
+
class TestConsistencyGroupSet(TestConsistencyGroup):
consistency_group = (
diff --git a/openstackclient/volume/v2/consistency_group.py b/openstackclient/volume/v2/consistency_group.py
index 2f4f3c95..0a932f84 100644
--- a/openstackclient/volume/v2/consistency_group.py
+++ b/openstackclient/volume/v2/consistency_group.py
@@ -27,6 +27,60 @@ from openstackclient.i18n import _
LOG = logging.getLogger(__name__)
+def _find_volumes(parsed_args_volumes, volume_client):
+ result = 0
+ uuid = ''
+ for volume in parsed_args_volumes:
+ try:
+ volume_id = utils.find_resource(
+ volume_client.volumes, volume).id
+ uuid += volume_id + ','
+ except Exception as e:
+ result += 1
+ LOG.error(_("Failed to find volume with "
+ "name or ID '%(volume)s':%(e)s")
+ % {'volume': volume, 'e': e})
+
+ return result, uuid
+
+
+class AddVolumeToConsistencyGroup(command.Command):
+ _description = _("Add volume(s) to consistency group")
+
+ def get_parser(self, prog_name):
+ parser = super(AddVolumeToConsistencyGroup, self).get_parser(prog_name)
+ parser.add_argument(
+ 'consistency_group',
+ metavar="<consistency-group>",
+ help=_('Consistency group to contain <volume> (name or ID)'),
+ )
+ parser.add_argument(
+ 'volumes',
+ metavar='<volume>',
+ nargs='+',
+ help=_('Volume(s) to add to <consistency-group> (name or ID) '
+ '(repeat option to add multiple volumes)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ result, add_uuid = _find_volumes(parsed_args.volumes, volume_client)
+
+ if result > 0:
+ total = len(parsed_args.volumes)
+ LOG.error(_("%(result)s of %(total)s volumes failed "
+ "to add.") % {'result': result, 'total': total})
+
+ if add_uuid:
+ add_uuid = add_uuid.rstrip(',')
+ consistency_group_id = utils.find_resource(
+ volume_client.consistencygroups,
+ parsed_args.consistency_group).id
+ volume_client.consistencygroups.update(
+ consistency_group_id, add_volumes=add_uuid)
+
+
class CreateConsistencyGroup(command.ShowOne):
_description = _("Create new consistency group.")
@@ -188,6 +242,44 @@ class ListConsistencyGroup(command.Lister):
for s in consistency_groups))
+class RemoveVolumeFromConsistencyGroup(command.Command):
+ _description = _("Remove volume(s) from consistency group")
+
+ def get_parser(self, prog_name):
+ parser = \
+ super(RemoveVolumeFromConsistencyGroup, self).get_parser(prog_name)
+ parser.add_argument(
+ 'consistency_group',
+ metavar="<consistency-group>",
+ help=_('Consistency group containing <volume> (name or ID)'),
+ )
+ parser.add_argument(
+ 'volumes',
+ metavar='<volume>',
+ nargs='+',
+ help=_('Volume(s) to remove from <consistency-group> (name or ID) '
+ '(repeat option to remove multiple volumes)'),
+ )
+ return parser
+
+ def take_action(self, parsed_args):
+ volume_client = self.app.client_manager.volume
+ result, remove_uuid = _find_volumes(parsed_args.volumes, volume_client)
+
+ if result > 0:
+ total = len(parsed_args.volumes)
+ LOG.error(_("%(result)s of %(total)s volumes failed "
+ "to remove.") % {'result': result, 'total': total})
+
+ if remove_uuid:
+ remove_uuid = remove_uuid.rstrip(',')
+ consistency_group_id = utils.find_resource(
+ volume_client.consistencygroups,
+ parsed_args.consistency_group).id
+ volume_client.consistencygroups.update(
+ consistency_group_id, remove_volumes=remove_uuid)
+
+
class SetConsistencyGroup(command.Command):
_description = _("Set consistency group properties")