summaryrefslogtreecommitdiff
path: root/glance_store/tests
diff options
context:
space:
mode:
authorAbhishek Kekane <akekane@redhat.com>2021-11-26 14:58:23 +0000
committerAbhishek Kekane <akekane@redhat.com>2021-12-21 17:11:45 +0000
commit3d221ec529862d43ab303644e74ee9ad6ce8cd40 (patch)
tree33de47fe153d8af3512b4fce40d94248c70c1f43 /glance_store/tests
parent6295d2eead3e492959f5861ded6a6c3e3f8cc9d0 (diff)
downloadglance_store-3d221ec529862d43ab303644e74ee9ad6ce8cd40.tar.gz
[RBD] Clone v2: Image is unusable if deletion fails
Recently cinder has utilized Ceph clone v2 support for its RBD backend, since then if you attempt to delete an image from glance that has a dependent volume, all future uses of that image will fail in error state. Despite the fact that image itself is still inside of Ceph/Glance. This issue is reproducible if you are using ceph client version greater than 'luminous' To resolve this issue glance RBD driver now checks whether snapshot of original image has any external references before deleting/removing it's snapshot and returns 409 Conflict response if it has any. NOTE: To check this dependency glance osd needs 'read' access to cinder and nova side RBD pool. Closes-Bug: #1954883 Depends-on: https://review.opendev.org/c/openstack/devstack-plugin-ceph/+/819476 Change-Id: If30b7bd7acac148b6f89ce46abbe128c678c90e7
Diffstat (limited to 'glance_store/tests')
-rw-r--r--glance_store/tests/unit/test_multistore_rbd.py15
-rw-r--r--glance_store/tests/unit/test_rbd_store.py15
2 files changed, 30 insertions, 0 deletions
diff --git a/glance_store/tests/unit/test_multistore_rbd.py b/glance_store/tests/unit/test_multistore_rbd.py
index 384fca0..822c1b5 100644
--- a/glance_store/tests/unit/test_multistore_rbd.py
+++ b/glance_store/tests/unit/test_multistore_rbd.py
@@ -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')
diff --git a/glance_store/tests/unit/test_rbd_store.py b/glance_store/tests/unit/test_rbd_store.py
index 2d1cae6..cbd34ac 100644
--- a/glance_store/tests/unit/test_rbd_store.py
+++ b/glance_store/tests/unit/test_rbd_store.py
@@ -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')