Skip to content

Commit

Permalink
Add compatibility for CPU model config with libvirt < 0.9.10
Browse files Browse the repository at this point in the history
Libvirt versions prior to 0.9.10 do not support the simpler
'mode' attribute for choosing CPU model. So with such libvirt
releases we must explicitly construct the guest CPU model
from the host capabilities info when mode=host-model. We
can not support mode=host-passthrough at all with these
earlier libvirt versions

This change can be reverted in the future, if the value of
the MIN_LIBVIRT_VERSION constant is increased to 0.9.10
or later

Fixes: bug #1003373
Implements: blueprint libvirt-xml-cpu-model
Change-Id: I3e55ffccf38be18454f810efeb5c201aab94ddb0
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
  • Loading branch information
berrange committed Jul 2, 2012
1 parent 7504c13 commit 2a236d2
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 3 deletions.
73 changes: 73 additions & 0 deletions nova/tests/test_libvirt.py
Expand Up @@ -684,6 +684,79 @@ def get_lib_version_stub(self):
self.assertEquals(conf.cpu.mode, "custom")
self.assertEquals(conf.cpu.model, "Penryn")

@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_host_passthrough_old(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 7

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")
self.assertRaises(exception.NovaException,
conn.get_guest_config,
instance_ref,
_fake_network_info(self.stubs, 1),
None, None)

@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_host_model_old(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 7

# Ensure we have a predictable host CPU
def get_host_capabilities_stub(self):
cpu = config.LibvirtConfigGuestCPU()
cpu.model = "Opteron_G4"
cpu.vendor = "AMD"

caps = config.LibvirtConfigCaps()
caps.host = config.LibvirtConfigCapsHost()
caps.host.cpu = cpu
return caps

self.stubs.Set(libvirt.virConnect,
"getLibVersion",
get_lib_version_stub)
self.stubs.Set(libvirt_driver.LibvirtDriver,
"get_host_capabilities",
get_host_capabilities_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, None)
self.assertEquals(conf.cpu.model, "Opteron_G4")
self.assertEquals(conf.cpu.vendor, "AMD")

@test.skip_if(missing_libvirt(), "Test requires libvirt")
def test_get_guest_cpu_config_custom_old(self):
def get_lib_version_stub(self):
return (0 * 1000 * 1000) + (9 * 1000) + 7

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, None)
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,
Expand Down
43 changes: 40 additions & 3 deletions nova/virt/libvirt/driver.py
Expand Up @@ -231,6 +231,9 @@ def repr_method(self):
}

MIN_LIBVIRT_VERSION = (0, 9, 6)
# When the above version matches/exceeds this version
# delete it & corresponding code using it
MIN_LIBVIRT_HOST_CPU_VERSION = (0, 9, 10)


def _late_load_cheetah():
Expand Down Expand Up @@ -1469,6 +1472,27 @@ def get_host_capabilities(self):
caps.parse_str(xmlstr)
return caps

def get_host_cpu_for_guest(self):
"""Returns an instance of config.LibvirtConfigGuestCPU
representing the host's CPU model & topology with
policy for configuring a guest to match"""

caps = self.get_host_capabilities()
hostcpu = caps.host.cpu
guestcpu = config.LibvirtConfigGuestCPU()

guestcpu.model = hostcpu.model
guestcpu.vendor = hostcpu.vendor
guestcpu.arch = hostcpu.arch

guestcpu.match = "exact"

for hostfeat in hostcpu.features:
guestfeat = config.LibvirtConfigGuestCPUFeature(hostfeat.name)
guestfeat.policy = "require"

return guestcpu

def get_guest_cpu_config(self):
mode = FLAGS.libvirt_cpu_mode
model = FLAGS.libvirt_cpu_model
Expand All @@ -1494,9 +1518,22 @@ def get_guest_cpu_config(self):
LOG.debug(_("CPU mode '%(mode)s' model '%(model)s' was chosen")
% {'mode': mode, 'model': (model or "")})

cpu = config.LibvirtConfigGuestCPU()
cpu.mode = mode
cpu.model = model
# TODO(berrange): in the future, when MIN_LIBVIRT_VERSION is
# updated to be at least this new, we can kill off the elif
# blocks here
if self.has_min_version(MIN_LIBVIRT_HOST_CPU_VERSION):
cpu = config.LibvirtConfigGuestCPU()
cpu.mode = mode
cpu.model = model
elif mode == "custom":
cpu = config.LibvirtConfigGuestCPU()
cpu.model = model
elif mode == "host-model":
cpu = self.get_host_cpu_for_guest()
elif mode == "host-passthrough":
msg = _("Passthrough of the host CPU was requested but "
"this libvirt version does not support this feature")
raise exception.NovaException(msg)

return cpu

Expand Down

0 comments on commit 2a236d2

Please sign in to comment.