From 474e7bb3f356e7e7592a249dcf2053659fe8cf38 Mon Sep 17 00:00:00 2001 From: Sam Yaple Date: Tue, 20 Oct 2015 22:42:36 +0000 Subject: [PATCH] Fix attibute error when cloning raw images in Ceph A regression introduced in If03b166d3ecc3e7fa6b7f1a0c69f8ab1cc7b1972 causes a glance image with the type 'raw' in ceph to fail to CoW clone which prevents launching at all in this case. The original patch did not update imagebackend.py [1] to use the new nova.objects.ImageMeta object so the clone() function passes a normal dict to the is_cloneable() function. Additionally add another test to ensure that not passing disk_format will fail, but not result in an exception. It will simply mean that the function returns that it cannot take advantage of the CoW cloning ceph provides. [1] https://github.com/openstack/nova/blob/f2e2a5891d5f5ff9346e6dc8e4dd0e994485245c/nova/virt/libvirt/imagebackend.py#L824 Change-Id: I7ae107bfccab7ff66c09d96856722dd6e60fdd96 Closes-Bug: #1508230 (cherry picked from commit 835ff1bf73d36a311168283f8a4ef5bec03d5a7e) --- .../unit/virt/libvirt/storage/test_rbd.py | 19 ++++++++++++++----- nova/virt/libvirt/storage/rbd_utils.py | 4 ++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/storage/test_rbd.py b/nova/tests/unit/virt/libvirt/storage/test_rbd.py index 9e940876cc67..1ebc50abb88b 100644 --- a/nova/tests/unit/virt/libvirt/storage/test_rbd.py +++ b/nova/tests/unit/virt/libvirt/storage/test_rbd.py @@ -96,7 +96,7 @@ class RbdTestCase(test.NoDBTestCase): 'rbd://fsid/pool/image/', 'rbd://fsid/pool/image/snap/', 'rbd://///', ] - image_meta = objects.ImageMeta.from_dict({'disk_format': 'raw'}) + image_meta = {'disk_format': 'raw'} for loc in locations: self.assertRaises(exception.ImageUnacceptable, @@ -110,7 +110,7 @@ class RbdTestCase(test.NoDBTestCase): def test_cloneable(self, mock_rados, mock_rbd, mock_get_fsid): mock_get_fsid.return_value = 'abc' location = {'url': 'rbd://abc/pool/image/snap'} - image_meta = objects.ImageMeta.from_dict({'disk_format': 'raw'}) + image_meta = {'disk_format': 'raw'} self.assertTrue(self.driver.is_cloneable(location, image_meta)) self.assertTrue(mock_get_fsid.called) @@ -118,7 +118,7 @@ class RbdTestCase(test.NoDBTestCase): def test_uncloneable_different_fsid(self, mock_get_fsid): mock_get_fsid.return_value = 'abc' location = {'url': 'rbd://def/pool/image/snap'} - image_meta = objects.ImageMeta.from_dict({'disk_format': 'raw'}) + image_meta = {'disk_format': 'raw'} self.assertFalse( self.driver.is_cloneable(location, image_meta)) self.assertTrue(mock_get_fsid.called) @@ -133,7 +133,7 @@ class RbdTestCase(test.NoDBTestCase): location = {'url': 'rbd://abc/pool/image/snap'} mock_proxy.side_effect = mock_rbd.Error - image_meta = objects.ImageMeta.from_dict({'disk_format': 'raw'}) + image_meta = {'disk_format': 'raw'} self.assertFalse( self.driver.is_cloneable(location, image_meta)) @@ -147,11 +147,20 @@ class RbdTestCase(test.NoDBTestCase): location = {'url': 'rbd://abc/pool/image/snap'} formats = ['qcow2', 'vmdk', 'vdi'] for f in formats: - image_meta = objects.ImageMeta.from_dict({'disk_format': f}) + image_meta = {'disk_format': f} self.assertFalse( self.driver.is_cloneable(location, image_meta)) self.assertTrue(mock_get_fsid.called) + @mock.patch.object(rbd_utils.RBDDriver, '_get_fsid') + def test_uncloneable_missing_format(self, mock_get_fsid): + mock_get_fsid.return_value = 'abc' + location = {'url': 'rbd://abc/pool/image/snap'} + image_meta = {} + self.assertFalse( + self.driver.is_cloneable(location, image_meta)) + self.assertTrue(mock_get_fsid.called) + @mock.patch.object(utils, 'execute') def test_get_mon_addrs(self, mock_execute): mock_execute.return_value = (CEPH_MON_DUMP, '') diff --git a/nova/virt/libvirt/storage/rbd_utils.py b/nova/virt/libvirt/storage/rbd_utils.py index ca5c71dab743..8564181100c7 100644 --- a/nova/virt/libvirt/storage/rbd_utils.py +++ b/nova/virt/libvirt/storage/rbd_utils.py @@ -190,10 +190,10 @@ class RBDDriver(object): LOG.debug(reason) return False - if image_meta.disk_format != 'raw': + if image_meta.get('disk_format') != 'raw': reason = ("rbd image clone requires image format to be " "'raw' but image {0} is '{1}'").format( - url, image_meta.disk_format) + url, image_meta.get('disk_format')) LOG.debug(reason) return False