diff --git a/glance_store/_drivers/rbd.py b/glance_store/_drivers/rbd.py index 74e929b5..195083da 100644 --- a/glance_store/_drivers/rbd.py +++ b/glance_store/_drivers/rbd.py @@ -514,6 +514,21 @@ class Store(driver.Store): if loc.snapshot: image.create_snap(loc.snapshot) image.protect_snap(loc.snapshot) + except rbd.NoSpace: + log_msg = (_LE("Failed to store image %(img_name)s " + "insufficient space available") % + {'img_name': image_name}) + LOG.error(log_msg) + + # Delete image if one was created + try: + target_pool = loc.pool or self.pool + self._delete_image(target_pool, loc.image, + loc.snapshot) + except exceptions.NotFound: + pass + + raise exceptions.StorageFull(message=log_msg) except Exception as exc: log_msg = (_LE("Failed to store image %(img_name)s " "Store Exception %(store_exc)s") % diff --git a/glance_store/tests/unit/test_multistore_rbd.py b/glance_store/tests/unit/test_multistore_rbd.py index 492c64b1..363ed9f7 100644 --- a/glance_store/tests/unit/test_multistore_rbd.py +++ b/glance_store/tests/unit/test_multistore_rbd.py @@ -89,6 +89,9 @@ class MockRBD(object): class InvalidArgument(Exception): pass + class NoSpace(Exception): + pass + class Image(object): def __init__(self, *args, **kwargs): diff --git a/glance_store/tests/unit/test_rbd_store.py b/glance_store/tests/unit/test_rbd_store.py index 6863bcea..5af6bace 100644 --- a/glance_store/tests/unit/test_rbd_store.py +++ b/glance_store/tests/unit/test_rbd_store.py @@ -88,6 +88,9 @@ class MockRBD(object): class InvalidArgument(Exception): pass + class NoSpace(Exception): + pass + class Image(object): def __init__(self, *args, **kwargs): @@ -214,7 +217,6 @@ class TestStore(base.StoreBaseTest, def _fake_enter(*args, **kwargs): raise exceptions.NotFound(image="fake_image_id") - create.side_effect = _fake_create_image delete.side_effect = _fake_delete_image enter.side_effect = _fake_enter @@ -226,6 +228,33 @@ class TestStore(base.StoreBaseTest, self.called_commands_expected = ['create', 'delete'] + @mock.patch.object(MockRBD.Image, 'resize') + @mock.patch.object(rbd_store.Store, '_create_image') + @mock.patch.object(rbd_store.Store, '_delete_image') + def test_add_w_rbd_no_space_exception(self, delete, create, resize): + def _fake_create_image(*args, **kwargs): + self.called_commands_actual.append('create') + return self.location + + def _fake_delete_image(target_pool, image_name, snapshot_name=None): + self.assertEqual(self.location.pool, target_pool) + self.assertEqual(self.location.image, image_name) + self.assertEqual(self.location.snapshot, snapshot_name) + self.called_commands_actual.append('delete') + + def _fake_resize(*args, **kwargs): + raise MockRBD.NoSpace() + create.side_effect = _fake_create_image + delete.side_effect = _fake_delete_image + resize.side_effect = _fake_resize + + self.assertRaises(exceptions.StorageFull, + self.store.add, + 'fake_image_id', self.data_iter, 0, + self.hash_algo) + + self.called_commands_expected = ['create', 'delete'] + def test_add_duplicate_image(self): def _fake_create_image(*args, **kwargs):