]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
XtremIO driver fix array snapshot problem
authorShay Halsband <shay.halsband@emc.com>
Mon, 22 Jun 2015 06:33:11 +0000 (09:33 +0300)
committerShay Halsband <shay.halsband@emc.com>
Mon, 29 Jun 2015 15:51:36 +0000 (18:51 +0300)
Use create snapshot v2, to resolve a potential bug
when 2 such requests are processed in the same second.

Change-Id: If2801cb737e8a3d1847c68c9e19265c2123e6687
Closes-Bug: #1467386

cinder/tests/unit/test_emc_xtremio.py
cinder/volume/drivers/emc/xtremio.py

index c0e4b50a02fea6243ff2104bf6a18947a1dd2f05..97a2a787c272c9cbdd0e13e6f010f3357c11720f 100644 (file)
@@ -173,6 +173,22 @@ def xms_bad_request(object_type='volumes', request_typ='GET', data=None,
         raise exception.VolumeBackendAPIException('Failed to create ig')
 
 
+def xms_failed_rename_snapshot_request(object_type='volumes',
+                                       request_typ='GET', data=None,
+                                       name=None, idx=None):
+    if request_typ == 'POST':
+        xms_data['volumes'][27] = {}
+        return {
+            "links": [
+                {
+                    "href": "https://host/api/json/v2/types/snapshots/27",
+                    "rel": "self"}]}
+    elif request_typ == 'PUT':
+        raise exception.VolumeBackendAPIException(msg='Failed to delete')
+    elif request_typ == 'DELETE':
+        del xms_data['volumes'][27]
+
+
 class D(dict):
     def update(self, *args, **kwargs):
         self.__dict__.update(*args, **kwargs)
@@ -267,9 +283,17 @@ class EMCXIODriverISCSITestCase(test.TestCase):
         clean_xms_data()
         self.driver.create_volume(self.data.test_volume)
         self.driver.create_snapshot(self.data.test_snapshot)
+        self.assertEqual(self.data.test_snapshot['id'],
+                         xms_data['volumes'][3]['name'])
         self.driver.delete_snapshot(self.data.test_snapshot)
         self.driver.delete_volume(self.data.test_volume)
 
+    def test_failed_rename_snapshot(self, req):
+        req.side_effect = xms_failed_rename_snapshot_request
+        self.driver.create_snapshot(self.data.test_snapshot)
+        self.assertIn(27, xms_data['volumes'])
+        clean_xms_data()
+
     def test_volume_from_snapshot(self, req):
         req.side_effect = xms_request
         clean_xms_data()
index d4ec195e5ebcf85795e39f48be2a1a1978ed503f..38efc48cff8de0ea73ebc0ead24d71ef7b696d18 100644 (file)
@@ -152,6 +152,17 @@ class XtremIOClient(object):
     def get_cluster(self):
         return self.req('clusters', idx=1)['content']
 
+    def create_snapshot(self, src, dest, ro=False):
+        """Create a snapshot of a volume on the array.
+
+        XtreamIO array snapshots are also volumes.
+
+        :src: name of the source volume to be cloned
+        :dest: name for the new snapshot
+        :ro: new snapshot type ro/regular. only applicable to Client4
+        """
+        raise NotImplementedError()
+
 
 class XtremIOClient3(XtremIOClient):
     def __init__(self, configuration, cluster_id):
@@ -195,6 +206,11 @@ class XtremIOClient3(XtremIOClient):
 
         return self._portals
 
+    def create_snapshot(self, src, dest, ro=False):
+        data = {'snap-vol-name': dest, 'ancestor-vol-id': src}
+
+        self.req('snapshots', 'POST', data)
+
 
 class XtremIOClient4(XtremIOClient):
     def __init__(self, configuration, cluster_id):
@@ -234,6 +250,25 @@ class XtremIOClient4(XtremIOClient):
 
         return self.req('clusters', name=self.cluster_id)['content']
 
+    def create_snapshot(self, src, dest, ro=False):
+        data = {'snapshot-set-name': dest, 'snap-suffix': dest,
+                'volume-list': [src],
+                'snapshot-type': 'readonly' if ro else 'regular'}
+
+        res = self.req('snapshots', 'POST', data, ver='v2')
+        typ, idx = res['links'][0]['href'].split('/')[-2:]
+
+        # rename the snapshot
+        data = {'name': dest}
+        try:
+            self.req(typ, 'PUT', data, idx=int(idx))
+        except exception.VolumeBackendAPIException:
+            # reverting
+            msg = _LE('Failed to rename the created snapshot, reverting.')
+            LOG.error(msg)
+            self.req(typ, 'DELETE', idx=int(idx))
+            raise
+
 
 class XtremIOVolumeDriver(san.SanDriver):
     """Executes commands relating to Volumes."""
@@ -292,17 +327,11 @@ class XtremIOVolumeDriver(san.SanDriver):
 
     def create_volume_from_snapshot(self, volume, snapshot):
         """Creates a volume from a snapshot."""
-        data = {'snap-vol-name': volume['id'],
-                'ancestor-vol-id': snapshot.id}
-
-        self.client.req('snapshots', 'POST', data)
+        self.client.create_snapshot(snapshot.id, volume['id'])
 
     def create_cloned_volume(self, volume, src_vref):
         """Creates a clone of the specified volume."""
-        data = {'snap-vol-name': volume['id'],
-                'ancestor-vol-id': src_vref['id']}
-
-        self.client.req('snapshots', 'POST', data)
+        self.client.create_snapshot(src_vref['id'], volume['id'])
 
     def delete_volume(self, volume):
         """Deletes a volume."""
@@ -313,10 +342,7 @@ class XtremIOVolumeDriver(san.SanDriver):
 
     def create_snapshot(self, snapshot):
         """Creates a snapshot."""
-        data = {'snap-vol-name': snapshot.id,
-                'ancestor-vol-id': snapshot.volume_id}
-
-        self.client.req('snapshots', 'POST', data)
+        self.client.create_snapshot(snapshot.volume_id, snapshot.id, True)
 
     def delete_snapshot(self, snapshot):
         """Deletes a snapshot."""