Support qemu >= 2.10
Qemu 2.10 added the requirement of a --force-share flag to qemu-img info when reading information about a disk that is in use by a guest. We do this a lot in Nova for operations like gathering information before live migration. Up until this point all qemu/libvirt version matching has been solely inside the libvirt driver, however all the image manip code was moved out to nova.virt.images. We need the version of QEMU available there. This does it by initializing that version on driver init host. The net effect is also that broken libvirt connections are figured out earlier, as there is an active probe for this value. Co-Authored-By: Sean Dague <sean@dague.net> Change-Id: Iae2962bb86100f03fd3ad9aac3767da876291e74 Closes-Bug: #1718295
This commit is contained in:
parent
b926a1d4df
commit
807579755c
@ -61,6 +61,7 @@ from nova.tests.unit import conf_fixture
|
||||
from nova.tests.unit import policy_fixture
|
||||
from nova.tests import uuidsentinel as uuids
|
||||
from nova import utils
|
||||
from nova.virt import images
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -303,6 +304,8 @@ class TestCase(testtools.TestCase):
|
||||
|
||||
# Reset the traits sync flag
|
||||
objects.resource_provider._TRAITS_SYNCED = False
|
||||
# Reset the global QEMU version flag.
|
||||
images.QEMU_VERSION = None
|
||||
|
||||
mox_fixture = self.useFixture(moxstubout.MoxStubout())
|
||||
self.mox = mox_fixture.mox
|
||||
|
@ -986,6 +986,23 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
break
|
||||
self.assertFalse(version_arg_found)
|
||||
|
||||
# NOTE(sdague): python2.7 and python3.5 have different behaviors
|
||||
# when it comes to comparing against the sentinel, so
|
||||
# has_min_version is needed to pass python3.5.
|
||||
@mock.patch.object(nova.virt.libvirt.host.Host, "has_min_version",
|
||||
return_value=True)
|
||||
@mock.patch.object(fakelibvirt.Connection, 'getVersion',
|
||||
return_value=mock.sentinel.qemu_version)
|
||||
def test_qemu_image_version(self, mock_get_libversion, min_ver):
|
||||
"""Test that init_host sets qemu image version
|
||||
|
||||
A sentinel is used here so that we aren't chasing this value
|
||||
against minimums that get raised over time.
|
||||
"""
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
drvr.init_host("dummyhost")
|
||||
self.assertEqual(images.QEMU_VERSION, mock.sentinel.qemu_version)
|
||||
|
||||
@mock.patch.object(fakelibvirt.Connection, 'getLibVersion',
|
||||
return_value=versionutils.convert_version_to_int(
|
||||
libvirt_driver.MIN_LIBVIRT_OTHER_ARCH.get(
|
||||
@ -11605,9 +11622,8 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
||||
return_value=service_mock),
|
||||
mock.patch.object(host.Host, "get_capabilities")):
|
||||
|
||||
drvr.init_host("wibble")
|
||||
self.assertRaises(exception.HypervisorUnavailable,
|
||||
drvr.get_num_instances)
|
||||
drvr.init_host, ("wibble",))
|
||||
self.assertTrue(service_mock.disabled)
|
||||
|
||||
def test_service_resume_after_broken_connection(self):
|
||||
|
@ -171,6 +171,31 @@ blah BLAH: bb
|
||||
self.assertEqual(98304, image_info.disk_size)
|
||||
self.assertEqual(65536, image_info.cluster_size)
|
||||
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('nova.utils.execute')
|
||||
def test_qemu_info_canon_qemu_2_10(self, mock_execute, mock_exists):
|
||||
images.QEMU_VERSION = images.QEMU_VERSION_REQ_SHARED
|
||||
path = "disk.config"
|
||||
example_output = """image: disk.config
|
||||
file format: raw
|
||||
virtual size: 64M (67108864 bytes)
|
||||
cluster_size: 65536
|
||||
disk size: 96K
|
||||
blah BLAH: bb
|
||||
"""
|
||||
mock_execute.return_value = (example_output, '')
|
||||
image_info = images.qemu_img_info(path)
|
||||
mock_execute.assert_called_once_with('env', 'LC_ALL=C', 'LANG=C',
|
||||
'qemu-img', 'info', path,
|
||||
'--force-share',
|
||||
prlimit=images.QEMU_IMG_LIMITS)
|
||||
mock_exists.assert_called_once_with(path)
|
||||
self.assertEqual('disk.config', image_info.image)
|
||||
self.assertEqual('raw', image_info.file_format)
|
||||
self.assertEqual(67108864, image_info.virtual_size)
|
||||
self.assertEqual(98304, image_info.disk_size)
|
||||
self.assertEqual(65536, image_info.cluster_size)
|
||||
|
||||
@mock.patch('os.path.exists', return_value=True)
|
||||
@mock.patch('nova.utils.execute')
|
||||
def test_qemu_info_canon2(self, mock_execute, mock_exists):
|
||||
|
@ -19,6 +19,7 @@
|
||||
Handling of VM disk images.
|
||||
"""
|
||||
|
||||
import operator
|
||||
import os
|
||||
|
||||
from oslo_concurrency import processutils
|
||||
@ -42,6 +43,11 @@ QEMU_IMG_LIMITS = processutils.ProcessLimits(
|
||||
cpu_time=30,
|
||||
address_space=1 * units.Gi)
|
||||
|
||||
# This is set by the libvirt driver on startup. The version is used to
|
||||
# determine what flags need to be set on the command line.
|
||||
QEMU_VERSION = None
|
||||
QEMU_VERSION_REQ_SHARED = 2010000
|
||||
|
||||
|
||||
def qemu_img_info(path, format=None):
|
||||
"""Return an object containing the parsed output from qemu-img info."""
|
||||
@ -60,6 +66,10 @@ def qemu_img_info(path, format=None):
|
||||
cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path)
|
||||
if format is not None:
|
||||
cmd = cmd + ('-f', format)
|
||||
# Check to see if the qemu version is >= 2.10 because if so, we need
|
||||
# to add the --force-share flag.
|
||||
if QEMU_VERSION and operator.ge(QEMU_VERSION, QEMU_VERSION_REQ_SHARED):
|
||||
cmd = cmd + ('--force-share',)
|
||||
out, err = utils.execute(*cmd, prlimit=QEMU_IMG_LIMITS)
|
||||
except processutils.ProcessExecutionError as exp:
|
||||
# this means we hit prlimits, make the exception more specific
|
||||
|
@ -481,11 +481,15 @@ class LibvirtDriver(driver.ComputeDriver):
|
||||
_('Nova requires libvirt version %s or greater.') %
|
||||
self._version_to_string(MIN_LIBVIRT_VERSION))
|
||||
|
||||
if (CONF.libvirt.virt_type in ("qemu", "kvm") and
|
||||
not self._host.has_min_version(hv_ver=MIN_QEMU_VERSION)):
|
||||
raise exception.InternalError(
|
||||
_('Nova requires QEMU version %s or greater.') %
|
||||
self._version_to_string(MIN_QEMU_VERSION))
|
||||
if CONF.libvirt.virt_type in ("qemu", "kvm"):
|
||||
if self._host.has_min_version(hv_ver=MIN_QEMU_VERSION):
|
||||
# "qemu-img info" calls are version dependent, so we need to
|
||||
# store the version in the images module.
|
||||
images.QEMU_VERSION = self._host.get_connection().getVersion()
|
||||
else:
|
||||
raise exception.InternalError(
|
||||
_('Nova requires QEMU version %s or greater.') %
|
||||
self._version_to_string(MIN_QEMU_VERSION))
|
||||
|
||||
if CONF.libvirt.virt_type == 'parallels':
|
||||
if not self._host.has_min_version(hv_ver=MIN_VIRTUOZZO_VERSION):
|
||||
|
Loading…
Reference in New Issue
Block a user