mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-03-05 20:58:31 +03:00
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:
parent
0492dbc1b1
commit
cac4ac1401
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user