cg = testutils.create_consistencygroup(self.ctxt, **kwargs)
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):
cg_snapshot = testutils.create_cgsnapshot(self.ctxt,
consistencygroup_id= cg_id,
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):
ctxt = testutils.get_test_admin_context()
type_ref = volume_types.create(ctxt, 'testtype', opts)
for volume in model_update[1]:
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):
# Generate a QoS volume type for volume.
if extra_specs:
return mapping_ready
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,
full_copy=True):
"""Create a FlashCopy mapping from the source to the target."""
{'vol': volume['name'], 'exception': err})
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):
"""Creates a cgsnapshot."""
# Use cgsnapshot id as cg name