Make RBD imagebackend flatten method idempotent
If glance and nova are both configured with RBD backend, but glance does not return location information from the API, nova will fail to clone the image from glance pool and will download it from the API. In this case, image will be already flat, and subsequent flatten call will fail. This commit makes flatten call idempotent, so that it ignores already flat images by catching ImageUnacceptable when requesting parent info from ceph. Closes-Bug: 1860990 Change-Id: Ia6c184c31a980e4728b7309b2afaec4d9f494ac3
This commit is contained in:
parent
80539a5e84
commit
65825ebfbd
|
@ -1582,11 +1582,28 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
||||||
["server1:1899", "server2:1920", "[::1]:1930"]),
|
["server1:1899", "server2:1920", "[::1]:1930"]),
|
||||||
model)
|
model)
|
||||||
|
|
||||||
|
@mock.patch.object(rbd_utils.RBDDriver, 'parent_info')
|
||||||
@mock.patch.object(rbd_utils.RBDDriver, 'flatten')
|
@mock.patch.object(rbd_utils.RBDDriver, 'flatten')
|
||||||
def test_flatten(self, mock_flatten):
|
def test_flatten(self, mock_flatten, mock_parent_info):
|
||||||
image = self.image_class(self.INSTANCE, self.NAME)
|
image = self.image_class(self.INSTANCE, self.NAME)
|
||||||
image.flatten()
|
image.flatten()
|
||||||
mock_flatten.assert_called_once_with(image.rbd_name, pool=self.POOL)
|
mock_flatten.assert_called_once_with(image.rbd_name, pool=self.POOL)
|
||||||
|
mock_parent_info.assert_called_once_with(
|
||||||
|
image.rbd_name, pool=self.POOL)
|
||||||
|
|
||||||
|
@mock.patch.object(imagebackend, 'LOG')
|
||||||
|
@mock.patch.object(rbd_utils.RBDDriver, 'parent_info')
|
||||||
|
@mock.patch.object(rbd_utils.RBDDriver, 'flatten')
|
||||||
|
def test_flatten_already_flat(
|
||||||
|
self, mock_flatten, mock_parent_info, mock_log):
|
||||||
|
mock_parent_info.side_effect = exception.ImageUnacceptable(
|
||||||
|
image_id=1, reason='foo')
|
||||||
|
image = self.image_class(self.INSTANCE, self.NAME)
|
||||||
|
image.flatten()
|
||||||
|
mock_log.debug.assert_called_once()
|
||||||
|
mock_flatten.assert_not_called()
|
||||||
|
mock_parent_info.assert_called_once_with(
|
||||||
|
image.rbd_name, pool=self.POOL)
|
||||||
|
|
||||||
def test_import_file(self):
|
def test_import_file(self):
|
||||||
image = self.image_class(self.INSTANCE, self.NAME)
|
image = self.image_class(self.INSTANCE, self.NAME)
|
||||||
|
|
|
@ -980,7 +980,17 @@ class Rbd(Image):
|
||||||
reason=reason)
|
reason=reason)
|
||||||
|
|
||||||
def flatten(self):
|
def flatten(self):
|
||||||
self.driver.flatten(self.rbd_name, pool=self.driver.pool)
|
# NOTE(vdrok): only flatten images if they are not already flattened,
|
||||||
|
# meaning that parent info is present
|
||||||
|
try:
|
||||||
|
self.driver.parent_info(self.rbd_name, pool=self.driver.pool)
|
||||||
|
except exception.ImageUnacceptable:
|
||||||
|
LOG.debug(
|
||||||
|
"Image %(img)s from pool %(pool)s has no parent info, "
|
||||||
|
"consider it already flat", {
|
||||||
|
'img': self.rbd_name, 'pool': self.driver.pool})
|
||||||
|
else:
|
||||||
|
self.driver.flatten(self.rbd_name, pool=self.driver.pool)
|
||||||
|
|
||||||
def get_model(self, connection):
|
def get_model(self, connection):
|
||||||
secret = None
|
secret = None
|
||||||
|
|
Loading…
Reference in New Issue