Merge "Fix failure to boot instances with qcow2 format images"
This commit is contained in:
commit
2f26a22100
|
@ -232,6 +232,9 @@ Possible values:
|
|||
Related options:
|
||||
|
||||
* ``compute_driver``: Only the libvirt driver uses this option.
|
||||
* ``[libvirt]/images_type``: If images_type is rbd, setting this option
|
||||
to False is not allowed. See the bug
|
||||
https://bugs.launchpad.net/nova/+bug/1816686 for more details.
|
||||
"""),
|
||||
# NOTE(yamahata): ListOpt won't work because the command may include a comma.
|
||||
# For example:
|
||||
|
|
|
@ -856,6 +856,7 @@ Related options:
|
|||
* compute.use_cow_images
|
||||
* images_volume_group
|
||||
* [workarounds]/ensure_libvirt_rbd_instance_dir_cleanup
|
||||
* compute.force_raw_images
|
||||
"""),
|
||||
cfg.StrOpt('images_volume_group',
|
||||
help="""
|
||||
|
|
|
@ -187,6 +187,10 @@ class Invalid(NovaException):
|
|||
code = 400
|
||||
|
||||
|
||||
class InvalidConfiguration(Invalid):
|
||||
msg_fmt = _("Configuration is Invalid.")
|
||||
|
||||
|
||||
class InvalidBDM(Invalid):
|
||||
msg_fmt = _("Block Device Mapping is Invalid.")
|
||||
|
||||
|
|
|
@ -1411,12 +1411,44 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
mock_exists.assert_has_calls([mock.call(), mock.call()])
|
||||
fn.assert_called_once_with(target=self.TEMPLATE_PATH)
|
||||
|
||||
@mock.patch.object(images, 'qemu_img_info')
|
||||
@mock.patch.object(os.path, 'exists', return_value=False)
|
||||
def test__remove_non_raw_cache_image_not_exists(
|
||||
self, mock_exists, mock_qemu):
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image._remove_non_raw_cache_image(self.TEMPLATE_PATH)
|
||||
mock_qemu.assert_not_called()
|
||||
|
||||
@mock.patch.object(os, 'remove')
|
||||
@mock.patch.object(images, 'qemu_img_info',
|
||||
return_value=imageutils.QemuImgInfo())
|
||||
@mock.patch.object(os.path, 'exists', return_value=True)
|
||||
def test__remove_non_raw_cache_image_with_raw_cache(
|
||||
self, mock_exists, mock_qemu, mock_remove):
|
||||
mock_qemu.return_value.file_format = 'raw'
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image._remove_non_raw_cache_image(self.TEMPLATE_PATH)
|
||||
mock_remove.assert_not_called()
|
||||
|
||||
@mock.patch.object(os, 'remove')
|
||||
@mock.patch.object(images, 'qemu_img_info',
|
||||
return_value=imageutils.QemuImgInfo())
|
||||
@mock.patch.object(os.path, 'exists', return_value=True)
|
||||
def test__remove_non_raw_cache_image_with_qcow2_cache(
|
||||
self, mock_exists, mock_qemu, mock_remove):
|
||||
mock_qemu.return_value.file_format = 'qcow2'
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
image._remove_non_raw_cache_image(self.TEMPLATE_PATH)
|
||||
mock_remove.assert_called_once_with(self.TEMPLATE_PATH)
|
||||
|
||||
@mock.patch.object(images, 'qemu_img_info',
|
||||
return_value=imageutils.QemuImgInfo())
|
||||
@mock.patch.object(rbd_utils.RBDDriver, 'resize')
|
||||
@mock.patch.object(imagebackend.Rbd, 'verify_base_size')
|
||||
@mock.patch.object(imagebackend.Rbd, 'get_disk_size')
|
||||
@mock.patch.object(imagebackend.Rbd, 'exists')
|
||||
def test_create_image_resize(self, mock_exists, mock_get,
|
||||
mock_verify, mock_resize):
|
||||
mock_verify, mock_resize, mock_qemu):
|
||||
fn = mock.MagicMock()
|
||||
full_size = self.SIZE * 2
|
||||
|
||||
|
@ -1427,6 +1459,7 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
mock_exists.return_value = False
|
||||
mock_qemu.return_value.file_format = 'raw'
|
||||
mock_get.return_value = self.SIZE
|
||||
rbd_name = "%s_%s" % (self.INSTANCE['uuid'], self.NAME)
|
||||
cmd = ('rbd', 'import', '--pool', self.POOL, self.TEMPLATE_PATH,
|
||||
|
@ -1443,13 +1476,17 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
mock_verify.assert_called_once_with(self.TEMPLATE_PATH, full_size)
|
||||
fn.assert_called_once_with(target=self.TEMPLATE_PATH)
|
||||
|
||||
@mock.patch.object(images, 'qemu_img_info',
|
||||
return_value=imageutils.QemuImgInfo())
|
||||
@mock.patch.object(imagebackend.Rbd, 'get_disk_size')
|
||||
@mock.patch.object(imagebackend.Rbd, 'exists')
|
||||
def test_create_image_already_exists(self, mock_exists, mock_get):
|
||||
def test_create_image_already_exists(self, mock_exists, mock_get,
|
||||
mock_qemu):
|
||||
rbd_utils.rbd.RBD_FEATURE_LAYERING = 1
|
||||
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
mock_exists.return_value = True
|
||||
mock_qemu.return_value.file_format = 'raw'
|
||||
mock_get.return_value = self.SIZE
|
||||
rbd_name = "%s_%s" % (self.INSTANCE['uuid'], self.NAME)
|
||||
fn = mock.MagicMock()
|
||||
|
@ -1507,7 +1544,10 @@ class RbdTestCase(_ImageTestCase, test.NoDBTestCase):
|
|||
self.assertEqual(2361393152, image.get_disk_size(image.path))
|
||||
size_mock.assert_called_once_with(image.rbd_name)
|
||||
|
||||
def test_create_image_too_small(self):
|
||||
@mock.patch.object(images, 'qemu_img_info',
|
||||
return_value=imageutils.QemuImgInfo())
|
||||
def test_create_image_too_small(self, mock_qemu):
|
||||
mock_qemu.return_value.file_format = 'raw'
|
||||
image = self.image_class(self.INSTANCE, self.NAME)
|
||||
with mock.patch.object(image, 'driver') as driver_mock:
|
||||
driver_mock.exists.return_value = True
|
||||
|
|
|
@ -901,6 +901,21 @@ class LibvirtConnTestCase(_VirtDriverTestCase, test.TestCase):
|
|||
# stub out the unplug call to os-vif since we don't care about it.
|
||||
self.stub_out('os_vif.unplug', lambda a, kw: None)
|
||||
|
||||
def test_init_host_image_type_rbd_force_raw_images_true(self):
|
||||
CONF.set_override('images_type', 'rbd', group='libvirt')
|
||||
CONF.set_override('force_raw_images', True)
|
||||
self.connection.init_host('myhostname')
|
||||
|
||||
def test_init_host_image_type_non_rbd(self):
|
||||
CONF.set_override('images_type', 'default', group='libvirt')
|
||||
self.connection.init_host('myhostname')
|
||||
|
||||
def test_init_host_raise_invalid_configuration(self):
|
||||
CONF.set_override('images_type', 'rbd', group='libvirt')
|
||||
CONF.set_override('force_raw_images', False)
|
||||
self.assertRaises(exception.InvalidConfiguration,
|
||||
self.connection.init_host, 'myhostname')
|
||||
|
||||
def test_force_hard_reboot(self):
|
||||
self.flags(wait_soft_reboot_seconds=0, group='libvirt')
|
||||
self.test_reboot()
|
||||
|
|
|
@ -612,6 +612,18 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
"'live_migration_with_native_tls'.")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
# Some imagebackends are only able to import raw disk images,
|
||||
# and will fail if given any other format. See the bug
|
||||
# https://bugs.launchpad.net/nova/+bug/1816686 for more details.
|
||||
if CONF.libvirt.images_type in ('rbd',):
|
||||
if not CONF.force_raw_images:
|
||||
msg = _("'[DEFAULT]/force_raw_images = False' is not "
|
||||
"allowed with '[libvirt]/images_type = rbd'. "
|
||||
"Please check the two configs and if you really "
|
||||
"do want to use rbd as images_type, set "
|
||||
"force_raw_images to True.")
|
||||
raise exception.InvalidConfiguration(msg)
|
||||
|
||||
# TODO(sbauza): Remove this code once mediated devices are persisted
|
||||
# across reboots.
|
||||
if self._host.has_min_version(MIN_LIBVIRT_MDEV_SUPPORT):
|
||||
|
|
|
@ -914,9 +914,28 @@ class Rbd(Image):
|
|||
"""
|
||||
return self.driver.size(self.rbd_name)
|
||||
|
||||
@staticmethod
|
||||
def _remove_non_raw_cache_image(base):
|
||||
# NOTE(boxiang): If the cache image file exists, we will check
|
||||
# the format of it. Only raw format image is compatible for
|
||||
# RBD image backend. If format is not raw, we will remove it
|
||||
# at first. We limit force_raw_images to True this time. So
|
||||
# the format of new cache image must be raw.
|
||||
# We can remove this in 'U' version later.
|
||||
if not os.path.exists(base):
|
||||
return True
|
||||
image_format = images.qemu_img_info(base)
|
||||
if image_format.file_format != 'raw':
|
||||
try:
|
||||
os.remove(base)
|
||||
except OSError as e:
|
||||
LOG.warning("Ignoring failure to remove %(path)s: "
|
||||
"%(error)s", {'path': base, 'error': e})
|
||||
|
||||
def create_image(self, prepare_template, base, size, *args, **kwargs):
|
||||
|
||||
if not self.exists():
|
||||
self._remove_non_raw_cache_image(base)
|
||||
prepare_template(target=base, *args, **kwargs)
|
||||
|
||||
# prepare_template() may have cloned the image into a new rbd
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
upgrade:
|
||||
- |
|
||||
The libvirt driver's RBD imagebackend no longer supports setting
|
||||
force_raw_images to False. Setting force_raw_images = False and
|
||||
images_type = rbd in nova.conf will cause the nova compute service
|
||||
to refuse to start. To fix this, set force_raw_images = True. This
|
||||
change was required to fix the `bug 1816686`_.
|
||||
|
||||
Note that non-raw cache image files will be removed if you set
|
||||
force_raw_images = True and images_type = rbd now.
|
||||
|
||||
.. _bug 1816686: https://bugs.launchpad.net/nova/+bug/1816686
|
Loading…
Reference in New Issue