From: Xiaoqin Li Date: Sun, 20 Dec 2015 13:27:35 +0000 (-0800) Subject: Updates consistency group for ibm svc driver X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=c69b3d47d272b2e5bb6f1d3bb1cdca38faa53411;p=openstack-build%2Fcinder-build.git Updates consistency group for ibm svc driver The changes are: 1. ability to modify a consistecy group (update_consistencygroup) 2. ability to create a consistency group from a cgsnapshot or from another consistency group (create_consistencygroup_from_src) DocImpact Change-Id: Ibdf60ca50d6ee2d25ed51b8f0adbb64ff2a3d17c Implements: bp ibm-storwize-cg-updates --- diff --git a/cinder/tests/unit/test_storwize_svc.py b/cinder/tests/unit/test_storwize_svc.py index 57516203f..ff0ab6e81 100644 --- a/cinder/tests/unit/test_storwize_svc.py +++ b/cinder/tests/unit/test_storwize_svc.py @@ -2646,6 +2646,15 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): 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, @@ -2669,6 +2678,22 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): 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) @@ -3808,6 +3833,170 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): 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: diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py index f8a654234..f7ab07d82 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -1209,6 +1209,59 @@ class StorwizeHelpers(object): 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.""" @@ -2298,6 +2351,56 @@ class StorwizeSVCCommonDriver(san.SanDriver, {'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