Merge "Updates consistency group for ibm svc driver"
This commit is contained in:
commit
7df01a599a
@ -2646,6 +2646,15 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
cg = testutils.create_consistencygroup(self.ctxt, **kwargs)
|
cg = testutils.create_consistencygroup(self.ctxt, **kwargs)
|
||||||
return cg
|
return cg
|
||||||
|
|
||||||
|
def _create_consistencegroup(self, **kwargs):
|
||||||
|
cg = self._create_consistencygroup_in_db(**kwargs)
|
||||||
|
|
||||||
|
model_update = self.driver.create_consistencygroup(self.ctxt, cg)
|
||||||
|
self.assertEqual('available',
|
||||||
|
model_update['status'],
|
||||||
|
"CG created failed")
|
||||||
|
return cg
|
||||||
|
|
||||||
def _create_cgsnapshot_in_db(self, cg_id, **kwargs):
|
def _create_cgsnapshot_in_db(self, cg_id, **kwargs):
|
||||||
cg_snapshot = testutils.create_cgsnapshot(self.ctxt,
|
cg_snapshot = testutils.create_cgsnapshot(self.ctxt,
|
||||||
consistencygroup_id= cg_id,
|
consistencygroup_id= cg_id,
|
||||||
@ -2669,6 +2678,22 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
|
|
||||||
return cg_snapshot
|
return cg_snapshot
|
||||||
|
|
||||||
|
def _create_cgsnapshot(self, cg_id, **kwargs):
|
||||||
|
cg_snapshot = self._create_cgsnapshot_in_db(cg_id, **kwargs)
|
||||||
|
|
||||||
|
model_update, snapshots = (
|
||||||
|
self.driver.create_cgsnapshot(self.ctxt, cg_snapshot, []))
|
||||||
|
self.assertEqual('available',
|
||||||
|
model_update['status'],
|
||||||
|
"CGSnapshot created failed")
|
||||||
|
|
||||||
|
for snapshot in snapshots:
|
||||||
|
self.assertEqual('available', snapshot['status'])
|
||||||
|
snapshots = (
|
||||||
|
self.db.snapshot_get_all_for_cgsnapshot(self.ctxt.elevated(),
|
||||||
|
cg_snapshot['id']))
|
||||||
|
return cg_snapshot, snapshots
|
||||||
|
|
||||||
def _create_test_vol(self, opts):
|
def _create_test_vol(self, opts):
|
||||||
ctxt = testutils.get_test_admin_context()
|
ctxt = testutils.get_test_admin_context()
|
||||||
type_ref = volume_types.create(ctxt, 'testtype', opts)
|
type_ref = volume_types.create(ctxt, 'testtype', opts)
|
||||||
@ -3808,6 +3833,170 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase):
|
|||||||
for volume in model_update[1]:
|
for volume in model_update[1]:
|
||||||
self.assertEqual('deleted', volume['status'])
|
self.assertEqual('deleted', volume['status'])
|
||||||
|
|
||||||
|
def test_storwize_consistency_group_from_src_invalid(self):
|
||||||
|
# Invalid input case for create cg from src
|
||||||
|
cg_type = self._create_consistency_group_volume_type()
|
||||||
|
self.ctxt.user_id = 'fake_user_id'
|
||||||
|
self.ctxt.project_id = 'fake_project_id'
|
||||||
|
# create cg in db
|
||||||
|
cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
|
||||||
|
|
||||||
|
# create volumes in db
|
||||||
|
vol1 = testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=cg['id'])
|
||||||
|
vol2 = testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=cg['id'])
|
||||||
|
volumes = [vol1, vol2]
|
||||||
|
|
||||||
|
source_cg = self._create_consistencegroup(volume_type_id=cg_type['id'])
|
||||||
|
|
||||||
|
# Add volumes to source CG
|
||||||
|
src_vol1 = self._create_volume(volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=source_cg['id'])
|
||||||
|
src_vol2 = self._create_volume(volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=source_cg['id'])
|
||||||
|
source_vols = [src_vol1, src_vol2]
|
||||||
|
|
||||||
|
cgsnapshot, snapshots = self._create_cgsnapshot(source_cg['id'])
|
||||||
|
|
||||||
|
# Create cg from src with null input
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_consistencygroup_from_src,
|
||||||
|
self.ctxt, cg, volumes, None, None,
|
||||||
|
None, None)
|
||||||
|
|
||||||
|
# Create cg from src with source_cg and empty source_vols
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_consistencygroup_from_src,
|
||||||
|
self.ctxt, cg, volumes, None, None,
|
||||||
|
source_cg, None)
|
||||||
|
|
||||||
|
# Create cg from src with source_vols and empty source_cg
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_consistencygroup_from_src,
|
||||||
|
self.ctxt, cg, volumes, None, None,
|
||||||
|
None, source_vols)
|
||||||
|
|
||||||
|
# Create cg from src with cgsnapshot and empty snapshots
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_consistencygroup_from_src,
|
||||||
|
self.ctxt, cg, volumes, cgsnapshot, None,
|
||||||
|
None, None)
|
||||||
|
# Create cg from src with snapshots and empty cgsnapshot
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_consistencygroup_from_src,
|
||||||
|
self.ctxt, cg, volumes, None, snapshots,
|
||||||
|
None, None)
|
||||||
|
|
||||||
|
model_update = self.driver.delete_consistencygroup(self.ctxt, cg, [])
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for volume in model_update[1]:
|
||||||
|
self.assertEqual('deleted', volume['status'])
|
||||||
|
|
||||||
|
model_update = (
|
||||||
|
self.driver.delete_consistencygroup(self.ctxt, source_cg, []))
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for volume in model_update[1]:
|
||||||
|
self.assertEqual('deleted', volume['status'])
|
||||||
|
|
||||||
|
model_update = (
|
||||||
|
self.driver.delete_consistencygroup(self.ctxt, cgsnapshot, []))
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for volume in model_update[1]:
|
||||||
|
self.assertEqual('deleted', volume['status'])
|
||||||
|
|
||||||
|
def test_storwize_consistency_group_from_src(self):
|
||||||
|
# Valid case for create cg from src
|
||||||
|
cg_type = self._create_consistency_group_volume_type()
|
||||||
|
self.ctxt.user_id = 'fake_user_id'
|
||||||
|
self.ctxt.project_id = 'fake_project_id'
|
||||||
|
|
||||||
|
# Create cg in db
|
||||||
|
cg = self._create_consistencygroup_in_db(volume_type_id=cg_type['id'])
|
||||||
|
# Create volumes in db
|
||||||
|
testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=cg['id'])
|
||||||
|
testutils.create_volume(self.ctxt, volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=cg['id'])
|
||||||
|
volumes = (
|
||||||
|
self.db.volume_get_all_by_group(self.ctxt.elevated(), cg['id']))
|
||||||
|
|
||||||
|
# Create source CG
|
||||||
|
source_cg = self._create_consistencegroup(volume_type_id=cg_type['id'])
|
||||||
|
# Add volumes to source CG
|
||||||
|
self._create_volume(volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=source_cg['id'])
|
||||||
|
self._create_volume(volume_type_id=cg_type['id'],
|
||||||
|
consistencygroup_id=source_cg['id'])
|
||||||
|
source_vols = self.db.volume_get_all_by_group(
|
||||||
|
self.ctxt.elevated(), source_cg['id'])
|
||||||
|
|
||||||
|
# Create cgsnapshot
|
||||||
|
cgsnapshot, snapshots = self._create_cgsnapshot(source_cg['id'])
|
||||||
|
|
||||||
|
# Create cg from source cg
|
||||||
|
model_update, volumes_model_update = (
|
||||||
|
self.driver.create_consistencygroup_from_src(self.ctxt,
|
||||||
|
cg,
|
||||||
|
volumes,
|
||||||
|
None, None,
|
||||||
|
source_cg,
|
||||||
|
source_vols))
|
||||||
|
self.assertEqual('available',
|
||||||
|
model_update['status'],
|
||||||
|
"CG create from src created failed")
|
||||||
|
|
||||||
|
for each_vol in volumes_model_update:
|
||||||
|
self.assertEqual('available', each_vol['status'])
|
||||||
|
model_update = self.driver.delete_consistencygroup(self.ctxt,
|
||||||
|
cg,
|
||||||
|
[])
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for each_vol in model_update[1]:
|
||||||
|
self.assertEqual('deleted', each_vol['status'])
|
||||||
|
|
||||||
|
# Create cg from cg snapshot
|
||||||
|
model_update, volumes_model_update = (
|
||||||
|
self.driver.create_consistencygroup_from_src(self.ctxt,
|
||||||
|
cg,
|
||||||
|
volumes,
|
||||||
|
cgsnapshot,
|
||||||
|
snapshots,
|
||||||
|
None, None))
|
||||||
|
self.assertEqual('available',
|
||||||
|
model_update['status'],
|
||||||
|
"CG create from src created failed")
|
||||||
|
|
||||||
|
for each_vol in volumes:
|
||||||
|
self.assertEqual('available', each_vol['status'])
|
||||||
|
|
||||||
|
model_update = self.driver.delete_consistencygroup(self.ctxt,
|
||||||
|
cg, [])
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for each_vol in model_update[1]:
|
||||||
|
self.assertEqual('deleted', each_vol['status'])
|
||||||
|
|
||||||
|
model_update = self.driver.delete_consistencygroup(self.ctxt,
|
||||||
|
cgsnapshot,
|
||||||
|
[])
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for volume in model_update[1]:
|
||||||
|
self.assertEqual('deleted', volume['status'])
|
||||||
|
|
||||||
|
model_update = self.driver.delete_consistencygroup(self.ctxt,
|
||||||
|
source_cg,
|
||||||
|
[])
|
||||||
|
|
||||||
|
self.assertEqual('deleted', model_update[0]['status'])
|
||||||
|
for each_vol in model_update[1]:
|
||||||
|
self.assertEqual('deleted', each_vol['status'])
|
||||||
|
|
||||||
def _create_volume_type_qos(self, extra_specs, fake_qos):
|
def _create_volume_type_qos(self, extra_specs, fake_qos):
|
||||||
# Generate a QoS volume type for volume.
|
# Generate a QoS volume type for volume.
|
||||||
if extra_specs:
|
if extra_specs:
|
||||||
|
@ -1209,6 +1209,59 @@ class StorwizeHelpers(object):
|
|||||||
return mapping_ready
|
return mapping_ready
|
||||||
self._wait_for_a_condition(prepare_fc_consistgrp_success, timeout)
|
self._wait_for_a_condition(prepare_fc_consistgrp_success, timeout)
|
||||||
|
|
||||||
|
def create_cg_from_source(self, group, fc_consistgrp,
|
||||||
|
sources, targets, state,
|
||||||
|
config, timeout):
|
||||||
|
"""Create consistence group from source"""
|
||||||
|
LOG.debug('Enter: create_cg_from_source: cg %(cg)s'
|
||||||
|
' source %(source)s, target %(target)s',
|
||||||
|
{'cg': fc_consistgrp, 'source': sources, 'target': targets})
|
||||||
|
model_update = {'status': 'available'}
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
try:
|
||||||
|
for source, target in zip(sources, targets):
|
||||||
|
opts = self.get_vdisk_params(config, state,
|
||||||
|
source['volume_type_id'])
|
||||||
|
self.create_flashcopy_to_consistgrp(source['name'],
|
||||||
|
target['name'],
|
||||||
|
fc_consistgrp,
|
||||||
|
config, opts,
|
||||||
|
True)
|
||||||
|
self.prepare_fc_consistgrp(fc_consistgrp, timeout)
|
||||||
|
self.start_fc_consistgrp(fc_consistgrp)
|
||||||
|
self.delete_fc_consistgrp(fc_consistgrp)
|
||||||
|
volumes_model_update = self._get_volume_model_updates(
|
||||||
|
ctxt, targets, group['id'], model_update['status'])
|
||||||
|
except exception.VolumeBackendAPIException as err:
|
||||||
|
model_update['status'] = 'error'
|
||||||
|
volumes_model_update = self._get_volume_model_updates(
|
||||||
|
ctxt, targets, group['id'], model_update['status'])
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
# Release cg
|
||||||
|
self.delete_fc_consistgrp(fc_consistgrp)
|
||||||
|
LOG.error(_LE("Failed to create CG from CGsnapshot. "
|
||||||
|
"Exception: %s"), err)
|
||||||
|
return model_update, volumes_model_update
|
||||||
|
|
||||||
|
LOG.debug('Leave: create_cg_from_source.')
|
||||||
|
return model_update, volumes_model_update
|
||||||
|
|
||||||
|
def _get_volume_model_updates(self, ctxt, volumes, cgId,
|
||||||
|
status='available'):
|
||||||
|
"""Update the volume model's status and return it."""
|
||||||
|
volume_model_updates = []
|
||||||
|
LOG.info(_LI(
|
||||||
|
"Updating status for CG: %(id)s."),
|
||||||
|
{'id': cgId})
|
||||||
|
if volumes:
|
||||||
|
for volume in volumes:
|
||||||
|
volume_model_updates.append({'id': volume['id'],
|
||||||
|
'status': status})
|
||||||
|
else:
|
||||||
|
LOG.info(_LI("No volume found for CG: %(cg)s."),
|
||||||
|
{'cg': cgId})
|
||||||
|
return volume_model_updates
|
||||||
|
|
||||||
def run_flashcopy(self, source, target, timeout, copy_rate,
|
def run_flashcopy(self, source, target, timeout, copy_rate,
|
||||||
full_copy=True):
|
full_copy=True):
|
||||||
"""Create a FlashCopy mapping from the source to the target."""
|
"""Create a FlashCopy mapping from the source to the target."""
|
||||||
@ -2298,6 +2351,56 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
|||||||
{'vol': volume['name'], 'exception': err})
|
{'vol': volume['name'], 'exception': err})
|
||||||
return model_update, volumes
|
return model_update, volumes
|
||||||
|
|
||||||
|
def update_consistencygroup(self, ctxt, group, add_volumes,
|
||||||
|
remove_volumes):
|
||||||
|
"""Adds or removes volume(s) to/from an existing consistency group."""
|
||||||
|
|
||||||
|
LOG.debug("Updating consistency group.")
|
||||||
|
return None, None, None
|
||||||
|
|
||||||
|
def create_consistencygroup_from_src(self, context, group, volumes,
|
||||||
|
cgsnapshot=None, snapshots=None,
|
||||||
|
source_cg=None, source_vols=None):
|
||||||
|
"""Creates a consistencygroup from source.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group: the dictionary of the consistency group to be created.
|
||||||
|
:param volumes: a list of volume dictionaries in the group.
|
||||||
|
:param cgsnapshot: the dictionary of the cgsnapshot as source.
|
||||||
|
:param snapshots: a list of snapshot dictionaries in the cgsnapshot.
|
||||||
|
:param source_cg: the dictionary of a consistency group as source.
|
||||||
|
:param source_vols: a list of volume dictionaries in the source_cg.
|
||||||
|
:return model_update, volumes_model_update
|
||||||
|
"""
|
||||||
|
LOG.debug('Enter: create_consistencygroup_from_src.')
|
||||||
|
if cgsnapshot and snapshots:
|
||||||
|
cg_name = 'cg-' + cgsnapshot.id
|
||||||
|
sources = snapshots
|
||||||
|
|
||||||
|
elif source_cg and source_vols:
|
||||||
|
cg_name = 'cg-' + source_cg.id
|
||||||
|
sources = source_vols
|
||||||
|
|
||||||
|
else:
|
||||||
|
error_msg = _("create_consistencygroup_from_src must be "
|
||||||
|
"creating from a CG snapshot, or a source CG.")
|
||||||
|
raise exception.InvalidInput(reason=error_msg)
|
||||||
|
|
||||||
|
LOG.debug('create_consistencygroup_from_src: cg_name %(cg_name)s'
|
||||||
|
' %(sources)s', {'cg_name': cg_name, 'sources': sources})
|
||||||
|
self._helpers.create_fc_consistgrp(cg_name)
|
||||||
|
timeout = self.configuration.storwize_svc_flashcopy_timeout
|
||||||
|
model_update, snapshots_model = (
|
||||||
|
self._helpers.create_cg_from_source(group,
|
||||||
|
cg_name,
|
||||||
|
sources,
|
||||||
|
volumes,
|
||||||
|
self._state,
|
||||||
|
self.configuration,
|
||||||
|
timeout))
|
||||||
|
LOG.debug("Leave: create_consistencygroup_from_src.")
|
||||||
|
return model_update, snapshots_model
|
||||||
|
|
||||||
def create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
|
def create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
|
||||||
"""Creates a cgsnapshot."""
|
"""Creates a cgsnapshot."""
|
||||||
# Use cgsnapshot id as cg name
|
# Use cgsnapshot id as cg name
|
||||||
|
Loading…
x
Reference in New Issue
Block a user