capabilities: Switch to use XMLBuilder

Just a cleanup to finally unify all the XML objects around the same
API, and drop a bunch of old cruft.
This commit is contained in:
Cole Robinson 2015-04-03 12:40:16 -04:00
parent 0492dbc1b1
commit cac4ac1401
7 changed files with 251 additions and 400 deletions

View File

@ -19,20 +19,19 @@ import os
import unittest
from tests import utils
from virtinst import CapabilitiesParser as capabilities
from virtinst.capabilities import _CPUMapFileValues
from virtinst import Capabilities
from virtinst import DomainCapabilities
from virtinst.capabilities import _CPUMapFileValues
def build_host_feature_dict(feature_list):
fdict = {}
for f in feature_list:
fdict[f] = capabilities.FEATURE_ON
return fdict
conn = utils.open_testdriver()
class TestCapabilities(unittest.TestCase):
def _buildCaps(self, filename):
path = os.path.join("tests/capabilities-xml", filename)
return Capabilities(conn, file(path).read())
def _compareGuest(self, (arch, os_type, domains, features), guest):
self.assertEqual(arch, guest.arch)
@ -44,13 +43,7 @@ class TestCapabilities(unittest.TestCase):
self.assertEqual(domains[n][2], guest.domains[n].machines)
for n in features:
self.assertEqual(features[n], guest.features[n])
def _buildCaps(self, filename):
path = os.path.join("tests/capabilities-xml", filename)
xml = file(path).read()
return capabilities.Capabilities(xml)
self.assertEqual(features[n], getattr(guest.features, n))
def _testCapabilities(self, path, (host_arch, host_features), guests,
secmodel=None):
@ -59,28 +52,31 @@ class TestCapabilities(unittest.TestCase):
if host_arch:
self.assertEqual(host_arch, caps.host.cpu.arch)
for n in host_features:
self.assertEqual(host_features[n], caps.host.cpu.features[n])
self.assertEqual(host_features[n], caps.host.cpu.has_feature(n))
if secmodel:
self.assertEqual(secmodel[0], caps.host.secmodel.model)
self.assertEqual(secmodel[1], caps.host.secmodel.doi)
if secmodel[2]:
for k, v in secmodel[2].items():
self.assertEqual(v, caps.host.secmodel.baselabels[k])
self.assertEqual(secmodel[0], caps.host.secmodels[0].model)
if secmodel[1]:
for idx, (t, v) in enumerate(secmodel[1].items()):
self.assertEqual(t,
caps.host.secmodels[0].baselabels[idx].type)
self.assertEqual(v,
caps.host.secmodels[0].baselabels[idx].content)
for idx in range(len(guests)):
self._compareGuest(guests[idx], caps.guests[idx])
def testCapabilities1(self):
host = ('x86_64', {'vmx': capabilities.FEATURE_ON})
host = ('x86_64', {'vmx': True})
guests = [
('x86_64', 'xen',
[['xen', None, []]], {}),
('i686', 'xen',
[['xen', None, []]], {'pae': capabilities.FEATURE_ON}),
[['xen', None, []]], {'pae': True, 'nonpae': False}),
('i686', 'hvm',
[['xen', "/usr/lib64/xen/bin/qemu-dm", ['pc', 'isapc']]], {'pae': capabilities.FEATURE_ON | capabilities.FEATURE_OFF}),
[['xen', "/usr/lib64/xen/bin/qemu-dm", ['pc', 'isapc']]],
{'pae': True, 'nonpae': True}),
('x86_64', 'hvm',
[['xen', "/usr/lib64/xen/bin/qemu-dm", ['pc', 'isapc']]], {})
]
@ -89,7 +85,7 @@ class TestCapabilities(unittest.TestCase):
def testCapabilities2(self):
host = ('x86_64', {})
secmodel = ('selinux', '0', None)
secmodel = ('selinux', None)
guests = [
('x86_64', 'hvm',
@ -129,18 +125,17 @@ class TestCapabilities(unittest.TestCase):
['g3bw', 'mac99', 'prep']]], {}),
]
secmodel = ('dac', '0', {"kvm" : "+0:+0", "qemu" : "+0:+0"})
secmodel = ('dac', {"kvm" : "+0:+0", "qemu" : "+0:+0"})
self._testCapabilities("capabilities-kvm.xml", host, guests, secmodel)
def testCapabilities4(self):
host = ('i686',
{'pae': capabilities.FEATURE_ON | capabilities.FEATURE_OFF})
host = ('i686', {'pae': True, 'nonpae': True})
guests = [
('i686', 'linux',
[['test', None, []]],
{'pae': capabilities.FEATURE_ON | capabilities.FEATURE_OFF}),
{'pae': True, 'nonpae': True}),
]
self._testCapabilities("capabilities-test.xml", host, guests)
@ -166,36 +161,33 @@ class TestCapabilities(unittest.TestCase):
def testCapsCPUFeaturesOldSyntax(self):
filename = "rhel5.4-xen-caps-virt-enabled.xml"
host_feature_list = ["vmx"]
feature_dict = build_host_feature_dict(host_feature_list)
caps = self._buildCaps(filename)
for f in feature_dict.keys():
self.assertEquals(caps.host.cpu.features[f], feature_dict[f])
for f in host_feature_list:
self.assertEquals(caps.host.cpu.has_feature(f), True)
def testCapsCPUFeaturesOldSyntaxSVM(self):
filename = "rhel5.4-xen-caps.xml"
host_feature_list = ["svm"]
feature_dict = build_host_feature_dict(host_feature_list)
caps = self._buildCaps(filename)
for f in feature_dict.keys():
self.assertEquals(caps.host.cpu.features[f], feature_dict[f])
for f in host_feature_list:
self.assertEquals(caps.host.cpu.has_feature(f), True)
def testCapsCPUFeaturesNewSyntax(self):
filename = "libvirt-0.7.6-qemu-caps.xml"
host_feature_list = ['lahf_lm', 'xtpr', 'cx16', 'tm2', 'est', 'vmx',
'ds_cpl', 'pbe', 'tm', 'ht', 'ss', 'acpi', 'ds']
feature_dict = build_host_feature_dict(host_feature_list)
'ds_cpl', 'pbe', 'tm', 'ht', 'ss', 'acpi', 'ds']
caps = self._buildCaps(filename)
for f in feature_dict.keys():
self.assertEquals(caps.host.cpu.features[f], feature_dict[f])
for f in host_feature_list:
self.assertEquals(caps.host.cpu.has_feature(f), True)
self.assertEquals(caps.host.cpu.model, "core2duo")
self.assertEquals(caps.host.cpu.vendor, "Intel")
self.assertEquals(caps.host.cpu.threads, "3")
self.assertEquals(caps.host.cpu.cores, "5")
self.assertEquals(caps.host.cpu.sockets, "7")
self.assertEquals(caps.host.cpu.threads, 3)
self.assertEquals(caps.host.cpu.cores, 5)
self.assertEquals(caps.host.cpu.sockets, 7)
def testCapsUtilFuncs(self):
new_caps = self._buildCaps("libvirt-0.7.6-qemu-caps.xml")
@ -246,7 +238,6 @@ class TestCapabilities(unittest.TestCase):
test_cpu_map(cpu_64, x86_cpunames)
test_cpu_map(cpu_random, [])
conn = utils.open_testdriver()
cpu_64 = caps.get_cpu_values(conn, "x86_64")
self.assertTrue(len(cpu_64) > 0)

