Merge "rbd: Fix snapshot delete when the source volume doesn't exist"
This commit is contained in:
commit
24f43918ea
@ -84,6 +84,10 @@ class MockImageHasSnapshotsException(MockException):
|
|||||||
"""Used as mock for rbd.ImageHasSnapshots."""
|
"""Used as mock for rbd.ImageHasSnapshots."""
|
||||||
|
|
||||||
|
|
||||||
|
class MockInvalidArgument(MockException):
|
||||||
|
"""Used as mock for rbd.InvalidArgument."""
|
||||||
|
|
||||||
|
|
||||||
class KeyObject(object):
|
class KeyObject(object):
|
||||||
def get_encoded(arg):
|
def get_encoded(arg):
|
||||||
return "asdf".encode('utf-8')
|
return "asdf".encode('utf-8')
|
||||||
@ -113,7 +117,7 @@ def common_mocks(f):
|
|||||||
inst.mock_rbd.ImageNotFound = MockImageNotFoundException
|
inst.mock_rbd.ImageNotFound = MockImageNotFoundException
|
||||||
inst.mock_rbd.ImageExists = MockImageExistsException
|
inst.mock_rbd.ImageExists = MockImageExistsException
|
||||||
inst.mock_rbd.ImageHasSnapshots = MockImageHasSnapshotsException
|
inst.mock_rbd.ImageHasSnapshots = MockImageHasSnapshotsException
|
||||||
inst.mock_rbd.InvalidArgument = MockImageNotFoundException
|
inst.mock_rbd.InvalidArgument = MockInvalidArgument
|
||||||
inst.mock_rbd.PermissionError = MockPermissionError
|
inst.mock_rbd.PermissionError = MockPermissionError
|
||||||
|
|
||||||
inst.driver.rbd = inst.mock_rbd
|
inst.driver.rbd = inst.mock_rbd
|
||||||
@ -1195,7 +1199,7 @@ class RBDTestCase(test.TestCase):
|
|||||||
|
|
||||||
self.driver.delete_snapshot(self.snapshot)
|
self.driver.delete_snapshot(self.snapshot)
|
||||||
|
|
||||||
proxy.remove_snap.assert_called_with(self.snapshot.name)
|
proxy.remove_snap.assert_not_called()
|
||||||
proxy.unprotect_snap.assert_called_with(self.snapshot.name)
|
proxy.unprotect_snap.assert_called_with(self.snapshot.name)
|
||||||
|
|
||||||
@common_mocks
|
@common_mocks
|
||||||
@ -1254,6 +1258,18 @@ class RBDTestCase(test.TestCase):
|
|||||||
self.assertTrue(proxy.unprotect_snap.called)
|
self.assertTrue(proxy.unprotect_snap.called)
|
||||||
self.assertFalse(proxy.remove_snap.called)
|
self.assertFalse(proxy.remove_snap.called)
|
||||||
|
|
||||||
|
@common_mocks
|
||||||
|
@mock.patch('cinder.objects.Volume.get_by_id')
|
||||||
|
def test_delete_snapshot_volume_not_found(self, volume_get_by_id):
|
||||||
|
volume_get_by_id.return_value = self.volume_a
|
||||||
|
proxy = self.mock_proxy.return_value
|
||||||
|
proxy.__enter__.side_effect = self.mock_rbd.ImageNotFound
|
||||||
|
|
||||||
|
self.driver.delete_snapshot(self.snapshot)
|
||||||
|
|
||||||
|
proxy.remove_snap.assert_not_called()
|
||||||
|
proxy.unprotect_snap.assert_not_called()
|
||||||
|
|
||||||
@common_mocks
|
@common_mocks
|
||||||
def test_snapshot_revert_use_temp_snapshot(self):
|
def test_snapshot_revert_use_temp_snapshot(self):
|
||||||
self.assertFalse(self.driver.snapshot_revert_use_temp_snapshot())
|
self.assertFalse(self.driver.snapshot_revert_use_temp_snapshot())
|
||||||
|
@ -1455,34 +1455,38 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||||||
volume_name = snapshot.volume_name
|
volume_name = snapshot.volume_name
|
||||||
snap_name = snapshot.name
|
snap_name = snapshot.name
|
||||||
|
|
||||||
with RBDVolumeProxy(self, volume_name) as volume:
|
try:
|
||||||
try:
|
with RBDVolumeProxy(self, volume_name) as volume:
|
||||||
volume.unprotect_snap(snap_name)
|
try:
|
||||||
except self.rbd.InvalidArgument:
|
volume.unprotect_snap(snap_name)
|
||||||
LOG.info(
|
except self.rbd.InvalidArgument:
|
||||||
"InvalidArgument: Unable to unprotect snapshot %s.",
|
LOG.info(
|
||||||
snap_name)
|
"InvalidArgument: Unable to unprotect snapshot %s.",
|
||||||
except self.rbd.ImageNotFound:
|
snap_name)
|
||||||
LOG.info(
|
except self.rbd.ImageNotFound:
|
||||||
"ImageNotFound: Unable to unprotect snapshot %s.",
|
LOG.info("Snapshot %s does not exist in backend.",
|
||||||
snap_name)
|
snap_name)
|
||||||
except self.rbd.ImageBusy:
|
return
|
||||||
children_list = self._get_children_info(volume, snap_name)
|
except self.rbd.ImageBusy:
|
||||||
|
children_list = self._get_children_info(volume, snap_name)
|
||||||
|
|
||||||
if children_list:
|
if children_list:
|
||||||
for (pool, image) in children_list:
|
for (pool, image) in children_list:
|
||||||
LOG.info('Image %(pool)s/%(image)s is dependent '
|
LOG.info('Image %(pool)s/%(image)s is dependent '
|
||||||
'on the snapshot %(snap)s.',
|
'on the snapshot %(snap)s.',
|
||||||
{'pool': pool,
|
{'pool': pool,
|
||||||
'image': image,
|
'image': image,
|
||||||
'snap': snap_name})
|
'snap': snap_name})
|
||||||
|
|
||||||
raise exception.SnapshotIsBusy(snapshot_name=snap_name)
|
raise exception.SnapshotIsBusy(snapshot_name=snap_name)
|
||||||
try:
|
|
||||||
volume.remove_snap(snap_name)
|
try:
|
||||||
except self.rbd.ImageNotFound:
|
volume.remove_snap(snap_name)
|
||||||
LOG.info("Snapshot %s does not exist in backend.",
|
except self.rbd.ImageNotFound:
|
||||||
snap_name)
|
LOG.info("Snapshot %s does not exist in backend.",
|
||||||
|
snap_name)
|
||||||
|
except self.rbd.ImageNotFound:
|
||||||
|
LOG.warning("Volume %s does not exist in backend.", volume_name)
|
||||||
|
|
||||||
def snapshot_revert_use_temp_snapshot(self) -> bool:
|
def snapshot_revert_use_temp_snapshot(self) -> bool:
|
||||||
"""Disable the use of a temporary snapshot on revert."""
|
"""Disable the use of a temporary snapshot on revert."""
|
||||||
|
7
releasenotes/notes/bug-1957073-0d1307a8637a62b7.yaml
Normal file
7
releasenotes/notes/bug-1957073-0d1307a8637a62b7.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
RBD Driver `bug #1957073
|
||||||
|
<https://bugs.launchpad.net/cinder/+bug/1957073>`_: Snapshot delete now
|
||||||
|
succeeds and skips updating the source volume image if the image
|
||||||
|
does not exist in the backend.
|
Loading…
Reference in New Issue
Block a user