]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Clear volumes stuck in 'downloading'
authorDermot Tynan <tynan@hp.com>
Thu, 25 Apr 2013 09:46:34 +0000 (10:46 +0100)
committerDermot Tynan <tynan@hp.com>
Thu, 25 Apr 2013 11:26:18 +0000 (12:26 +0100)
If the CinderVolume service is restarted while an image-copy is
happening, the volume gets left in a 'downloading' state and
cannot be used or deleted. This fix adds code to init_host to
look for volumes (on this host) in such a state, and move them
to an error state. It also calls clear_download in the driver
in case the driver needs to perform an action, such as
detaching the volume.

Fixes Bug #1172645

Change-Id: Ia5dab9ebf997f573c0b4e57d983f5996af81ede5

cinder/tests/test_volume.py
cinder/volume/driver.py
cinder/volume/manager.py

index a22224aceb7936c0791fc98d5520767edae25d40..523ebcf661a12ba21490d9c48da6fb853d072e18 100644 (file)
@@ -77,7 +77,7 @@ class VolumeTestCase(test.TestCase):
 
     @staticmethod
     def _create_volume(size=0, snapshot_id=None, image_id=None,
-                       metadata=None):
+                       metadata=None, status="creating"):
         """Create a volume object."""
         vol = {}
         vol['size'] = size
@@ -86,13 +86,22 @@ class VolumeTestCase(test.TestCase):
         vol['user_id'] = 'fake'
         vol['project_id'] = 'fake'
         vol['availability_zone'] = FLAGS.storage_availability_zone
-        vol['status'] = "creating"
+        vol['status'] = status
         vol['attach_status'] = "detached"
         vol['host'] = FLAGS.host
         if metadata is not None:
             vol['metadata'] = metadata
         return db.volume_create(context.get_admin_context(), vol)
 
+    def test_init_host_clears_downloads(self):
+        """Test that init_host will unwedge a volume stuck in downloading."""
+        volume = self._create_volume(status='downloading')
+        volume_id = volume['id']
+        self.volume.init_host()
+        volume = db.volume_get(context.get_admin_context(), volume_id)
+        self.assertEquals(volume['status'], "error")
+        self.volume.delete_volume(self.context, volume_id)
+
     def test_create_delete_volume(self):
         """Test volume can be created and deleted."""
         # Need to stub out reserve, commit, and rollback
index 7615932e1a239e8bae6b5a7a3dae3199a52ab0f4..03f18a2b7640e687d61cd4b27b937f7f988aeec1 100644 (file)
@@ -191,6 +191,10 @@ class VolumeDriver(object):
         """Restore an existing backup to a new or existing volume."""
         raise NotImplementedError()
 
+    def clear_download(self, context, volume):
+        """Clean up after an interrupted image copy."""
+        pass
+
 
 class ISCSIDriver(VolumeDriver):
     """Executes commands relating to ISCSI volumes.
index 5e2ee28ddc801f28d50a4a4fb0ba3497fc98cc30..5ae2b28f1085be898efbc01aa3df147ad894955c 100644 (file)
@@ -147,6 +147,11 @@ class VolumeManager(manager.SchedulerDependentManager):
         for volume in volumes:
             if volume['status'] in ['available', 'in-use']:
                 self.driver.ensure_export(ctxt, volume)
+            elif volume['status'] == 'downloading':
+                LOG.info(_("volume %s stuck in a downloading state"),
+                         volume['id'])
+                self.driver.clear_download(ctxt, volume)
+                self.db.volume_update(ctxt, volume['id'], {'status': 'error'})
             else:
                 LOG.info(_("volume %s: skipping export"), volume['name'])