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 commit6231d26667
) (cherry picked from commite1ed30838c
)
This commit is contained in:
parent
d00b1de8a9
commit
4f40f059f8
|
@ -1311,17 +1311,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',
|
||||
|
@ -1371,6 +1383,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')
|
||||
|
|
|
@ -1601,7 +1601,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))
|
||||
|
|
Loading…
Reference in New Issue