]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fixed issue with mismatched config in VMAX driver
authorXing Yang <xing.yang@emc.com>
Wed, 15 Apr 2015 19:33:59 +0000 (15:33 -0400)
committerXing Yang <xing.yang@emc.com>
Fri, 24 Apr 2015 03:05:21 +0000 (23:05 -0400)
When the source and target volumes have different meta device
configurations, clone volume will fail. This patch fixed the
problem.

Closes-Bug: #1442376
Change-Id: If2f2c085596b0045d7af6762bddeb4cd59158a57

cinder/tests/unit/test_emc_vmax.py
cinder/volume/drivers/emc/emc_vmax_common.py
cinder/volume/drivers/emc/emc_vmax_fc.py
cinder/volume/drivers/emc/emc_vmax_iscsi.py

index d335053b5443810ee1a6ee9a8c5643d57603f939..e7d0c6d48ed7c5f645994cad2ea224e7750499b1 100644 (file)
@@ -393,7 +393,7 @@ class EMCVMAXCommonData(object):
                           'project_id':
                           'project', 'id': '2',
                           'provider_location':
-                              six.text_type(provider_location),
+                          six.text_type(provider_location),
                           'display_description': 'snapshot source volume'}
 
     test_CG = {'name': 'myCG1',
@@ -2661,6 +2661,51 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
         self.driver.delete_cgsnapshot(
             self.data.test_ctxt, self.data.test_CG_snapshot)
 
+    # Bug https://bugs.launchpad.net/cinder/+bug/1442376
+    @mock.patch.object(
+        emc_vmax_common.EMCVMAXCommon,
+        '_get_pool_and_storage_system',
+        return_value=(None, EMCVMAXCommonData.storage_system))
+    @mock.patch.object(
+        emc_vmax_utils.EMCVMAXUtils,
+        'get_meta_members_capacity_in_bit',
+        return_value=[1234567, 7654321])
+    @mock.patch.object(
+        emc_vmax_utils.EMCVMAXUtils,
+        'get_volume_meta_head',
+        return_value=[EMCVMAXCommonData.test_volume])
+    @mock.patch.object(
+        FakeDB,
+        'volume_get',
+        return_value=EMCVMAXCommonData.test_source_volume)
+    @mock.patch.object(
+        volume_types,
+        'get_volume_type_extra_specs',
+        return_value={'volume_backend_name': 'ISCSINoFAST'})
+    def test_create_clone_with_different_meta_sizes(
+            self, mock_volume_type, mock_volume,
+            mock_meta, mock_size, mock_pool):
+        self.data.test_volume['volume_name'] = "vmax-1234567"
+        common = self.driver.common
+        volumeDict = {'classname': u'Symm_StorageVolume',
+                      'keybindings': EMCVMAXCommonData.keybindings}
+        volume = {'size': 0L}
+        common.provision.create_volume_from_pool = (
+            mock.Mock(return_value=(volumeDict, volume['size'])))
+        common.provision.get_volume_dict_from_job = (
+            mock.Mock(return_value=volumeDict))
+
+        common._create_composite_volume = (
+            mock.Mock(return_value=(0L,
+                                    volumeDict,
+                                    EMCVMAXCommonData.storage_system)))
+
+        self.driver.create_cloned_volume(self.data.test_volume,
+                                         EMCVMAXCommonData.test_source_volume)
+        extraSpecs = self.driver.common._initial_setup(self.data.test_volume)
+        common._create_composite_volume.assert_called_with(
+            volume, "TargetBaseVol", 1234567, extraSpecs, 1)
+
     def _cleanup(self):
         if self.config_file_path:
             bExists = os.path.exists(self.config_file_path)
index 6cc4e34cccd7af42bde1fc8ec36cd2b1f7b9d5f8..dd17b26457ccff3cb0cf8c2f9794bc2fab50dbc6 100644 (file)
@@ -2671,41 +2671,47 @@ class EMCVMAXCommon(object):
         return memberInstanceNames
 
     def _create_composite_volume(
-            self, volume, volumeName, volumeSize, extraSpecs):
+            self, volume, volumeName, volumeSize, extraSpecs,
+            memberCount=None):
         """Create a composite volume (V2).
 
         :param volume: the volume object
         :param volumeName: the name of the volume
         :param volumeSize: the size of the volume
         :param extraSpecs: extra specifications
+        :param memberCount: the number of meta members in a composite volume
         :returns: int -- return code
         :returns: dict -- volumeDict
         :returns: string -- storageSystemName
         :raises: VolumeBackendAPIException
         """
