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
This commit is contained in:
Andrew Bonney 2020-10-06 14:42:38 +01:00
parent 261de76104
commit eeeca4ceff
2 changed files with 47 additions and 2 deletions

View File

@ -339,6 +339,26 @@ class LibvirtConfigCPUFeatureTest(LibvirtConfigBaseTest):
<feature name="mtrr"/>
""")
def test_config_parse_require(self):
xml = """
<feature name="mtrr" policy="require"/>
"""
xmldoc = etree.fromstring(xml)
obj = config.LibvirtConfigCPUFeature()
obj.parse_dom(xmldoc)
self.assertEqual(obj.policy, "require")
def test_config_parse_disable(self):
xml = """
<feature name="mtrr" policy="disable"/>
"""
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):
</cpu>
""")
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, """
<cpu>
<arch>x86_64</arch>
<model>Penryn</model>
<vendor>Intel</vendor>
<feature name="apic"/>
</cpu>
""")
def test_only_uniq_cpu_featues(self):
obj = config.LibvirtConfigCPU()
obj.model = "Penryn"

View File

@ -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