Merge "[RBD] Clone v2: Image is unusable if deletion fails"

This commit is contained in:
Zuul 2021-12-22 20:04:28 +00:00 committed by Gerrit Code Review
commit 63d6f8341a
4 changed files with 59 additions and 0 deletions

View File

@ -434,6 +434,14 @@ class Store(driver.Store):
'snapshot': DEFAULT_SNAPNAME,
}, self.conf)
def _snapshot_has_external_reference(self, image, snapshot_name):
"""Returns True if snapshot has external reference else False.
"""
image.set_snap(snapshot_name)
has_references = bool(image.list_children())
image.set_snap(None)
return has_references
def _delete_image(self, target_pool, image_name,
snapshot_name=None, context=None):
"""
@ -453,6 +461,14 @@ class Store(driver.Store):
if snapshot_name is not None:
with rbd.Image(ioctx, image_name) as image:
try:
# NOTE(abhishekk): Check whether snapshot
# has any external references
if self._snapshot_has_external_reference(
image, snapshot_name):
raise rbd.ImageBusy(
"Image snapshot has external "
"references.")
self._unprotect_snapshot(image, snapshot_name)
image.remove_snap(snapshot_name)
except rbd.ImageNotFound as exc:

View File

@ -113,6 +113,12 @@ class MockRBD(object):
def remove_snap(self, *args, **kwargs):
pass
def set_snap(self, *args, **kwargs):
pass
def list_children(self, *args, **kwargs):
pass
def protect_snap(self, *args, **kwargs):
pass
@ -417,6 +423,15 @@ class TestMultiStore(base.MultiStoreBaseTest,
self.called_commands_expected = ['unprotect_snap']
def test_delete_image_snap_has_external_references(self):
with mock.patch.object(MockRBD.Image, 'list_children') as mocked:
mocked.return_value = True
self.assertRaises(exceptions.InUseByStore,
self.store._delete_image,
'fake_pool', self.location.image,
snapshot_name='snap')
def test_delete_image_w_snap_exc_image_has_snap(self):
def _fake_remove(*args, **kwargs):
self.called_commands_actual.append('remove')

View File

@ -114,6 +114,12 @@ class MockRBD(object):
def remove_snap(self, *args, **kwargs):
pass
def set_snap(self, *args, **kwargs):
pass
def list_children(self, *args, **kwargs):
pass
def protect_snap(self, *args, **kwargs):
pass
@ -623,6 +629,15 @@ class TestStore(base.StoreBaseTest,
self.called_commands_expected = ['unprotect_snap']
def test_delete_image_snap_has_external_references(self):
with mock.patch.object(MockRBD.Image, 'list_children') as mocked:
mocked.return_value = True
self.assertRaises(exceptions.InUseByStore,
self.store._delete_image,
'fake_pool', self.location.image,
snapshot_name='snap')
def test_delete_image_w_snap_exc_image_has_snap(self):
def _fake_remove(*args, **kwargs):
self.called_commands_actual.append('remove')

View File

@ -0,0 +1,13 @@
---
fixes:
- |
* Bug 1954883_: [RBD] Image is unusable if deletion fails
.. _1954883: https://code.launchpad.net/bugs/1954883
upgrade:
- |
Deployments which are using Ceph V2 clone feature (i.e. RBD backend for
glance_store as well as cinder driver is RBD or nova is using RBD driver)
and minimum ceph client version is greater than 'luminous' need to grant
glance osd read access to the cinder and nova RBD pool.