]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Updates consistency group for ibm svc driver
authorXiaoqin Li <lixqin@cn.ibm.com>
Sun, 20 Dec 2015 13:27:35 +0000 (05:27 -0800)
committerXiaoqin Li <lixqin@cn.ibm.com>
Tue, 29 Dec 2015 02:25:20 +0000 (18:25 -0800)
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

cinder/tests/unit/test_storwize_svc.py
cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py

index 57516203ffb52a88309828a1a05edc7900196c0c..ff0ab6e81f5e0eacef98cc1083b9e170d8f1b1ff 100644 (file)
@@ -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:
index f8a65423410f48f008307eb0304cbd7c5e3a0657..f7ab07d82c15b838bb357b5750ae124a3f5ac49e 100644 (file)
@@ -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