-        memberCount, errorDesc = self.utils.determine_member_count(
-            volume['size'], extraSpecs[MEMBERCOUNT],
-            extraSpecs[COMPOSITETYPE])
-        if errorDesc is not None:
-            exceptionMessage = (_("The striped meta count of %(memberCount)s "
-                                  "is too small for volume: %(volumeName)s "
-                                  "with size %(volumeSize)s.")
-                                % {'memberCount': memberCount,
-                                   'volumeName': volumeName,
-                                   'volumeSize': volume['size']})
-            LOG.error(exceptionMessage)
-            raise exception.VolumeBackendAPIException(data=exceptionMessage)
+        if not memberCount:
+            memberCount, errorDesc = self.utils.determine_member_count(
+                volume['size'], extraSpecs[MEMBERCOUNT],
+                extraSpecs[COMPOSITETYPE])
+            if errorDesc is not None:
+                exceptionMessage = (_("The striped meta count of "
+                                      "%(memberCount)s is too small for "
+                                      "volume: %(volumeName)s, "
+                                      "with size %(volumeSize)s.")
+                                    % {'memberCount': memberCount,
+                                       'volumeName': volumeName,
+                                       'volumeSize': volume['size']})
+                LOG.error(exceptionMessage)
+                raise exception.VolumeBackendAPIException(
+                    data=exceptionMessage)
 
         poolInstanceName, storageSystemName = (
             self._get_pool_and_storage_system(extraSpecs))
 
         LOG.debug("Create Volume: %(volume)s  Pool: %(pool)s "
                   "Storage System: %(storageSystem)s "
-                  "Size: %(size)lu.",
+                  "Size: %(size)lu  MemberCount: %(memberCount)s.",
                   {'volume': volumeName,
                    'pool': poolInstanceName,
                    'storageSystem': storageSystemName,
-                   'size': volumeSize})
+                   'size': volumeSize,
+                   'memberCount': memberCount})
 
         elementCompositionService = (
             self.utils.find_element_composition_service(self.conn,
@@ -3483,7 +3489,7 @@ class EMCVMAXCommon(object):
                     _rc, baseVolumeDict, storageSystemName = (
                         self._create_composite_volume(
                             volume, baseVolumeName, volumeSizeInbits,
-                            extraSpecs))
+                            extraSpecs, 1))
                     baseTargetVolumeInstance = self.utils.find_volume_instance(
                         self.conn, baseVolumeDict, baseVolumeName)
                     LOG.debug("Base target volume %(targetVol)s created. "
index d02aafc4b7075ef0be5a8195dcbafcef95015a6c..c56e58752539a10474cb2e2aaa7357de476e3a79 100644 (file)
@@ -34,9 +34,10 @@ class EMCVMAXFCDriver(driver.FibreChannelDriver):
                 performance enhancement.
         2.0.0 - Add driver requirement functions
         2.1.0 - Add consistency group functions
+        2.1.1 - Fixed issue with mismatched config (bug #1442376)
     """
 
-    VERSION = "2.1.0"
+    VERSION = "2.1.1"
 
     def __init__(self, *args, **kwargs):
 
index eda1de19e8f8df19945c8af00a9090be38ce9d44..f2d49a7c65e07aa4e6ed452b64ed3065da8c44bb 100644 (file)
@@ -42,9 +42,10 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
                 performance enhancement.
         2.0.0 - Add driver requirement functions
         2.1.0 - Add consistency group functions
+        2.1.1 - Fixed issue with mismatched config (bug #1442376)
     """
 
-    VERSION = "2.1.0"
+    VERSION = "2.1.1"
 
     def __init__(self, *args, **kwargs):