diff --git a/glance/store/rbd.py b/glance/store/rbd.py index 75f0270397..2974a71fee 100644 --- a/glance/store/rbd.py +++ b/glance/store/rbd.py @@ -144,9 +144,10 @@ class ImageIterator(object): Reads data from an RBD image, one chunk at a time. """ - def __init__(self, name, store): + def __init__(self, pool, name, snapshot, store): + self.pool = pool or store.pool self.name = name - self.pool = store.pool + self.snapshot = snapshot self.user = store.user self.conf_file = store.conf_file self.chunk_size = store.chunk_size @@ -156,7 +157,8 @@ class ImageIterator(object): with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn: with conn.open_ioctx(self.pool) as ioctx: - with rbd.Image(ioctx, self.name) as image: + with rbd.Image(ioctx, self.name, + snapshot=self.snapshot) as image: img_info = image.stat() size = img_info['size'] bytes_left = size @@ -211,7 +213,8 @@ class Store(glance.store.base.Store): :raises `glance.exception.NotFound` if image does not exist """ loc = location.store_location - return (ImageIterator(loc.image, self), self.get_size(location)) + return (ImageIterator(loc.pool, loc.image, loc.snapshot, self), + self.get_size(location)) def get_size(self, location): """ @@ -223,9 +226,12 @@ class Store(glance.store.base.Store): :raises `glance.exception.NotFound` if image does not exist """ loc = location.store_location + # if there is a pool specific in the location, use it; otherwise + # we fall back to the default pool specified in the config + target_pool = loc.pool or self.pool with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn: - with conn.open_ioctx(self.pool) as ioctx: + with conn.open_ioctx(target_pool) as ioctx: try: with rbd.Image(ioctx, loc.image, snapshot=loc.snapshot) as image: @@ -260,7 +266,7 @@ class Store(glance.store.base.Store): librbd.create(ioctx, image_name, size, order, old_format=True) return StoreLocation({'image': image_name}) - def _delete_image(self, image_name, snapshot_name=None): + def _delete_image(self, target_pool, image_name, snapshot_name=None): """ Delete RBD image and snapshot. @@ -271,7 +277,7 @@ class Store(glance.store.base.Store): InUseByStore if image is in use or snapshot unprotect failed """ with rados.Rados(conffile=self.conf_file, rados_id=self.user) as conn: - with conn.open_ioctx(self.pool) as ioctx: + with conn.open_ioctx(target_pool) as ioctx: try: # First remove snapshot. if snapshot_name is not None: @@ -387,4 +393,5 @@ class Store(glance.store.base.Store): InUseByStore if image is in use or snapshot unprotect failed """ loc = location.store_location - self._delete_image(loc.image, loc.snapshot) + target_pool = loc.pool or self.pool + self._delete_image(target_pool, loc.image, loc.snapshot) diff --git a/glance/tests/unit/test_rbd_store.py b/glance/tests/unit/test_rbd_store.py index f21cba5c32..828fee906a 100644 --- a/glance/tests/unit/test_rbd_store.py +++ b/glance/tests/unit/test_rbd_store.py @@ -37,7 +37,8 @@ class TestStore(base.StoreClearingUnitTest): self.store.chunk_size = 2 self.called_commands_actual = [] self.called_commands_expected = [] - self.store_specs = {'image': 'fake_image', + self.store_specs = {'pool': 'fake_pool', + 'image': 'fake_image', 'snapshot': 'fake_snapshot'} self.location = StoreLocation(self.store_specs) # Provide enough data to get more than one chunk iteration. @@ -99,7 +100,7 @@ class TestStore(base.StoreClearingUnitTest): self.called_commands_actual.append('remove') self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove) - self.store._delete_image(self.location) + self.store._delete_image('fake_pool', self.location) self.called_commands_expected = ['remove'] def test__delete_image_w_snap(self): @@ -115,7 +116,8 @@ class TestStore(base.StoreClearingUnitTest): self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove) self.stubs.Set(mock_rbd.Image, 'unprotect_snap', _fake_unprotect_snap) self.stubs.Set(mock_rbd.Image, 'remove_snap', _fake_remove_snap) - self.store._delete_image(self.location, snapshot_name='snap') + self.store._delete_image('fake_pool', self.location, + snapshot_name='snap') self.called_commands_expected = ['unprotect_snap', 'remove_snap', 'remove'] @@ -127,7 +129,7 @@ class TestStore(base.StoreClearingUnitTest): self.stubs.Set(mock_rbd.Image, 'unprotect_snap', _fake_unprotect_snap) self.assertRaises(exception.NotFound, self.store._delete_image, - self.location, snapshot_name='snap') + 'fake_pool', self.location, snapshot_name='snap') self.called_commands_expected = ['unprotect_snap'] @@ -138,7 +140,7 @@ class TestStore(base.StoreClearingUnitTest): self.stubs.Set(mock_rbd.RBD, 'remove', _fake_remove) self.assertRaises(exception.NotFound, self.store._delete_image, - self.location, snapshot_name='snap') + 'fake_pool', self.location, snapshot_name='snap') self.called_commands_expected = ['remove']