From bcc04993fe8fbeb374cacf990105270579a530c2 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 13 Jun 2012 16:34:06 +0100 Subject: Refactor libvirt config classes for representing CPU models/features The previously added (but not used) LibvirtConfigCPUTest class was too inflexible. It did not distinguish between parts of the XML schema which applied to both capabilities & domain XML, vs those which only applied to the domain XML. By representing features as a plain string it did not allow for setting attributes on feature flags like policy. This change replaces the single LibvirtConfigCPUTest class with 4 new classes: - LibvirtConfigCPUFeature - base class for defining CPU features - LibvirtConfigCPU - base class for defining CPU models - LibvirtConfigGuestCPUFeature - extension for setting the guest specific feature policy - LibvirtConfigGuestCPU - extension for setting the guest specific match policy, and allowing use of host CPU model passthrough Fixes: bug #1003373 Implements: blueprint libvirt-xml-cpu-model Change-Id: I0aa0ddfb86cf8b89b2e4dcc95e21bdca304bd6b3 Signed-off-by: Daniel P. Berrange --- nova/tests/test_libvirt_config.py | 154 +++++++++++++++++++++++++++++--------- nova/virt/libvirt/config.py | 137 +++++++++++++++++++++++---------- nova/virt/libvirt/driver.py | 2 +- 3 files changed, 215 insertions(+), 78 deletions(-) diff --git a/nova/tests/test_libvirt_config.py b/nova/tests/test_libvirt_config.py index 4f9970e79..59ed88e1c 100644 --- a/nova/tests/test_libvirt_config.py +++ b/nova/tests/test_libvirt_config.py @@ -151,6 +151,123 @@ class LibvirtConfigGuestClockTest(LibvirtConfigBaseTest): """) +class LibvirtConfigCPUFeatureTest(LibvirtConfigBaseTest): + + def test_config_simple(self): + obj = config.LibvirtConfigCPUFeature("mtrr") + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + """) + + +class LibvirtConfigGuestCPUFeatureTest(LibvirtConfigBaseTest): + + def test_config_simple(self): + obj = config.LibvirtConfigGuestCPUFeature("mtrr") + obj.policy = "force" + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + """) + + +class LibvirtConfigCPUTest(LibvirtConfigBaseTest): + + def test_config_simple(self): + obj = config.LibvirtConfigCPU() + obj.model = "Penryn" + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + Penryn + + """) + + def test_config_complex(self): + obj = config.LibvirtConfigCPU() + obj.model = "Penryn" + obj.vendor = "Intel" + obj.arch = "x86_64" + + obj.add_feature(config.LibvirtConfigCPUFeature("mtrr")) + obj.add_feature(config.LibvirtConfigCPUFeature("apic")) + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + x86_64 + Penryn + Intel + + + + """) + + def test_config_topology(self): + obj = config.LibvirtConfigCPU() + obj.model = "Penryn" + obj.sockets = 4 + obj.cores = 4 + obj.threads = 2 + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + Penryn + + + """) + + +class LibvirtConfigGuestCPUTest(LibvirtConfigBaseTest): + + def test_config_simple(self): + obj = config.LibvirtConfigGuestCPU() + obj.model = "Penryn" + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + Penryn + + """) + + def test_config_complex(self): + obj = config.LibvirtConfigGuestCPU() + obj.model = "Penryn" + obj.vendor = "Intel" + obj.arch = "x86_64" + obj.mode = "custom" + + obj.add_feature(config.LibvirtConfigGuestCPUFeature("mtrr")) + obj.add_feature(config.LibvirtConfigGuestCPUFeature("apic")) + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + x86_64 + Penryn + Intel + + + + """) + + def test_config_host(self): + obj = config.LibvirtConfigGuestCPU() + obj.mode = "host-model" + obj.match = "exact" + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + """) + + class LibvirtConfigGuestDiskTest(LibvirtConfigBaseTest): def test_config_file(self): @@ -485,43 +602,6 @@ class LibvirtConfigGuestTest(LibvirtConfigBaseTest): """) -class LibvirtConfigCPUTest(LibvirtConfigBaseTest): - - def test_config_cpu(self): - obj = config.LibvirtConfigCPU() - obj.vendor = "AMD" - obj.model = "Quad-Core AMD Opteron(tm) Processor 2350" - obj.arch = "x86_64" - obj.add_feature("svm") - obj.add_feature("extapic") - obj.add_feature("constant_tsc") - - xml = obj.to_xml() - self.assertXmlEqual(xml, """ - - x86_64 - Quad-Core AMD Opteron(tm) Processor 2350 - AMD - - - - """) - - def test_config_topology(self): - obj = config.LibvirtConfigCPU() - obj.vendor = "AMD" - obj.sockets = 2 - obj.cores = 4 - obj.threads = 2 - - xml = obj.to_xml() - self.assertXmlEqual(xml, """ - - AMD - - """) - - class LibvirtConfigGuestSnapshotTest(LibvirtConfigBaseTest): def test_config_snapshot(self): diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index c67f11550..b432b860f 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -124,6 +124,99 @@ class LibvirtConfigGuestClock(LibvirtConfigObject): self.timers.append(tm) +class LibvirtConfigCPUFeature(LibvirtConfigObject): + + def __init__(self, name=None, **kwargs): + super(LibvirtConfigCPUFeature, self).__init__(root_name='feature', + **kwargs) + + self.name = name + + def format_dom(self): + ft = super(LibvirtConfigCPUFeature, self).format_dom() + + ft.set("name", self.name) + + return ft + + +class LibvirtConfigCPU(LibvirtConfigObject): + + def __init__(self, **kwargs): + super(LibvirtConfigCPU, self).__init__(root_name='cpu', + **kwargs) + + self.arch = None + self.vendor = None + self.model = None + + self.sockets = None + self.cores = None + self.threads = None + + self.features = [] + + def format_dom(self): + cpu = super(LibvirtConfigCPU, self).format_dom() + + if self.arch is not None: + cpu.append(self._text_node("arch", self.arch)) + if self.model is not None: + cpu.append(self._text_node("model", self.model)) + if self.vendor is not None: + cpu.append(self._text_node("vendor", self.vendor)) + + if (self.sockets is not None and + self.cores is not None and + self.threads is not None): + top = etree.Element("topology") + top.set("sockets", str(self.sockets)) + top.set("cores", str(self.cores)) + top.set("threads", str(self.threads)) + cpu.append(top) + + for f in self.features: + cpu.append(f.format_dom()) + + return cpu + + def add_feature(self, feat): + self.features.append(feat) + + +class LibvirtConfigGuestCPUFeature(LibvirtConfigCPUFeature): + + def __init__(self, name=None, **kwargs): + super(LibvirtConfigGuestCPUFeature, self).__init__(name, **kwargs) + + self.policy = "require" + + def format_dom(self): + ft = super(LibvirtConfigGuestCPUFeature, self).format_dom() + + ft.set("policy", self.policy) + + return ft + + +class LibvirtConfigGuestCPU(LibvirtConfigCPU): + + def __init__(self, **kwargs): + super(LibvirtConfigGuestCPU, self).__init__(**kwargs) + + self.mode = None + self.match = "exact" + + def format_dom(self): + cpu = super(LibvirtConfigGuestCPU, self).format_dom() + + if self.mode: + cpu.set("mode", self.mode) + cpu.set("match", self.match) + + return cpu + + class LibvirtConfigGuestDevice(LibvirtConfigObject): def __init__(self, **kwargs): @@ -366,6 +459,7 @@ class LibvirtConfigGuest(LibvirtConfigObject): self.name = None self.memory = 1024 * 1024 * 500 self.vcpus = 1 + self.cpu = None self.acpi = False self.clock = None self.os_type = None @@ -426,6 +520,9 @@ class LibvirtConfigGuest(LibvirtConfigObject): if self.clock is not None: root.append(self.clock.format_dom()) + if self.cpu is not None: + root.append(self.cpu.format_dom()) + self._format_devices(root) return root @@ -437,46 +534,6 @@ class LibvirtConfigGuest(LibvirtConfigObject): self.clock = clk -class LibvirtConfigCPU(LibvirtConfigObject): - - def __init__(self, **kwargs): - super(LibvirtConfigCPU, self).__init__(root_name="cpu", - **kwargs) - - self.arch = None - self.model = None - self.vendor = None - self.sockets = None - self.cores = None - self.threads = None - self.features = [] - - def add_feature(self, name): - self.features.append(name) - - def format_dom(self): - cpu = super(LibvirtConfigCPU, self).format_dom() - if self.arch: - cpu.append(self._text_node("arch", self.arch)) - if self.model: - cpu.append(self._text_node("model", self.model)) - if self.vendor: - cpu.append(self._text_node("vendor", self.vendor)) - if (self.sockets is not None and - self.cores is not None and - self.threads is not None): - cpu.append(etree.Element("topology", - sockets=str(self.sockets), - cores=str(self.cores), - threads=str(self.threads))) - - for f in self.features: - cpu.append(etree.Element("feature", - name=f)) - - return cpu - - class LibvirtConfigGuestSnapshot(LibvirtConfigObject): def __init__(self, **kwargs): diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index d0000186b..08de82d62 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -2117,7 +2117,7 @@ class LibvirtDriver(driver.ComputeDriver): cpu.cores = info['topology']['cores'] cpu.threads = info['topology']['threads'] for f in info['features']: - cpu.add_feature(f) + cpu.add_feature(config.LibvirtConfigCPUFeature(f)) u = "http://libvirt.org/html/libvirt-libvirt.html#virCPUCompareResult" m = _("CPU doesn't have compatibility.\n\n%(ret)s\n\nRefer to %(u)s") -- cgit