Allow specification of the libvirt guest CPU model per host

Currently Nova does not configure any CPU model for libvirt
guests. This is sub-optimal because the default KVM CPU
model has changed a number of times, and more importantly
VMs are not able to take advantage of many performance
features in newer CPUs. To get a consistent CPU model exposed
to the guest and maximize performance of VMs in the cloud,
explicit specification of CPU models per host is desirable.

This change adds a new Nova config flag:

  libvirt_cpu_mode = host-model|host-passthrough|custom

Where

  * host-model == configure a model that matches the features
                  available in the host CPU

  * host-passthrough == passthrough the host CPU precisely
                        with no change at all

  * custom == configure a specific named CPU model

If the 'custom' mode is used, then the additional flag
is available to choose the model:

  libvirt_cpu_model = <one of the names from /usr/share/libvirt/cpu_model.xml>

eg

  libvirt_cpu_model = core2duo

If specifying a custom CPU model, it is wise to choose one that is
capable of running on all the various different Nova hosts in the
cloud. That said, libvirt will enforce compatibility at time of
starting or migrating guests & refuse the operation if required.

If using either the host-model or host-passthrough modes, and use
of live migration is desired, admins should ensure that all hosts
have a homogeneous CPU model. If hosts have a hetergeneous CPU
models, then a custom named CPU model is a better choice

This configuration only works for libvirt >= 0.9.10, due to the
use of the 'mode' attribute on the <cpu> element for configuring
host models.

Fixes: bug #1003373
Implements: blueprint libvirt-xml-cpu-model
Change-Id: I90ce78d7e29bd0d563e3bc547b7cc5d64dd9496e
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange
2012-06-13 17:57:03 +01:00
parent da2145e8e8
commit efd7ac1344

View File

@@ -614,6 +614,76 @@ class LibvirtConnTestCase(test.TestCase):
config.LibvirtConfigGuestDisk)
self.assertEquals(cfg.devices[3].target_dev, 'vdd')
def test_get_guest_cpu_config_none(self):
conn = libvirt_driver.LibvirtDriver(True)
instance_ref = db.instance_create(self.context, self.test_instance)
conf = conn.get_guest_config(instance_ref,
_fake_network_info(self.stubs, 1),
None, None)
self.assertEquals(conf.cpu, None)
@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_host_passthrough_new(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 11
self.stubs.Set(libvirt.virConnect,
"getLibVersion",
get_lib_version_stub)
conn = libvirt_driver.LibvirtDriver(True)
instance_ref = db.instance_create(self.context, self.test_instance)
self.flags(libvirt_cpu_mode="host-passthrough")
conf = conn.get_guest_config(instance_ref,
_fake_network_info(self.stubs, 1),
None, None)
self.assertEquals(type(conf.cpu),
config.LibvirtConfigGuestCPU)
self.assertEquals(conf.cpu.mode, "host-passthrough")
self.assertEquals(conf.cpu.model, None)
@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_host_model_new(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 11
self.stubs.Set(libvirt.virConnect,
"getLibVersion",
get_lib_version_stub)
conn = libvirt_driver.LibvirtDriver(True)
instance_ref = db.instance_create(self.context, self.test_instance)
self.flags(libvirt_cpu_mode="host-model")
conf = conn.get_guest_config(instance_ref,
_fake_network_info(self.stubs, 1),
None, None)
self.assertEquals(type(conf.cpu),
config.LibvirtConfigGuestCPU)
self.assertEquals(conf.cpu.mode, "host-model")
self.assertEquals(conf.cpu.model, None)
@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_custom_new(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 11
self.stubs.Set(libvirt.virConnect,
"getLibVersion",
get_lib_version_stub)
conn = libvirt_driver.LibvirtDriver(True)
instance_ref = db.instance_create(self.context, self.test_instance)
self.flags(libvirt_cpu_mode="custom")
self.flags(libvirt_cpu_model="Penryn")
conf = conn.get_guest_config(instance_ref,
_fake_network_info(self.stubs, 1),
None, None)
self.assertEquals(type(conf.cpu),
config.LibvirtConfigGuestCPU)
self.assertEquals(conf.cpu.mode, "custom")
self.assertEquals(conf.cpu.model, "Penryn")
def test_xml_and_uri_no_ramdisk_no_kernel(self):
instance_data = dict(self.test_instance)
self._check_xml_and_uri(instance_data,