Merge "Add compatibility checks for CPU mode and CPU models and extra flags"
This commit is contained in:
commit
93f4cdb713
|
@ -1292,6 +1292,70 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||
self.assertRaises(exception.InternalError,
|
||||
drvr._check_file_backed_memory_support)
|
||||
|
||||
def test__check_cpu_compatibility_start_ok(self):
|
||||
self.flags(cpu_mode="custom",
|
||||
cpu_models=["Penryn"],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
drvr.init_host("dummyhost")
|
||||
|
||||
def test__check_cpu_compatibility_none_models(self):
|
||||
self.flags(cpu_mode="custom",
|
||||
cpu_models=[],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.Invalid, drvr.init_host, "dummyhost")
|
||||
|
||||
def test__check_cpu_compatibility_none_mode(self):
|
||||
self.flags(cpu_mode="none",
|
||||
cpu_models=["Penryn"],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.Invalid, drvr.init_host, "dummyhost")
|
||||
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.compareCPU')
|
||||
def test__check_cpu_compatibility_advance_model(self, mocked_compare):
|
||||
mocked_compare.side_effect = (2, 0)
|
||||
self.flags(cpu_mode="custom",
|
||||
cpu_models=["qemu64", "Broadwell-noTSX"],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.InvalidCPUInfo,
|
||||
drvr.init_host, "dummyhost")
|
||||
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.compareCPU')
|
||||
def test__check_cpu_compatibility_advance_flag(self, mocked_compare):
|
||||
mocked_compare.side_effect = (2, 0)
|
||||
self.flags(cpu_mode="custom",
|
||||
cpu_models=["qemu64"],
|
||||
cpu_model_extra_flags = ["avx", "avx2"],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.InvalidCPUInfo,
|
||||
drvr.init_host, "dummyhost")
|
||||
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.compareCPU')
|
||||
def test__check_cpu_compatibility_wrong_flag(self, mocked_compare):
|
||||
mocked_compare.side_effect = (2, 0)
|
||||
self.flags(cpu_mode="custom",
|
||||
cpu_models=["Broadwell-noTSX"],
|
||||
cpu_model_extra_flags = ["a v x"],
|
||||
group="libvirt")
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.InvalidCPUInfo,
|
||||
drvr.init_host, "dummyhost")
|
||||
|
||||
def test__check_cpu_compatibility_invalid_virt_type(self):
|
||||
"""Test getting CPU traits when using a virt_type that doesn't support
|
||||
the feature, only kvm and qemu supports reporting CPU traits.
|
||||
"""
|
||||
self.flags(cpu_mode='custom',
|
||||
cpu_models=['IvyBridge'],
|
||||
virt_type='lxc',
|
||||
group='libvirt')
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
self.assertRaises(exception.Invalid, drvr.init_host, "dummyhost")
|
||||
|
||||
def _do_test_parse_migration_flags(self, lm_expected=None,
|
||||
bm_expected=None):
|
||||
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
|
||||
|
@ -22436,17 +22500,6 @@ class LibvirtDriverTestCase(test.NoDBTestCase, TraitsComparisonMixin):
|
|||
|
||||
self.assertTraitsEqual([], self.drvr._get_cpu_feature_traits())
|
||||
|
||||
def test_cpu_traits_with_invalid_virt_type(self):
|
||||
"""Test getting CPU traits when using a virt_type that doesn't support
|
||||
the feature, only kvm and qemu supports reporting CPU traits.
|
||||
"""
|
||||
self.flags(cpu_mode='custom',
|
||||
cpu_models=['IvyBridge'],
|
||||
virt_type='lxc',
|
||||
group='libvirt'
|
||||
)
|
||||
self.assertRaises(exception.Invalid, self.drvr._get_cpu_feature_traits)
|
||||
|
||||
@mock.patch('nova.virt.libvirt.host.libvirt.Connection.getCapabilities')
|
||||
@mock.patch('nova.virt.libvirt.utils.cpu_features_to_traits')
|
||||
def test_cpu_traits_with_mode_passthrough_and_extra_flags(
|
||||
|
|
|
@ -649,6 +649,64 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
if self._host.has_min_version(MIN_LIBVIRT_MDEV_SUPPORT):
|
||||
self._recreate_assigned_mediated_devices()
|
||||
|
||||
self._check_cpu_compatibility()
|
||||
|
||||
def _check_cpu_compatibility(self):
|
||||
mode = CONF.libvirt.cpu_mode
|
||||
models = CONF.libvirt.cpu_models
|
||||
|
||||
if (CONF.libvirt.virt_type not in ("kvm", "qemu") and
|
||||
mode not in (None, 'none')):
|
||||
msg = _("Config requested an explicit CPU model, but "
|
||||
"the current libvirt hypervisor '%s' does not "
|
||||
"support selecting CPU models") % CONF.libvirt.virt_type
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if mode != "custom":
|
||||
if not models:
|
||||
return
|
||||
msg = _("The cpu_models option is not required when "
|
||||
"cpu_mode!=custom")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if not models:
|
||||
msg = _("The cpu_models option is required when cpu_mode=custom")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
cpu = vconfig.LibvirtConfigGuestCPU()
|
||||
for model in models:
|
||||
cpu.model = self._get_cpu_model_mapping(model)
|
||||
if not cpu.model:
|
||||
msg = (_("Configured CPU model: %(model)s is not correct, "
|
||||
"or your host CPU arch does not suuport this "
|
||||
"model. Please correct your config and try "
|
||||
"again.") % {'model': model})
|
||||
raise exception.InvalidCPUInfo(msg)
|
||||
try:
|
||||
self._compare_cpu(cpu, self._get_cpu_info(), None)
|
||||
except exception.InvalidCPUInfo as e:
|
||||
msg = (_("Configured CPU model: %(model)s is not "
|
||||
"compatible with host CPU. Please correct your "
|
||||
"config and try again. %(e)s") % {
|
||||
'model': model, 'e': e})
|
||||
raise exception.InvalidCPUInfo(msg)
|
||||
|
||||
# Use guest CPU model to check the compatibility between guest CPU and
|
||||
# configured extra_flags
|
||||
cpu = vconfig.LibvirtConfigGuestCPU()
|
||||
cpu.model = self._host.get_capabilities().host.cpu.arch
|
||||
for flag in set(x.lower() for x in CONF.libvirt.cpu_model_extra_flags):
|
||||
cpu.add_feature(vconfig.LibvirtConfigCPUFeature(flag))
|
||||
try:
|
||||
self._compare_cpu(cpu, self._get_cpu_info(), None)
|
||||
except (exception.InvalidCPUInfo,
|
||||
exception.MigrationPreCheckError) as e:
|
||||
msg = (_("Configured extra flag: %(flag)s it not correct, or "
|
||||
"the host CPU does not support this flag. Please "
|
||||
"correct the config and try again. %(e)s") % {
|
||||
'flag': flag, 'e': e})
|
||||
raise exception.InvalidCPUInfo(msg)
|
||||
|
||||
@staticmethod
|
||||
def _is_existing_mdev(uuid):
|
||||
# FIXME(sbauza): Some kernel can have a uevent race meaning that the
|
||||
|
@ -3965,11 +4023,21 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
mount.get_manager().host_down()
|
||||
|
||||
def _get_cpu_model_mapping(self, model):
|
||||
"""Get the CPU model mapping
|
||||
|
||||
The CPU models which admin configured are case-insensitive, libvirt is
|
||||
case-sensitive, therefore build a mapping to get the correct CPU model
|
||||
name.
|
||||
|
||||
:param model: Case-insensitive CPU model name.
|
||||
:return: Case-sensitive CPU model name, or None(Only when configured
|
||||
CPU model name not correct)
|
||||
"""
|
||||
if not self.cpu_models_mapping:
|
||||
cpu_models = self._host.get_cpu_model_names()
|
||||
for cpu_model in cpu_models:
|
||||
self.cpu_models_mapping[cpu_model.lower()] = cpu_model
|
||||
return self.cpu_models_mapping.get(model.lower())
|
||||
return self.cpu_models_mapping.get(model.lower(), None)
|
||||
|
||||
def _get_guest_cpu_model_config(self, flavor=None):
|
||||
mode = CONF.libvirt.cpu_mode
|
||||
|
@ -4004,23 +4072,6 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
if mode is None or mode == "none":
|
||||
return None
|
||||
|
||||
if ((CONF.libvirt.virt_type != "kvm" and
|
||||
CONF.libvirt.virt_type != "qemu")):
|
||||
msg = _("Config requested an explicit CPU model, but "
|
||||
"the current libvirt hypervisor '%s' does not "
|
||||
"support selecting CPU models") % CONF.libvirt.virt_type
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if mode == "custom" and not models:
|
||||
msg = _("Config requested custom CPU models, but no "
|
||||
"model names was provided")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
if mode != "custom" and models:
|
||||
msg = _("CPU model names should not be set when a "
|
||||
"host CPU model is requested")
|
||||
raise exception.Invalid(msg)
|
||||
|
||||
cpu = vconfig.LibvirtConfigGuestCPU()
|
||||
cpu.mode = mode
|
||||
cpu.model = models[0] if models else None
|
||||
|
@ -7643,7 +7694,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
def _compare_cpu(self, guest_cpu, host_cpu_str, instance):
|
||||
"""Check the host is compatible with the requested CPU
|
||||
|
||||
:param guest_cpu: nova.objects.VirtCPUModel or None
|
||||
:param guest_cpu: nova.objects.VirtCPUModel
|
||||
or nova.virt.libvirt.vconfig.LibvirtConfigGuestCPU or None.
|
||||
:param host_cpu_str: JSON from _get_cpu_info() method
|
||||
|
||||
If the 'guest_cpu' parameter is not None, this will be
|
||||
|
@ -7677,6 +7729,8 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||
cpu.threads = info['topology']['threads']
|
||||
for f in info['features']:
|
||||
cpu.add_feature(vconfig.LibvirtConfigCPUFeature(f))
|
||||
elif isinstance(guest_cpu, vconfig.LibvirtConfigGuestCPU):
|
||||
cpu = guest_cpu
|
||||
else:
|
||||
cpu = self._vcpu_model_to_cpu_config(guest_cpu)
|
||||
|
||||
|
|
Loading…
Reference in New Issue