]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Fix HP LeftHand migration with snapshots
authorJim Branen <james.branen@hp.com>
Mon, 3 Mar 2014 18:53:17 +0000 (10:53 -0800)
committerJim Branen <james.branen@hp.com>
Mon, 3 Mar 2014 19:20:35 +0000 (11:20 -0800)
Check for snapshots associated with volumes during assisted
migration, and fail if a snapshot is found.

When a volume is cloned on the HP LeftHand array, a snapshot
is created and the cloned volume is created from the snapshot.
The snapshot remains associated with the newly created volume.
Therefore, backend assisted migration should check for volumes
with snapshots and not use native APIs to migrate any volume
that has a snapshot.

Change-Id: I29fc3dbd1f24c01968e7c3d043cdf6b9d1b89ee9
Closes-Bug:#1285829

cinder/tests/test_hplefthand.py
cinder/volume/drivers/san/hp/hp_lefthand_rest_proxy.py

index 3fc7b96d19edad789ad0b6852407487f1e6ba240..36428c564df6e31a0bba95bbdf3ae899f4027610 100644 (file)
@@ -1230,6 +1230,8 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
 
         mock_client.getVolumeByName.return_value = {'id': self.volume_id,
                                                     'iscsiSessions': None}
+        mock_client.getVolume.return_value = {'snapshots': {
+            'resource': None}}
 
         location = (self.driver.proxy.DRIVER_LOCATION % {
             'cluster': 'New_CloudCluster',
@@ -1247,6 +1249,9 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
         expected = self.driver_startup_call_stack + [
             mock.call.getClusterByName('New_CloudCluster'),
             mock.call.getVolumeByName('fakevolume'),
+            mock.call.getVolume(
+                1,
+                'fields=snapshots,snapshots[resource[members[name]]]'),
             mock.call.modifyVolume(1, {'clusterName': 'New_CloudCluster'})]
 
         mock_client.assert_has_calls(expected)
@@ -1254,3 +1259,44 @@ class TestHPLeftHandRESTISCSIDriver(HPLeftHandBaseDriver, test.TestCase):
         self.assertEqual(
             len(expected),
             len(mock_client.method_calls))
+
+    def test_migrate_with_Snapshots(self):
+        # setup drive with default configuration
+        # and return the mock HTTP LeftHand client
+        mock_client = self.setup_driver()
+        mock_client.getClusterByName.return_value = {
+            "virtualIPAddresses": [{
+                "ipV4Address": "10.10.10.111",
+                "ipV4NetMask": "255.255.240.0"}]}
+
+        mock_client.getVolumeByName.return_value = {
+            'id': self.volume_id,
+            'iscsiSessions': None}
+        mock_client.getVolume.return_value = {'snapshots': {
+            'resource': 'snapfoo'}}
+
+        location = (self.driver.proxy.DRIVER_LOCATION % {
+            'cluster': 'New_CloudCluster',
+            'vip': '10.10.10.111'})
+
+        host = {
+            'host': self.serverName,
+            'capabilities': {'location_info': location}}
+        (migrated, update) = self.driver.migrate_volume(
+            None,
+            self.volume,
+            host)
+        self.assertFalse(migrated)
+
+        expected = self.driver_startup_call_stack + [
+            mock.call.getClusterByName('New_CloudCluster'),
+            mock.call.getVolumeByName('fakevolume'),
+            mock.call.getVolume(
+                1,
+                'fields=snapshots,snapshots[resource[members[name]]]')]
+
+        mock_client.assert_has_calls(expected)
+        # and nothing else
+        self.assertEqual(
+            len(expected),
+            len(mock_client.method_calls))
index 30468a99b45fc4ffa24f17b90ff013b0c1b02d53..80c08ac8488eecdf219f71dd73ee8c2cdfe3a052 100644 (file)
@@ -85,9 +85,11 @@ class HPLeftHandRESTProxy(ISCSIDriver):
         1.0.0 - Initial REST iSCSI proxy
         1.0.1 - Added support for retype
         1.0.2 - Added support for volume migrate
+        1.0.3 - Fixed bug #1285829, HP LeftHand backend assisted migration
+                should check for snapshots
     """
 
-    VERSION = "1.0.2"
+    VERSION = "1.0.3"
 
     device_stats = {}
 
@@ -467,38 +469,49 @@ class HPLeftHandRESTProxy(ISCSIDriver):
             virtual_ips = cluster_info['virtualIPAddresses']
 
             if driver != self.__class__.__name__:
-                LOG.info(_("Can not provide backend assisted migration for "
-                           "volume:%s because volume is from a different "
+                LOG.info(_("Cannot provide backend assisted migration for "
+                           "volume: %s because volume is from a different "
                            "backend.") % volume['name'])
                 return false_ret
             if vip != virtual_ips[0]['ipV4Address']:
-                LOG.info(_("Can not provide backend assisted migration for "
-                           "volume:%s because cluster exists in different "
+                LOG.info(_("Cannot provide backend assisted migration for "
+                           "volume: %s because cluster exists in different "
                            "management group.") % volume['name'])
                 return false_ret
 
         except hpexceptions.HTTPNotFound:
-            LOG.info(_("Can not provide backend assisted migration for "
-                       "volume:%s because cluster exists in different "
+            LOG.info(_("Cannot provide backend assisted migration for "
+                       "volume: %s because cluster exists in different "
                        "management group.") % volume['name'])
             return false_ret
 
         try:
-            options = {'clusterName': cluster}
             volume_info = self.client.getVolumeByName(volume['name'])
             LOG.debug(_('Volume info: %s') % volume_info)
 
             # can't migrate if server is attached
             if volume_info['iscsiSessions'] is not None:
-                LOG.info(_("Can not provide backend assisted migration "
-                           "for volume:%s because the volume has been "
+                LOG.info(_("Cannot provide backend assisted migration "
+                           "for volume: %s because the volume has been "
                            "exported.") % volume['name'])
                 return false_ret
 
+            # can't migrate if volume has snapshots
+            snap_info = self.client.getVolume(
+                volume_info['id'],
+                'fields=snapshots,snapshots[resource[members[name]]]')
+            LOG.debug(_('Snapshot info: %s') % snap_info)
+            if snap_info['snapshots']['resource'] is not None:
+                LOG.info(_("Cannot provide backend assisted migration "
+                           "for volume: %s because the volume has "
+                           "snapshots.") % volume['name'])
+                return false_ret
+
+            options = {'clusterName': cluster}
             self.client.modifyVolume(volume_info['id'], options)
         except hpexceptions.HTTPNotFound:
-            LOG.info(_("Can not provide backend assisted migration for "
-                       "volume:%s because volume does not exist in this "
+            LOG.info(_("Cannot provide backend assisted migration for "
+                       "volume: %s because volume does not exist in this "
                        "management group.") % volume['name'])
             return false_ret
         except hpexceptions.HTTPServerError as ex: