summaryrefslogtreecommitdiff
path: root/cinderclient
diff options
context:
space:
mode:
authorxing-yang <xing.yang@emc.com>2016-07-09 21:56:42 -0400
committerxing-yang <xing.yang@emc.com>2017-05-05 02:14:56 -0400
commitda79866e1431442431cb3c077b57252caa480750 (patch)
tree38ee75939524adad9003e61381be8bb1b2610f31 /cinderclient
parent0fdd41d84ccfa16245d60617a4099e120f6100cf (diff)
downloadpython-cinderclient-da79866e1431442431cb3c077b57252caa480750.tar.gz
Tiramisu: replication group support
This patch adds CLI support for replication group. It is built upon the generic volume groups. Server side patch is here: https://review.openstack.org/#/c/352228/ Depends-On: I4d488252bd670b3ebabbcc9f5e29e0e4e913765a Change-Id: I462c3ab8c9c3a6a1b434748f81d208359ffd2431 Implements: blueprint replication-cg
Diffstat (limited to 'cinderclient')
-rw-r--r--cinderclient/tests/unit/v3/fakes.py3
-rw-r--r--cinderclient/tests/unit/v3/test_groups.py54
-rw-r--r--cinderclient/tests/unit/v3/test_shell.py34
-rw-r--r--cinderclient/v3/groups.py71
-rw-r--r--cinderclient/v3/shell.py69
5 files changed, 230 insertions, 1 deletions
diff --git a/cinderclient/tests/unit/v3/fakes.py b/cinderclient/tests/unit/v3/fakes.py
index 25a8151..7b6ea71 100644
--- a/cinderclient/tests/unit/v3/fakes.py
+++ b/cinderclient/tests/unit/v3/fakes.py
@@ -369,6 +369,9 @@ class FakeHTTPClient(fake_v2.FakeHTTPClient):
action = list(body)[0]
if action == 'delete':
assert 'delete-volumes' in body[action]
+ elif action in ('enable_replication', 'disable_replication',
+ 'failover_replication', 'list_replication_targets'):
+ assert action in body
else:
raise AssertionError("Unexpected action: %s" % action)
return (resp, {}, {})
diff --git a/cinderclient/tests/unit/v3/test_groups.py b/cinderclient/tests/unit/v3/test_groups.py
index 72e72a0..d74e2a0 100644
--- a/cinderclient/tests/unit/v3/test_groups.py
+++ b/cinderclient/tests/unit/v3/test_groups.py
@@ -158,3 +158,57 @@ class GroupsTest(utils.TestCase):
cs.assert_called('POST', '/groups/action',
body=expected)
self._assert_request_id(grp)
+
+ def test_enable_replication_group(self):
+ expected = {'enable_replication': {}}
+ g0 = cs.groups.list()[0]
+ grp = g0.enable_replication()
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.enable_replication('1234')
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.enable_replication(g0)
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+
+ def test_disable_replication_group(self):
+ expected = {'disable_replication': {}}
+ g0 = cs.groups.list()[0]
+ grp = g0.disable_replication()
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.disable_replication('1234')
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.disable_replication(g0)
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+
+ def test_failover_replication_group(self):
+ expected = {'failover_replication':
+ {'allow_attached_volume': False,
+ 'secondary_backend_id': None}}
+ g0 = cs.groups.list()[0]
+ grp = g0.failover_replication()
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.failover_replication('1234')
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.failover_replication(g0)
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+
+ def test_list_replication_targets(self):
+ expected = {'list_replication_targets': {}}
+ g0 = cs.groups.list()[0]
+ grp = g0.list_replication_targets()
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.list_replication_targets('1234')
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
+ grp = cs.groups.list_replication_targets(g0)
+ self._assert_request_id(grp)
+ cs.assert_called('POST', '/groups/1234/action', body=expected)
diff --git a/cinderclient/tests/unit/v3/test_shell.py b/cinderclient/tests/unit/v3/test_shell.py
index 9777548..bfd2d93 100644
--- a/cinderclient/tests/unit/v3/test_shell.py
+++ b/cinderclient/tests/unit/v3/test_shell.py
@@ -754,3 +754,37 @@ class ShellTest(utils.TestCase):
command += ' --withreplication %s' % replication
self.run_command(command)
self.assert_called('GET', '/os-services')
+
+ def test_group_enable_replication(self):
+ cmd = '--os-volume-api-version 3.38 group-enable-replication 1234'
+ self.run_command(cmd)
+ expected = {'enable_replication': {}}
+ self.assert_called('POST', '/groups/1234/action', body=expected)
+
+ def test_group_disable_replication(self):
+ cmd = '--os-volume-api-version 3.38 group-disable-replication 1234'
+ self.run_command(cmd)
+ expected = {'disable_replication': {}}
+ self.assert_called('POST', '/groups/1234/action', body=expected)
+
+ @ddt.data((False, None), (True, None),
+ (False, "backend1"), (True, "backend1"),
+ (False, "default"), (True, "default"))
+ @ddt.unpack
+ def test_group_failover_replication(self, attach_vol, backend):
+ attach = '--allow-attached-volume ' if attach_vol else ''
+ backend_id = ('--secondary-backend-id ' + backend) if backend else ''
+ cmd = ('--os-volume-api-version 3.38 group-failover-replication 1234 '
+ + attach + backend_id)
+ self.run_command(cmd)
+ expected = {'failover_replication':
+ {'allow_attached_volume': attach_vol,
+ 'secondary_backend_id': backend if backend else None}}
+ self.assert_called('POST', '/groups/1234/action', body=expected)
+
+ def test_group_list_replication_targets(self):
+ cmd = ('--os-volume-api-version 3.38 group-list-replication-targets'
+ ' 1234')
+ self.run_command(cmd)
+ expected = {'list_replication_targets': {}}
+ self.assert_called('POST', '/groups/1234/action', body=expected)
diff --git a/cinderclient/v3/groups.py b/cinderclient/v3/groups.py
index 386a6a3..6bc298a 100644
--- a/cinderclient/v3/groups.py
+++ b/cinderclient/v3/groups.py
@@ -39,6 +39,25 @@ class Group(base.Resource):
"""Reset the group's state with specified one"""
return self.manager.reset_state(self, state)
+ def enable_replication(self):
+ """Enables replication for this group."""
+ return self.manager.enable_replication(self)
+
+ def disable_replication(self):
+ """Disables replication for this group."""
+ return self.manager.disable_replication(self)
+
+ def failover_replication(self, allow_attached_volume=False,
+ secondary_backend_id=None):
+ """Fails over replication for this group."""
+ return self.manager.failover_replication(self,
+ allow_attached_volume,
+ secondary_backend_id)
+
+ def list_replication_targets(self):
+ """Lists replication targets for this group."""
+ return self.manager.list_replication_targets(self)
+
class GroupManager(base.ManagerWithFind):
"""Manage :class:`Group` resources."""
@@ -180,3 +199,55 @@ class GroupManager(base.ManagerWithFind):
url = '/groups/%s/action' % base.getid(group)
resp, body = self.api.client.post(url, body=body)
return common_base.TupleWithMeta((resp, body), resp)
+
+ def enable_replication(self, group):
+ """Enables replication for a group.
+
+ :param group: the :class:`Group` to enable replication.
+ """
+ body = {'enable_replication': {}}
+ self.run_hooks('modify_body_for_action', body, 'group')
+ url = '/groups/%s/action' % base.getid(group)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def disable_replication(self, group):
+ """disables replication for a group.
+
+ :param group: the :class:`Group` to disable replication.
+ """
+ body = {'disable_replication': {}}
+ self.run_hooks('modify_body_for_action', body, 'group')
+ url = '/groups/%s/action' % base.getid(group)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def failover_replication(self, group, allow_attached_volume=False,
+ secondary_backend_id=None):
+ """fails over replication for a group.
+
+ :param group: the :class:`Group` to failover.
+ :param allow attached volumes: allow attached volumes in the group.
+ :param secondary_backend_id: secondary backend id.
+ """
+ body = {
+ 'failover_replication': {
+ 'allow_attached_volume': allow_attached_volume,
+ 'secondary_backend_id': secondary_backend_id
+ }
+ }
+ self.run_hooks('modify_body_for_action', body, 'group')
+ url = '/groups/%s/action' % base.getid(group)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
+
+ def list_replication_targets(self, group):
+ """List replication targets for a group.
+
+ :param group: the :class:`Group` to list replication targets.
+ """
+ body = {'list_replication_targets': {}}
+ self.run_hooks('modify_body_for_action', body, 'group')
+ url = '/groups/%s/action' % base.getid(group)
+ resp, body = self.api.client.post(url, body=body)
+ return common_base.TupleWithMeta((resp, body), resp)
diff --git a/cinderclient/v3/shell.py b/cinderclient/v3/shell.py
index 8994906..3b73b15 100644
--- a/cinderclient/v3/shell.py
+++ b/cinderclient/v3/shell.py
@@ -1174,7 +1174,74 @@ def do_group_update(cs, args):
print("Request to update group '%s' has been accepted." % args.group)
-@api_versions.wraps('3.14')
+@api_versions.wraps('3.38')
+@utils.arg('group',
+ metavar='<group>',
+ help='Name or ID of the group.')
+def do_group_enable_replication(cs, args):
+ """Enables replication for group."""
+
+ shell_utils.find_group(cs, args.group).enable_replication()
+
+
+@api_versions.wraps('3.38')
+@utils.arg('group',
+ metavar='<group>',
+ help='Name or ID of the group.')
+def do_group_disable_replication(cs, args):
+ """Disables replication for group."""
+
+ shell_utils.find_group(cs, args.group).disable_replication()
+
+
+@api_versions.wraps('3.38')
+@utils.arg('group',
+ metavar='<group>',
+ help='Name or ID of the group.')
+@utils.arg('--allow-attached-volume',
+ action='store_true',
+ default=False,
+ help='Allows or disallows group with '
+ 'attached volumes to be failed over.')
+@utils.arg('--secondary-backend-id',
+ metavar='<secondary_backend_id>',
+ help='Secondary backend id. Default=None.')
+def do_group_failover_replication(cs, args):
+ """Fails over replication for group."""
+
+ shell_utils.find_group(cs, args.group).failover_replication(
+ allow_attached_volume=args.allow_attached_volume,
+ secondary_backend_id=args.secondary_backend_id)
+
+
+@api_versions.wraps('3.38')
+@utils.arg('group',
+ metavar='<group>',
+ help='Name or ID of the group.')
+def do_group_list_replication_targets(cs, args):
+ """Lists replication targets for group.
+
+ Example value for replication_targets:
+
+ .. code-block: json
+
+ {
+ 'replication_targets': [{'backend_id': 'vendor-id-1',
+ 'unique_key': 'val1',
+ ......},
+ {'backend_id': 'vendor-id-2',
+ 'unique_key': 'val2',
+ ......}]
+ }
+ """
+
+ rc, replication_targets = shell_utils.find_group(
+ cs, args.group).list_replication_targets()
+ rep_targets = replication_targets.get('replication_targets')
+ if rep_targets and len(rep_targets) > 0:
+ utils.print_list(rep_targets, [key for key in rep_targets[0].keys()])
+
+
@utils.arg('--all-tenants',
dest='all_tenants',
metavar='<0|1>',