Adds v2 replication support

v2 replication has been merged in cinder, but there is no way to call
the api methods. This patch allows the following methods to be called
in order to fully support v2 replication:
  - os-enable_replication
  - os-disable_replication
  - os-list_replication_targets
  - os-failover_replication

Change-Id: Ic3cf082916bdf089de05eebce456dff8cdc11f7c
Implements: blueprint replication-v2
This commit is contained in:
Alex O'Rourke
2015-10-06 13:20:30 -07:00
parent e4c580f628
commit b8e118f5c2
4 changed files with 135 additions and 0 deletions

View File

@@ -437,6 +437,14 @@ class FakeHTTPClient(base_client.HTTPClient):
elif action == 'os-migrate_volume':
assert 'host' in body[action]
assert 'force_host_copy' in body[action]
elif action == 'os-enable_replication':
assert body[action] is None
elif action == 'os-disable_replication':
assert body[action] is None
elif action == 'os-list_replication_targets':
assert body[action] is None
elif action == 'os-failover_replication':
assert 'secondary' in body[action]
elif action == 'os-update_readonly_flag':
assert list(body[action]) == ['readonly']
elif action == 'os-retype':

View File

@@ -772,6 +772,23 @@ class ShellTest(utils.TestCase):
self.assert_called('POST', '/volumes/1234/action',
body=expected)
def test_replication_enable(self):
self.run_command('replication-enable 1234')
self.assert_called('POST', '/volumes/1234/action')
def test_replication_disable(self):
self.run_command('replication-disable 1234')
self.assert_called('POST', '/volumes/1234/action')
def test_replication_list_targets(self):
self.run_command('replication-list-targets 1234')
self.assert_called('POST', '/volumes/1234/action')
def test_replication_failover(self):
self.run_command('replication-failover 1234 target')
expected = {'os-failover_replication': {'secondary': 'target'}}
self.assert_called('POST', '/volumes/1234/action', body=expected)
def test_snapshot_metadata_set(self):
self.run_command('snapshot-metadata 1234 set key1=val1 key2=val2')
self.assert_called('POST', '/snapshots/1234/metadata',

View File

@@ -1206,6 +1206,60 @@ def do_migrate(cs, args):
six.text_type(e)))
@utils.arg('volume',
metavar='<volume>',
help='ID of volume to enable replication.')
@utils.service_type('volumev2')
def do_replication_enable(cs, args):
"""Enables volume replication on a given volume."""
volume = utils.find_volume(cs, args.volume)
volume.replication_enable(args.volume)
@utils.arg('volume',
metavar='<volume>',
help='ID of volume to disable replication.')
@utils.service_type('volumev2')
def do_replication_disable(cs, args):
"""Disables volume replication on a given volume."""
volume = utils.find_volume(cs, args.volume)
volume.replication_disable(args.volume)
@utils.arg('volume',
metavar='<volume>',
help='ID of volume to list available replication targets.')
@utils.service_type('volumev2')
def do_replication_list_targets(cs, args):
"""List replication targets available for a volume."""
volume = utils.find_volume(cs, args.volume)
resp, body = volume.replication_list_targets(args.volume)
if body:
targets = body['targets']
columns = ['target_device_id']
if targets:
utils.print_list(targets, columns)
else:
print("There are no replication targets found for volume %s." %
args.volume)
else:
print("There is no replication information for volume %s." %
args.volume)
@utils.arg('volume',
metavar='<volume>',
help='ID of volume to failover.')
@utils.arg('secondary',
metavar='<secondary>',
help='A unqiue identifier that represents a failover target.')
@utils.service_type('volumev2')
def do_replication_failover(cs, args):
"""Failover a volume to a secondary target"""
volume = utils.find_volume(cs, args.volume)
volume.replication_failover(args.volume, args.secondary)
@utils.arg('volume', metavar='<volume>',
help='Name or ID of volume for which to modify type.')
@utils.arg('new_type', metavar='<volume-type>', help='New volume type.')

View File

@@ -150,6 +150,22 @@ class Volume(base.Resource):
"""Migrate the volume to a new host."""
self.manager.migrate_volume(self, host, force_host_copy, lock_volume)
def replication_enable(self, volume):
"""Enables volume replication on a given volume."""
return self.manager.replication_enable(volume)
def replication_disable(self, volume):
"""Disables volume replication on a given volume."""
return self.manager.replication_disable(volume)
def replication_list_targets(self, volume):
"""List replication targets available for a volume."""
return self.manager.replication_list_targets(volume)
def replication_failover(self, volume, secondary):
"""Failover a volume to a secondary target."""
return self.manager.replication_failover(volume, secondary)
def retype(self, volume_type, policy):
"""Change a volume's type."""
self.manager.retype(self, volume_type, policy)
@@ -601,6 +617,46 @@ class VolumeManager(base.ManagerWithFind):
old_volume,
{'new_volume': new_volume_id, 'error': error})[1]
def replication_enable(self, volume_id):
"""
Enables volume replication on a given volume.
:param volume_id: The id of the volume to query
"""
return self._action('os-enable_replication',
volume_id)
def replication_disable(self, volume_id):
"""
Disables volume replication on a given volume.
:param volume_id: The id of the volume to query
"""
return self._action('os-disable_replication',
volume_id)
def replication_list_targets(self, volume_id):
"""
List replication targets available for a volume.
:param volume_id: The id of the volume to query
:return: a list of available replication targets
"""
return self._action('os-list_replication_targets',
volume_id)
def replication_failover(self, volume_id, secondary):
"""
Failover a volume to a secondary target.
:param volume_id: The id of the volume to query
:param secondary: A unqiue identifier that represents a failover
target
"""
return self._action('os-failover_replication',
volume_id,
{"secondary": secondary})
def update_all_metadata(self, volume, metadata):
"""Update all metadata of a volume.