]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Don't return Exception when volume is detached
authorWalter A. Boring IV <walter.boring@hp.com>
Wed, 12 Aug 2015 21:00:54 +0000 (14:00 -0700)
committerWalter A. Boring IV (hemna) <walter.boring@hp.com>
Thu, 13 Aug 2015 16:36:41 +0000 (16:36 +0000)
This patch changes the way we handle volume detach
attempts when the attachment_id is already detached
and/or when the volume has no attachments.  We now
handle this the same way we do with deleting volumes
that don't exist.  We return success.

This patch also takes care to make sure we safely reset
the volume status to what it should be depending on if
there are other attachments.  If the attachment_id is
passed in and that attachment is detached, but there are
other attachments, we want to make sure that the volume is
left in an in-use state, not available.

Change-Id: I11b7c45bb6570ce11e13e487cf1136ca2551036b
Closes-Bug: #1484194
Related-Bug: #1476806

cinder/db/sqlalchemy/api.py
cinder/tests/unit/test_volume.py
cinder/volume/manager.py

index da6f14940939b429ed612fe81879957b34ebaa43..fd1bfb54f2ee508fdced7551faeadaec8e9bb4e8 100644 (file)
@@ -1216,8 +1216,12 @@ def volume_detached(context, volume_id, attachment_id):
     """
     session = get_session()
     with session.begin():
-        attachment = volume_attachment_get(context, attachment_id,
-                                           session=session)
+        attachment = None
+        try:
+            attachment = volume_attachment_get(context, attachment_id,
+                                               session=session)
+        except exception.VolumeAttachmentNotFound:
+            pass
 
         # If this is already detached, attachment will be None
         if attachment:
index 4a66f1528e2fa4477dd04098be0009c7fb58a7c1..761b385a1c9407da5b2cc4e9c1f55071c23dcd92 100644 (file)
@@ -2117,26 +2117,35 @@ class VolumeTestCase(BaseVolumeTestCase):
     def test_detach_invalid_attachment_id(self):
         """Make sure if the attachment id isn't found we raise."""
         attachment_id = "notfoundid"
-        volume_id = "abc123"
-        fake_volume = {'id': volume_id,
-                       'status': 'available'}
-        with mock.patch.object(db, 'volume_get') as mock_volume_get:
-            mock_volume_get.return_value = fake_volume
-            self.assertRaises(exception.VolumeAttachmentNotFound,
-                              self.volume.detach_volume,
-                              self.context,
-                              volume_id,
-                              attachment_id)
+        volume = tests_utils.create_volume(self.context,
+                                           admin_metadata={'readonly': 'True'},
+                                           multiattach=False,
+                                           **self.volume_params)
+        self.volume.detach_volume(self.context, volume['id'],
+                                  attachment_id)
+        volume = db.volume_get(self.context, volume['id'])
+        self.assertEqual('available', volume['status'])
+
+        instance_uuid = '12345678-1234-5678-1234-567812345678'
+        attached_host = 'fake_host'
+        mountpoint = '/dev/fake'
+        tests_utils.attach_volume(self.context, volume['id'],
+                                  instance_uuid, attached_host,
+                                  mountpoint)
+        self.volume.detach_volume(self.context, volume['id'],
+                                  attachment_id)
+        volume = db.volume_get(self.context, volume['id'])
+        self.assertEqual('in-use', volume['status'])
 
     def test_detach_no_attachments(self):
+        self.volume_params['status'] = 'detaching'
         volume = tests_utils.create_volume(self.context,
                                            admin_metadata={'readonly': 'True'},
                                            multiattach=False,
                                            **self.volume_params)
-        self.assertRaises(exception.InvalidVolume,
-                          self.volume.detach_volume,
-                          self.context,
-                          volume['id'])
+        self.volume.detach_volume(self.context, volume['id'])
+        volume = db.volume_get(self.context, volume['id'])
+        self.assertEqual('available', volume['status'])
 
     def test_run_attach_detach_volume_for_instance_no_attachment_id(self):
         """Make sure volume can be attached and detached from instance."""
index 534df2c5819ca77e4de92f4b9413d41f6e61c88d..00c40264fd17e6b16ed8e1a5eb89fbde59d8bacb 100644 (file)
@@ -863,9 +863,13 @@ class VolumeManager(manager.SchedulerDependentManager):
                 attachment = self.db.volume_attachment_get(context,
                                                            attachment_id)
             except exception.VolumeAttachmentNotFound:
-                LOG.error(_LE("Find attachment in detach_volume failed."),
-                          resource=volume)
-                raise
+                LOG.info(_LI("Volume detach called, but volume not attached."),
+                         resource=volume)
+                # We need to make sure the volume status is set to the correct
+                # status.  It could be in detaching status now, and we don't
+                # want to leave it there.
+                self.db.volume_detached(context, volume_id, attachment_id)
+                return
         else:
             # We can try and degrade gracefully here by trying to detach
             # a volume without the attachment_id here if the volume only has
@@ -883,10 +887,13 @@ class VolumeManager(manager.SchedulerDependentManager):
                 attachment = attachments[0]
             else:
                 # there aren't any attachments for this volume.
-                msg = _("Detach volume failed, because there are currently no "
-                        "active attachments.")
-                LOG.error(msg, resource=volume)
-                raise exception.InvalidVolume(reason=msg)
+                # so set the status to available and move on.
+                LOG.info(_LI("Volume detach called, but volume not attached."),
+                         resource=volume)
+                self.db.volume_update(context, volume_id,
+                                      {'status': 'available',
+                                       'attach_status': 'detached'})
+                return
 
         self._notify_about_volume_usage(context, volume, "detach.start")
         try: