From eeeca4ceff576beaa8558360c8a6a165d716f996 Mon Sep 17 00:00:00 2001 From: Andrew Bonney Date: Tue, 6 Oct 2020 14:42:38 +0100 Subject: [PATCH] Handle disabled CPU features to fix live migration failures When performing a live migration between hypervisors running libvirt, where one or more CPU features are disabled, nova does not take account of these. This results in migration failures as none of the available hypervisor targets appear compatible. This patch ensures that the libvirt 'disable' poicy is taken account of, at least in a basic sense, by explicitly ignoring items flagged in this way when enumerating CPU features. Closes-Bug: #1898715 Change-Id: Iaf14ca97cfac99dd280d1114123f2d4bb6292b63 --- nova/tests/unit/virt/libvirt/test_config.py | 41 +++++++++++++++++++++ nova/virt/libvirt/config.py | 8 +++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/nova/tests/unit/virt/libvirt/test_config.py b/nova/tests/unit/virt/libvirt/test_config.py index f0c2fa3b51..9a9342efae 100644 --- a/nova/tests/unit/virt/libvirt/test_config.py +++ b/nova/tests/unit/virt/libvirt/test_config.py @@ -339,6 +339,26 @@ class LibvirtConfigCPUFeatureTest(LibvirtConfigBaseTest): """) + def test_config_parse_require(self): + xml = """ + + """ + xmldoc = etree.fromstring(xml) + obj = config.LibvirtConfigCPUFeature() + obj.parse_dom(xmldoc) + + self.assertEqual(obj.policy, "require") + + def test_config_parse_disable(self): + xml = """ + + """ + xmldoc = etree.fromstring(xml) + obj = config.LibvirtConfigCPUFeature() + obj.parse_dom(xmldoc) + + self.assertEqual(obj.policy, "disable") + class LibvirtConfigGuestCPUFeatureTest(LibvirtConfigBaseTest): @@ -437,6 +457,27 @@ class LibvirtConfigCPUTest(LibvirtConfigBaseTest): """) + def test_config_disabled_features(self): + obj = config.LibvirtConfigCPU() + obj.model = "Penryn" + obj.vendor = "Intel" + obj.arch = obj_fields.Architecture.X86_64 + + disabled_feature = config.LibvirtConfigCPUFeature("mtrr") + disabled_feature.policy = "disable" + obj.add_feature(disabled_feature) + obj.add_feature(config.LibvirtConfigCPUFeature("apic")) + + xml = obj.to_xml() + self.assertXmlEqual(xml, """ + + x86_64 + Penryn + Intel + + + """) + def test_only_uniq_cpu_featues(self): obj = config.LibvirtConfigCPU() obj.model = "Penryn" diff --git a/nova/virt/libvirt/config.py b/nova/virt/libvirt/config.py index 7cfdb4218b..ea525648b3 100644 --- a/nova/virt/libvirt/config.py +++ b/nova/virt/libvirt/config.py @@ -674,11 +674,13 @@ class LibvirtConfigCPUFeature(LibvirtConfigObject): **kwargs) self.name = name + self.policy = "require" def parse_dom(self, xmldoc): super(LibvirtConfigCPUFeature, self).parse_dom(xmldoc) self.name = xmldoc.get("name") + self.policy = xmldoc.get("policy", "require") def format_dom(self): ft = super(LibvirtConfigCPUFeature, self).format_dom() @@ -730,7 +732,8 @@ class LibvirtConfigCPU(LibvirtConfigObject): elif c.tag == "feature": f = LibvirtConfigCPUFeature() f.parse_dom(c) - self.add_feature(f) + if f.policy != "disable": + self.add_feature(f) def format_dom(self): cpu = super(LibvirtConfigCPU, self).format_dom() @@ -753,7 +756,8 @@ class LibvirtConfigCPU(LibvirtConfigObject): # sorting the features to allow more predictable tests for f in sorted(self.features, key=lambda x: x.name): - cpu.append(f.format_dom()) + if f.policy != "disable": + cpu.append(f.format_dom()) return cpu