View File

@ -972,7 +972,7 @@ class vmmConnection(vmmGObject):
self._backend.daemon_version())
logging.debug("conn version=%s", self._backend.conn_version())
logging.debug("%s capabilities:\n%s",
self.get_uri(), self.caps.xml)
self.get_uri(), self.caps.get_xml_config())
self._add_conn_events()
# Prime CPU cache

View File

@ -51,7 +51,7 @@ from virtinst.seclabel import Seclabel
from virtinst.pm import PM
from virtinst.idmap import IdMap
from virtinst import capabilities as CapabilitiesParser
from virtinst.capabilities import Capabilities
from virtinst.domcapabilities import DomainCapabilities
from virtinst.interface import Interface, InterfaceProtocol
from virtinst.network import Network

View File

@ -22,17 +22,14 @@
import re
from . import util
# Whether a guest can be created with a certain feature on resp. off
FEATURE_ON = 0x01
FEATURE_OFF = 0x02
from .cpu import CPU as DomainCPU
from .xmlbuilder import XMLBuilder, XMLChildProperty
from .xmlbuilder import XMLProperty as _XMLProperty
def xpathString(node, path, default=None):
result = node.xpathEval("string(%s)" % path)
if len(result) == 0:
result = default
return result
# Disable test suite property tracking
class XMLProperty(_XMLProperty):
_track = False
class CPUValuesModel(object):
@ -141,252 +138,109 @@ class _CPUMapFileValues(_CPUAPIValues):
return cpumap.cpus
class Features(object):
"""Represent a set of features. For each feature, store a bit mask of
FEATURE_ON and FEATURE_OFF to indicate whether the feature can
be turned on or off. For features for which toggling doesn't make sense
(e.g., 'vmx') store FEATURE_ON when the feature is present."""
class _CapsCPU(DomainCPU):
arch = XMLProperty("./arch")
def __init__(self, node=None):
self.features = {}
if node is not None:
self.parseXML(node)
# capabilities used to just expose these properties as bools
_svm_bool = XMLProperty("./features/svm", is_bool=True)
_vmx_bool = XMLProperty("./features/vmx", is_bool=True)
_pae_bool = XMLProperty("./features/pae", is_bool=True)
_nonpae_bool = XMLProperty("./features/nonpae", is_bool=True)
def __getitem__(self, feature):
if feature in self.features:
return self.features[feature]
return 0
def names(self):
return self.features.keys()
def parseXML(self, node):
d = self.features
feature_list = []
if node.name == "features":
node_list = node.xpathEval("*")
for n in node_list:
feature_list.append(n.name)
else:
# New style features
node_list = node.xpathEval("feature/@name")
for n in node_list:
feature_list.append(n.content)
for feature in feature_list:
if feature not in d:
d[feature] = 0
self._extractFeature(feature, d, n)
def _extractFeature(self, feature, d, node):
"""Extract the value of FEATURE from NODE and set DICT[FEATURE] to
its value. Abstract method, must be overridden"""
raise NotImplementedError("Abstract base class")
has_feature_block = XMLProperty("./features", is_bool=True)
class CapabilityFeatures(Features):
def __init__(self, node=None):
Features.__init__(self, node)
##############
# Public API #
##############
def _extractFeature(self, feature, d, n):
default = xpathString(n, "@default")
toggle = xpathString(n, "@toggle")
def has_feature(self, name):
if name == "svm" and self._svm_bool:
return True
if name == "vmx" and self._vmx_bool:
return True
if name == "pae" and self._pae_bool:
return True
if name == "nonpae" and self._nonpae_bool:
return True
if default is not None:
# Format for guest features
if default == "on":
d[feature] = FEATURE_ON
elif default == "off":
d[feature] = FEATURE_OFF
else:
raise RuntimeError("Feature %s: value of default must "
"be 'on' or 'off', but is '%s'" %
(feature, default))
if toggle == "yes":
d[feature] |= d[feature] ^ (FEATURE_ON | FEATURE_OFF)
else:
# Format for old HOST features, on OLD old guest features
# back compat is just <$featurename>, like <svm/>
if feature == "nonpae":
d["pae"] |= FEATURE_OFF
else:
d[feature] |= FEATURE_ON
return name in [f.name for f in self.features]
class CPU(object):
def __init__(self, node=None):
# e.g. "i686" or "x86_64"
self.arch = None
self.model = None
self.vendor = None
self.sockets = 1
self.cores = 1
self.threads = 1
self.features = CapabilityFeatures()
###########################
# Caps <topology> parsers #
###########################
if node is not None:
self.parseXML(node)
def parseXML(self, node):
newstyle_features = False
child = node.children
while child:
# Do a first pass to try and detect new style features
if child.name == "feature":
newstyle_features = True
break
child = child.next
if newstyle_features:
self.features = CapabilityFeatures(node)
child = node.children
while child:
if child.name == "arch":
self.arch = child.content
elif child.name == "model":
self.model = child.content
elif child.name == "vendor":
self.vendor = child.content
elif child.name == "topology":
self.sockets = xpathString(child, "@sockets") or 1
self.cores = xpathString(child, "@cores") or 1
self.threads = xpathString(child, "@threads") or 1
elif child.name == "features" and not newstyle_features:
self.features = CapabilityFeatures(child)
child = child.next
class _CapsTopologyCPU(XMLBuilder):
_XML_ROOT_NAME = "cpu"
id = XMLProperty("./@id")
class Host(object):
def __init__(self, node=None):
self.cpu = CPU()
self.topology = None
self.secmodels = []
if node is not None:
self.parseXML(node)
def get_secmodel(self):
return self.secmodels and self.secmodels[0] or None
secmodel = property(get_secmodel)
def parseXML(self, node):
child = node.children
while child:
if child.name == "topology":
self.topology = Topology(child)
if child.name == "secmodel":
self.secmodels.append(SecurityModel(child))
if child.name == "cpu":
self.cpu = CPU(child)
child = child.next
class _TopologyCell(XMLBuilder):
_XML_ROOT_NAME = "cell"
id = XMLProperty("./@id")
cpus = XMLChildProperty(_CapsTopologyCPU, relative_xpath="./cpus")
class Guest(object):
def __init__(self, node=None):
# e.g. "xen" or "hvm"
self.os_type = None
# e.g. "i686" or "x86_64"
self.arch = None
self.domains = []
self.features = CapabilityFeatures()
if node is not None:
self.parseXML(node)
def parseXML(self, node):
child = node.children
while child:
if child.name == "os_type":
self.os_type = child.content
elif child.name == "features":
self.features = CapabilityFeatures(child)
elif child.name == "arch":
self.arch = child.prop("name")
machines = []
emulator = None
loader = None
n = child.children
while n:
if n.name == "machine":
machines.append(n.content)
canon = n.prop("canonical")
if canon:
machines.append(canon)
elif n.name == "emulator":
emulator = n.content
elif n.name == "loader":
loader = n.content
n = n.next
n = child.children
while n:
if n.name == "domain":
self.domains.append(Domain(n.prop("type"),
emulator, loader, machines, n))
n = n.next
child = child.next
def _favoredDomain(self, domains):
"""
Return the recommended domain for use if the user does not explicitly
request one.
"""
if not domains:
return None
priority = ["kvm", "xen", "kqemu", "qemu"]
for t in priority:
for d in domains:
if d.hypervisor_type == t:
return d
# Fallback, just return last item in list
return domains[-1]
def bestDomainType(self, dtype=None, machine=None):
domains = []
for d in self.domains:
d.set_recommended_machine(None)
if dtype and d.hypervisor_type != dtype.lower():
continue
if machine and machine not in d.machines:
continue
if machine:
d.set_recommended_machine(machine)
domains.append(d)
return self._favoredDomain(domains)
class _CapsTopology(XMLBuilder):
_XML_ROOT_NAME = "topology"
cells = XMLChildProperty(_TopologyCell, relative_xpath="./cells")
class Domain(object):
def __init__(self, hypervisor_type,
emulator=None, loader=None,
machines=None, node=None):
self.hypervisor_type = hypervisor_type
self.emulator = emulator
self.loader = loader
self.machines = machines
######################################
# Caps <host> and <secmodel> parsers #
######################################
class _CapsSecmodelBaselabel(XMLBuilder):
_XML_ROOT_NAME = "baselabel"
type = XMLProperty("./@type")
content = XMLProperty(".")
class _CapsSecmodel(XMLBuilder):
_XML_ROOT_NAME = "secmodel"
model = XMLProperty("./model")
baselabels = XMLChildProperty(_CapsSecmodelBaselabel)
class _CapsHost(XMLBuilder):
_XML_ROOT_NAME = "host"
secmodels = XMLChildProperty(_CapsSecmodel)
cpu = XMLChildProperty(_CapsCPU, is_single=True)
topology = XMLChildProperty(_CapsTopology, is_single=True)
################################
# <guest> and <domain> parsers #
################################
class _CapsMachine(XMLBuilder):
_XML_ROOT_NAME = "machine"
name = XMLProperty(".")
canonical = XMLProperty("./@canonical")
class _CapsDomain(XMLBuilder):
def __init__(self, *args, **kwargs):
XMLBuilder.__init__(self, *args, **kwargs)
self.machines = []
for m in self._machines:
self.machines.append(m.name)
if m.canonical:
self.machines.append(m.canonical)
self._recommended_machine = None
if node is not None:
self.parseXML(node)
_XML_ROOT_NAME = "domain"
hypervisor_type = XMLProperty("./@type")
emulator = XMLProperty("./emulator")
_machines = XMLChildProperty(_CapsMachine)
###############
# Public APIs #
###############
def get_recommended_machine(self, conn, capsguest):
if self._recommended_machine:
@ -408,102 +262,102 @@ class Domain(object):
def set_recommended_machine(self, machine):
self._recommended_machine = machine
def parseXML(self, node):
child = node.children
machines = []
while child:
if child.name == "emulator":
self.emulator = child.content
elif child.name == "machine":
machines.append(child.content)
canon = child.prop("canonical")
if canon:
machines.append(canon)
machines.append(child.content)
child = child.next
if len(machines) > 0:
self.machines = machines
def is_accelerated(self):
return self.hypervisor_type in ["kvm", "kqemu"]
class Topology(object):
def __init__(self, node=None):
self.cells = []
class _CapsGuestFeatures(XMLBuilder):
_XML_ROOT_NAME = "features"
if node is not None:
self.parseXML(node)
def parseXML(self, node):
child = node.children
if child.name == "cells":
for cell in child.children:
if cell.name == "cell":
self.cells.append(TopologyCell(cell))
pae = XMLProperty("./pae", is_bool=True)
nonpae = XMLProperty("./nonpae", is_bool=True)
acpi = XMLProperty("./acpi", is_bool=True)
apic = XMLProperty("./apci", is_bool=True)
class TopologyCell(object):
def __init__(self, node=None):
self.id = None
self.cpus = []
class _CapsGuest(XMLBuilder):
def __init__(self, *args, **kwargs):
XMLBuilder.__init__(self, *args, **kwargs)
if node is not None:
self.parseXML(node)
self.machines = []
for m in self._machines:
self.machines.append(m.name)
if m.canonical:
self.machines.append(m.canonical)
def parseXML(self, node):
self.id = int(node.prop("id"))
for child in node.children:
if child.name == "cpus":
for cpu in child.children:
if cpu.name == "cpu":
self.cpus.append(TopologyCPU(cpu))
for d in self.domains:
if not d.emulator:
d.emulator = self.emulator
if not d.machines:
d.machines = self.machines
class TopologyCPU(object):
def __init__(self, node=None):
self.id = None
_XML_ROOT_NAME = "guest"
if node is not None:
self.parseXML(node)
os_type = XMLProperty("./os_type")
arch = XMLProperty("./arch/@name")
loader = XMLProperty("./arch/loader")
emulator = XMLProperty("./arch/emulator")
def parseXML(self, node):
self.id = int(node.prop("id"))
domains = XMLChildProperty(_CapsDomain, relative_xpath="./arch")
features = XMLChildProperty(_CapsGuestFeatures, is_single=True)
_machines = XMLChildProperty(_CapsMachine, relative_xpath="./arch")
class SecurityModel(object):
def __init__(self, node=None):
self.model = None
self.doi = None
self.baselabels = {}
###############
# Public APIs #
###############
if node is not None:
self.parseXML(node)
def bestDomainType(self, dtype=None, machine=None):
"""
Return the recommended domain for use if the user does not explicitly
request one.
"""
domains = []
for d in self.domains:
d.set_recommended_machine(None)
def parseXML(self, node):
for child in node.children or []:
if child.name == "model":
self.model = child.content
elif child.name == "doi":
self.doi = child.content
elif child.name == "baselabel":
typ = child.prop("type")
self.baselabels[typ] = child.content
if dtype and d.hypervisor_type != dtype.lower():
continue
if machine and machine not in d.machines:
continue
if machine:
d.set_recommended_machine(machine)
domains.append(d)
if not domains:
return None
priority = ["kvm", "xen", "kqemu", "qemu"]
for t in priority:
for d in domains:
if d.hypervisor_type == t:
return d
# Fallback, just return last item in list
return domains[-1]
class Capabilities(object):
def __init__(self, xml):
self.host = None
self.guests = []
self.xml = xml
self._topology = None
############################
# Main capabilities object #
############################
class Capabilities(XMLBuilder):
def __init__(self, *args, **kwargs):
XMLBuilder.__init__(self, *args, **kwargs)
self._cpu_values = None
util.parse_node_helper(self.xml, "capabilities",
self.parseXML,
RuntimeError)
_XML_ROOT_NAME = "capabilities"
host = XMLChildProperty(_CapsHost, is_single=True)
guests = XMLChildProperty(_CapsGuest)
###################
# Private helpers #
###################
def _is_xen(self):
for g in self.guests:
@ -516,6 +370,11 @@ class Capabilities(object):
return False
##############
# Public API #
##############
def no_install_options(self):
"""
Return True if there are no install options available
@ -534,17 +393,17 @@ class Capabilities(object):
sufficiently provided, so we will return True in cases that we
aren't sure.
"""
# Obvious case of feature being specified
if (self.host.cpu.has_feature("vmx") or
self.host.cpu.has_feature("svm")):
return True
has_hvm_guests = False
for g in self.guests:
if g.os_type == "hvm":
has_hvm_guests = True
break
# Obvious case of feature being specified
if (self.host.cpu.features["vmx"] == FEATURE_ON or
self.host.cpu.features["svm"] == FEATURE_ON):
return True
# Xen seems to block the vmx/svm feature bits from cpuinfo?
# so make sure no hvm guests are listed
if self._is_xen() and has_hvm_guests:
@ -552,7 +411,7 @@ class Capabilities(object):
# If there is other features, but no virt bit, then HW virt
# isn't supported
if len(self.host.cpu.features.names()):
if self.host.cpu.has_feature_block:
return False
# Xen caps have always shown this info, so if we didn't find any
@ -617,36 +476,15 @@ class Capabilities(object):
return True
def support_pae(self):
def supports_pae(self):
"""
Return True if capabilities report support for PAE
"""
for g in self.guests:
if "pae" in g.features.names():
if g.features.pae:
return True
return False
def _guestForOSType(self, typ=None, arch=None):
if self.host is None:
return None
if arch is None:
archs = [self.host.cpu.arch, None]
else:
archs = [arch]
for a in archs:
for g in self.guests:
if (typ is None or g.os_type == typ) and \
(a is None or g.arch == a):
return g
def parseXML(self, node):
child = node.children
while child:
if child.name == "host":
self.host = Host(child)
elif child.name == "guest":
self.guests.append(Guest(child))
child = child.next
def get_cpu_values(self, conn, arch):
if not arch:
return []
@ -663,6 +501,25 @@ class Capabilities(object):
return []
############################
# Public XML building APIs #
############################
def _guestForOSType(self, typ=None, arch=None):
if self.host is None:
return None
archs = [arch]
if arch is None:
archs = [self.host.cpu.arch, None]
for a in archs:
for g in self.guests:
if ((typ is None or g.os_type == typ) and
(a is None or g.arch == a)):
return g
def guest_lookup(self, os_type=None, arch=None, typ=None, machine=None):
"""
Simple virtualization availability lookup
@ -714,12 +571,12 @@ class Capabilities(object):
return (guest, domain)
def build_virtinst_guest(self, conn, guest, domain):
from .guest import Guest as VMGuest
gobj = VMGuest(conn)
from .guest import Guest
gobj = Guest(conn)
gobj.type = domain.hypervisor_type
gobj.os.os_type = guest.os_type
gobj.os.arch = guest.arch
gobj.os.loader = domain.loader
gobj.os.loader = guest.loader
gobj.emulator = domain.emulator
gobj.os.machine = domain.get_recommended_machine(conn, guest)

View File

@ -25,8 +25,8 @@ import libvirt
from . import pollhelpers
from . import support
from . import util
from . import capabilities as CapabilitiesParser
from . import URISplit
from . import Capabilities
from .cli import VirtOptionString
from .guest import Guest
from .nodedev import NodeDevice
@ -121,8 +121,8 @@ class VirtualConnection(object):
def _get_caps(self):
if not self._caps:
self._caps = CapabilitiesParser.Capabilities(
self._libvirtconn.getCapabilities())
self._caps = Capabilities(self,
self._libvirtconn.getCapabilities())
return self._caps
caps = property(_get_caps)

View File

@ -252,12 +252,15 @@ class VirtualDisk(VirtualDevice):
from virtcli import cliconfig
user = cliconfig.default_qemu_user
try:
for i in conn.caps.host.secmodels:
if i.model != "dac":
for secmodel in conn.caps.host.secmodels:
if secmodel.model != "dac":
continue
label = (i.baselabels.get("kvm") or
i.baselabels.get("qemu"))
label = None
for baselabel in secmodel.baselabels:
if baselabel.type in ["qemu", "kvm"]:
label = baselabel.content
break
if not label:
continue

View File

@ -833,7 +833,7 @@ class Guest(XMLBuilder):
if self.features.apic == "default":
self.features.apic = self._lookup_osdict_key("apic", default)
if self.features.pae == "default":
self.features.pae = self.conn.caps.support_pae()
self.features.pae = self.conn.caps.supports_pae()
if (self._lookup_osdict_key("hyperv_features", False) and
self._hv_supported() and