summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorey Bryant <corey.bryant@canonical.com>2020-10-22 10:55:33 -0400
committerCorey Bryant <corey.bryant@canonical.com>2021-02-12 19:36:14 +0000
commit0a3851af306095ea89f6006fb0caa155e8013597 (patch)
tree149e1b14a348d37879de0f8ff57fd3de5c098a84
parent1b24dd6f45372a180f80a7b13dbddbad4299a073 (diff)
downloadcinder-0a3851af306095ea89f6006fb0caa155e8013597.tar.gz
RBD: Retry delete if VolumeIsBusy in _copy_image_to_volume
Cinder can fail to create an image-based volume if RBD mirroring is enabled. With the journaling-based approach to RBD mirroring, ceph will still create a snapshot as a result of volume creation. The volume create in _create_from_image_download() results in a snapshot getting created, resulting in a race where delete_volume() gets a VolumeIsBusy exception. Change-Id: Ib80e04512ec34a390e9e17af2f3544e18cad8598 Closes-Bug: #1900775 (cherry picked from commit 6231d26667508e34eb0a985f1f7ced1dbe623e1a) (cherry picked from commit e1ed30838c3d72e70e3e06d5e7bc6f18d6bc4aad) (cherry picked from commit 4f40f059f81ac27c92e4238f78ba649b69b09dd0)
-rw-r--r--cinder/tests/unit/volume/drivers/test_rbd.py23
-rw-r--r--cinder/volume/drivers/rbd.py8
2 files changed, 27 insertions, 4 deletions
diff --git a/cinder/tests/unit/volume/drivers/test_rbd.py b/cinder/tests/unit/volume/drivers/test_rbd.py
index e1ba497b2..b918c3b93 100644
--- a/cinder/tests/unit/volume/drivers/test_rbd.py
+++ b/cinder/tests/unit/volume/drivers/test_rbd.py
@@ -1308,17 +1308,29 @@ class RBDTestCase(test.TestCase):
self.driver._is_cloneable(location, {'disk_format': f}))
self.assertTrue(mock_get_fsid.called)
- def _copy_image(self):
+ def _copy_image(self, volume_busy=False):
with mock.patch.object(tempfile, 'NamedTemporaryFile'):
with mock.patch.object(os.path, 'exists') as mock_exists:
mock_exists.return_value = True
with mock.patch.object(image_utils, 'fetch_to_raw'):
- with mock.patch.object(self.driver, 'delete_volume'):
+ with mock.patch.object(self.driver, 'delete_volume') \
+ as mock_dv:
with mock.patch.object(self.driver, '_resize'):
mock_image_service = mock.MagicMock()
args = [None, self.volume_a,
mock_image_service, None]
- self.driver.copy_image_to_volume(*args)
+ if volume_busy:
+ mock_dv.side_effect = (
+ exception.VolumeIsBusy("doh"))
+ self.assertRaises(
+ exception.VolumeIsBusy,
+ self.driver.copy_image_to_volume,
+ *args)
+ self.assertEqual(
+ self.cfg.rados_connection_retries,
+ mock_dv.call_count)
+ else:
+ self.driver.copy_image_to_volume(*args)
@mock.patch('cinder.volume.drivers.rbd.fileutils.delete_if_exists')
@mock.patch('cinder.volume.volume_utils.check_encryption_provider',
@@ -1368,6 +1380,11 @@ class RBDTestCase(test.TestCase):
self.cfg.image_conversion_dir = '/var/run/cinder/tmp'
self._copy_image_encrypted()
+ @common_mocks
+ def test_copy_image_busy_volume(self):
+ self.cfg.image_conversion_dir = '/var/run/cinder/tmp'
+ self._copy_image(volume_busy=True)
+
@ddt.data(True, False)
@common_mocks
@mock.patch('cinder.volume.drivers.rbd.RBDDriver._get_usage_info')
diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py
index a3a48607e..ccb72f92b 100644
--- a/cinder/volume/drivers/rbd.py
+++ b/cinder/volume/drivers/rbd.py
@@ -1571,7 +1571,13 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
if encrypted:
self._encrypt_image(context, volume, tmp_dir, tmp.name)
- self.delete_volume(volume)
+ @utils.retry(exception.VolumeIsBusy,
+ self.configuration.rados_connection_interval,
+ self.configuration.rados_connection_retries)
+ def _delete_volume(volume):
+ self.delete_volume(volume)
+
+ _delete_volume(volume)
chunk_size = self.configuration.rbd_store_chunk_size * units.Mi
order = int(math.log(chunk_size, 2))