diff --git a/nova/tests/unit/virt/libvirt/test_imagebackend.py b/nova/tests/unit/virt/libvirt/test_imagebackend.py index a76c4f60bd3c..013c73a06b2a 100644 --- a/nova/tests/unit/virt/libvirt/test_imagebackend.py +++ b/nova/tests/unit/virt/libvirt/test_imagebackend.py @@ -1558,11 +1558,28 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase): ["server1:1899", "server2:1920"]), model) + @mock.patch.object(rbd_utils.RBDDriver, 'parent_info') @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.flatten() 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): image = self.image_class(self.INSTANCE, self.NAME) diff --git a/nova/virt/libvirt/imagebackend.py b/nova/virt/libvirt/imagebackend.py index d185b7e1eb2a..5a7877b77801 100644 --- a/nova/virt/libvirt/imagebackend.py +++ b/nova/virt/libvirt/imagebackend.py @@ -969,7 +969,17 @@ class Rbd(Image): reason=reason) def flatten(self): - self.driver.flatten(self.rbd_name, pool=self.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.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.pool}) + else: + self.driver.flatten(self.rbd_name, pool=self.pool) def get_model(self, connection): secret = None