xmlbuilder: Track singleton child properties explicitly
Things like Guest.Seclabel, VirtualDevice.VirtualAlias, etc. Now we don't need to track a full xpath with each class, just its root name and we build its hierarchy depending on its parent.
This commit is contained in:
parent
38545e3af8
commit
0be727e6bb
|
@ -21,6 +21,6 @@ from virtinst.xmlbuilder import XMLBuilder, XMLProperty
|
|||
|
||||
|
||||
class Clock(XMLBuilder):
|
||||
_XML_ROOT_XPATH = "/domain/clock"
|
||||
_XML_ROOT_NAME = "clock"
|
||||
|
||||
offset = XMLProperty(xpath="./clock/@offset")
|
||||
offset = XMLProperty(xpath="./@offset")
|
||||
|
|
|
@ -27,7 +27,7 @@ class CPUFeature(XMLBuilder):
|
|||
|
||||
POLICIES = ["force", "require", "optional", "disable", "forbid"]
|
||||
|
||||
_XML_ROOT_XPATH = "/domain/cpu/feature"
|
||||
_XML_ROOT_NAME = "feature"
|
||||
_XML_PROP_ORDER = ["name", "policy"]
|
||||
|
||||
name = XMLProperty("./@name")
|
||||
|
@ -41,7 +41,7 @@ class CPU(XMLBuilder):
|
|||
|
||||
MATCHS = ["minimum", "exact", "strict"]
|
||||
|
||||
_XML_ROOT_XPATH = "/domain/cpu"
|
||||
_XML_ROOT_NAME = "cpu"
|
||||
_XML_PROP_ORDER = ["mode", "match", "model", "vendor",
|
||||
"sockets", "cores", "threads", "features"]
|
||||
|
||||
|
@ -131,12 +131,12 @@ class CPU(XMLBuilder):
|
|||
if not self.match:
|
||||
self.match = "exact"
|
||||
return val
|
||||
model = XMLProperty(xpath="./cpu/model", set_converter=_set_model)
|
||||
model = XMLProperty(xpath="./model", set_converter=_set_model)
|
||||
|
||||
match = XMLProperty(xpath="./cpu/@match")
|
||||
vendor = XMLProperty(xpath="./cpu/vendor")
|
||||
mode = XMLProperty(xpath="./cpu/@mode")
|
||||
match = XMLProperty(xpath="./@match")
|
||||
vendor = XMLProperty(xpath="./vendor")
|
||||
mode = XMLProperty(xpath="./@mode")
|
||||
|
||||
sockets = XMLProperty(xpath="./cpu/topology/@sockets", is_int=True)
|
||||
cores = XMLProperty(xpath="./cpu/topology/@cores", is_int=True)
|
||||
threads = XMLProperty(xpath="./cpu/topology/@threads", is_int=True)
|
||||
sockets = XMLProperty(xpath="./topology/@sockets", is_int=True)
|
||||
cores = XMLProperty(xpath="./topology/@cores", is_int=True)
|
||||
threads = XMLProperty(xpath="./topology/@threads", is_int=True)
|
||||
|
|
|
@ -19,7 +19,65 @@
|
|||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301 USA.
|
||||
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLProperty
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
|
||||
|
||||
|
||||
class VirtualDeviceAlias(XMLBuilder):
|
||||
_XML_ROOT_NAME = "alias"
|
||||
name = XMLProperty(xpath="./@name")
|
||||
|
||||
|
||||
class VirtualDeviceAddress(XMLBuilder):
|
||||
"""
|
||||
Examples:
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||
<address type='drive' controller='0' bus='0' unit='0'/>
|
||||
<address type='ccid' controller='0' slot='0'/>
|
||||
<address type='virtio-serial' controller='1' bus='0' port='4'/>
|
||||
"""
|
||||
|
||||
ADDRESS_TYPE_PCI = "pci"
|
||||
ADDRESS_TYPE_DRIVE = "drive"
|
||||
ADDRESS_TYPE_VIRTIO_SERIAL = "virtio-serial"
|
||||
ADDRESS_TYPE_CCID = "ccid"
|
||||
ADDRESS_TYPE_SPAPR_VIO = "spapr-vio"
|
||||
|
||||
TYPES = [ADDRESS_TYPE_PCI, ADDRESS_TYPE_DRIVE,
|
||||
ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID,
|
||||
ADDRESS_TYPE_SPAPR_VIO]
|
||||
|
||||
_XML_ROOT_NAME = "address"
|
||||
_XML_PROP_ORDER = ["type", "domain", "controller", "bus", "slot",
|
||||
"function", "target", "unit", "multifunction"]
|
||||
|
||||
def set_addrstr(self, addrstr):
|
||||
if addrstr is None:
|
||||
return
|
||||
|
||||
if addrstr.count(":") in [1, 2] and addrstr.count("."):
|
||||
self.type = self.ADDRESS_TYPE_PCI
|
||||
addrstr, self.function = addrstr.split(".", 1)
|
||||
addrstr, self.slot = addrstr.rsplit(":", 1)
|
||||
self.domain = "0"
|
||||
if addrstr.count(":"):
|
||||
self.domain, self.bus = addrstr.split(":", 1)
|
||||
elif addrstr == "spapr-vio":
|
||||
self.type = self.ADDRESS_TYPE_SPAPR_VIO
|
||||
else:
|
||||
raise ValueError(_("Could not determine or unsupported "
|
||||
"format of '%s'") % addrstr)
|
||||
|
||||
|
||||
type = XMLProperty(xpath="./@type")
|
||||
domain = XMLProperty(xpath="./@domain", is_int=True)
|
||||
bus = XMLProperty(xpath="./@bus", is_int=True)
|
||||
slot = XMLProperty(xpath="./@slot", is_int=True)
|
||||
function = XMLProperty(xpath="./@function", is_int=True)
|
||||
controller = XMLProperty(xpath="./@controller", is_int=True)
|
||||
unit = XMLProperty(xpath="./@unit", is_int=True)
|
||||
port = XMLProperty(xpath="./@port", is_int=True)
|
||||
target = XMLProperty(xpath="./@target", is_int=True)
|
||||
multifunction = XMLProperty(xpath="./@multifunction", is_onoff=True)
|
||||
|
||||
|
||||
class VirtualDevice(XMLBuilder):
|
||||
|
@ -71,23 +129,19 @@ class VirtualDevice(XMLBuilder):
|
|||
|
||||
@classmethod
|
||||
def register_type(cls):
|
||||
cls._XML_ROOT_XPATH = "/domain/devices/%s" % cls.virtual_device_type
|
||||
cls._XML_ROOT_NAME = cls.virtual_device_type
|
||||
VirtualDevice.virtual_device_classes[cls.virtual_device_type] = cls
|
||||
|
||||
# General device type (disk, interface, etc.)
|
||||
virtual_device_type = None
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Initialize device state
|
||||
|
||||
@param conn: libvirt connection to validate device against
|
||||
"""
|
||||
|
||||
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
|
||||
|
||||
self.alias = VirtualDeviceAlias(conn, parsexmlnode=parsexmlnode)
|
||||
self.address = VirtualDeviceAddress(conn, parsexmlnode=parsexmlnode)
|
||||
XMLBuilder.__init__(self, *args, **kwargs)
|
||||
self._XML_PROP_ORDER = self._XML_PROP_ORDER + ["alias", "address"]
|
||||
|
||||
if not self.virtual_device_type:
|
||||
|
@ -97,6 +151,9 @@ class VirtualDevice(XMLBuilder):
|
|||
raise ValueError(_("Unknown virtual device type '%s'.") %
|
||||
self.virtual_device_type)
|
||||
|
||||
alias = XMLChildProperty(VirtualDeviceAlias, is_single=True)
|
||||
address = XMLChildProperty(VirtualDeviceAddress, is_single=True)
|
||||
|
||||
|
||||
def setup(self, meter=None):
|
||||
"""
|
||||
|
@ -108,61 +165,3 @@ class VirtualDevice(XMLBuilder):
|
|||
# Will be overwritten by subclasses if necessary.
|
||||
ignore = meter
|
||||
return
|
||||
|
||||
|
||||
class VirtualDeviceAlias(XMLBuilder):
|
||||
_XML_ROOT_XPATH = "/alias"
|
||||
name = XMLProperty(xpath="./alias/@name")
|
||||
|
||||
|
||||
class VirtualDeviceAddress(XMLBuilder):
|
||||
"""
|
||||
Examples:
|
||||
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
|
||||
<address type='drive' controller='0' bus='0' unit='0'/>
|
||||
<address type='ccid' controller='0' slot='0'/>
|
||||
<address type='virtio-serial' controller='1' bus='0' port='4'/>
|
||||
"""
|
||||
|
||||
ADDRESS_TYPE_PCI = "pci"
|
||||
ADDRESS_TYPE_DRIVE = "drive"
|
||||
ADDRESS_TYPE_VIRTIO_SERIAL = "virtio-serial"
|
||||
ADDRESS_TYPE_CCID = "ccid"
|
||||
ADDRESS_TYPE_SPAPR_VIO = "spapr-vio"
|
||||
|
||||
TYPES = [ADDRESS_TYPE_PCI, ADDRESS_TYPE_DRIVE,
|
||||
ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID,
|
||||
ADDRESS_TYPE_SPAPR_VIO]
|
||||
|
||||
_XML_ROOT_XPATH = "/address"
|
||||
_XML_PROP_ORDER = ["type", "domain", "controller", "bus", "slot",
|
||||
"function", "target", "unit", "multifunction"]
|
||||
|
||||
def set_addrstr(self, addrstr):
|
||||
if addrstr is None:
|
||||
return
|
||||
|
||||
if addrstr.count(":") in [1, 2] and addrstr.count("."):
|
||||
self.type = self.ADDRESS_TYPE_PCI
|
||||
addrstr, self.function = addrstr.split(".", 1)
|
||||
addrstr, self.slot = addrstr.rsplit(":", 1)
|
||||
self.domain = "0"
|
||||
if addrstr.count(":"):
|
||||
self.domain, self.bus = addrstr.split(":", 1)
|
||||
elif addrstr == "spapr-vio":
|
||||
self.type = self.ADDRESS_TYPE_SPAPR_VIO
|
||||
else:
|
||||
raise ValueError(_("Could not determine or unsupported "
|
||||
"format of '%s'") % addrstr)
|
||||
|
||||
|
||||
type = XMLProperty(xpath="./address/@type")
|
||||
domain = XMLProperty(xpath="./address/@domain", is_int=True)
|
||||
bus = XMLProperty(xpath="./address/@bus", is_int=True)
|
||||
slot = XMLProperty(xpath="./address/@slot", is_int=True)
|
||||
function = XMLProperty(xpath="./address/@function", is_int=True)
|
||||
controller = XMLProperty(xpath="./address/@controller", is_int=True)
|
||||
unit = XMLProperty(xpath="./address/@unit", is_int=True)
|
||||
port = XMLProperty(xpath="./address/@port", is_int=True)
|
||||
target = XMLProperty(xpath="./address/@target", is_int=True)
|
||||
multifunction = XMLProperty(xpath="./address/@multifunction", is_onoff=True)
|
||||
|
|
|
@ -397,8 +397,8 @@ class VirtualDisk(VirtualDevice):
|
|||
"_xmlpath", "target", "bus",
|
||||
]
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
VirtualDevice.__init__(self, conn, parsexml, parsexmlnode)
|
||||
def __init__(self, *args, **kwargs):
|
||||
VirtualDevice.__init__(self, *args, **kwargs)
|
||||
|
||||
self.__storage_backend = None
|
||||
self._storage_creator = None
|
||||
|
|
|
@ -94,8 +94,8 @@ class VirtualGraphics(VirtualDevice):
|
|||
|
||||
return str(gtype).capitalize()
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
VirtualDevice.__init__(self, conn, parsexml, parsexmlnode)
|
||||
def __init__(self, *args, **kwargs):
|
||||
VirtualDevice.__init__(self, *args, **kwargs)
|
||||
|
||||
self._local_keymap = -1
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import random
|
|||
|
||||
from virtinst import util
|
||||
from virtinst import VirtualDevice
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLProperty
|
||||
from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
|
||||
|
||||
|
||||
def _random_mac(conn):
|
||||
|
@ -53,15 +53,13 @@ def _random_mac(conn):
|
|||
|
||||
|
||||
class VirtualPort(XMLBuilder):
|
||||
_XML_ROOT_XPATH = "/domain/devices/interface/virtualport"
|
||||
_XML_ROOT_NAME = "virtualport"
|
||||
|
||||
type = XMLProperty(xpath="./virtualport/@type")
|
||||
managerid = XMLProperty(xpath="./virtualport/parameters/@managerid",
|
||||
is_int=True)
|
||||
typeid = XMLProperty(xpath="./virtualport/parameters/@typeid", is_int=True)
|
||||
typeidversion = XMLProperty(
|
||||
xpath="./virtualport/parameters/@typeidversion", is_int=True)
|
||||
instanceid = XMLProperty(xpath="./virtualport/parameters/@instanceid")
|
||||
type = XMLProperty("./@type")
|
||||
managerid = XMLProperty("./parameters/@managerid", is_int=True)
|
||||
typeid = XMLProperty("./parameters/@typeid", is_int=True)
|
||||
typeidversion = XMLProperty("./parameters/@typeidversion", is_int=True)
|
||||
instanceid = XMLProperty("./parameters/@instanceid")
|
||||
|
||||
|
||||
class VirtualNetworkInterface(VirtualDevice):
|
||||
|
@ -133,15 +131,12 @@ class VirtualNetworkInterface(VirtualDevice):
|
|||
return (False, None)
|
||||
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
VirtualDevice.__init__(self, conn, parsexml, parsexmlnode)
|
||||
|
||||
self.virtualport = VirtualPort(conn, parsexml, parsexmlnode)
|
||||
def __init__(self, *args, **kwargs):
|
||||
VirtualDevice.__init__(self, *args, **kwargs)
|
||||
|
||||
self._random_mac = None
|
||||
self._default_bridge = None
|
||||
|
||||
|
||||
def _generate_default_bridge(self):
|
||||
ret = self._default_bridge
|
||||
if ret is None:
|
||||
|
@ -201,6 +196,7 @@ class VirtualNetworkInterface(VirtualDevice):
|
|||
"macaddr", "target_dev", "model", "virtualport",
|
||||
"filterref"]
|
||||
|
||||
virtualport = XMLChildProperty(VirtualPort, is_single=True)
|
||||
type = XMLProperty(xpath="./@type",
|
||||
default_cb=lambda s: s.TYPE_BRIDGE)
|
||||
|
||||
|
|
|
@ -24,16 +24,16 @@ class DomainFeatures(XMLBuilder):
|
|||
"""
|
||||
Class for generating <features> XML
|
||||
"""
|
||||
_XML_ROOT_XPATH = "/domain/features"
|
||||
_XML_ROOT_NAME = "features"
|
||||
_XML_PROP_ORDER = ["acpi", "apic", "pae"]
|
||||
|
||||
acpi = XMLProperty(xpath="./features/acpi", is_bool=True,
|
||||
acpi = XMLProperty(xpath="./acpi", is_bool=True,
|
||||
default_name="default",
|
||||
default_cb=lambda s: False)
|
||||
apic = XMLProperty(xpath="./features/apic", is_bool=True,
|
||||
apic = XMLProperty(xpath="./apic", is_bool=True,
|
||||
default_name="default",
|
||||
default_cb=lambda s: False)
|
||||
pae = XMLProperty(xpath="./features/pae", is_bool=True,
|
||||
pae = XMLProperty(xpath="./pae", is_bool=True,
|
||||
default_name="default",
|
||||
default_cb=lambda s: False)
|
||||
|
||||
|
|
|
@ -146,8 +146,8 @@ class DomainNumatune(XMLBuilder):
|
|||
|
||||
MEMORY_MODES = ["interleave", "strict", "preferred"]
|
||||
|
||||
_XML_ROOT_XPATH = "/domain/numatune"
|
||||
_XML_ROOT_NAME = "numatune"
|
||||
_XML_PROP_ORDER = ["memory_mode", "memory_nodeset"]
|
||||
|
||||
memory_nodeset = XMLProperty(xpath="./numatune/memory/@nodeset")
|
||||
memory_mode = XMLProperty(xpath="./numatune/memory/@mode")
|
||||
memory_nodeset = XMLProperty(xpath="./memory/@nodeset")
|
||||
memory_mode = XMLProperty(xpath="./memory/@mode")
|
||||
|
|
|
@ -84,15 +84,15 @@ class Guest(XMLBuilder):
|
|||
raise ValueError(_("Guest name '%s' is already in use.") % name)
|
||||
|
||||
|
||||
_XML_ROOT_XPATH = "/domain"
|
||||
_XML_ROOT_NAME = "domain"
|
||||
_XML_PROP_ORDER = ["type", "name", "uuid", "description",
|
||||
"maxmemory", "memory", "hugepage", "vcpus", "curvcpus",
|
||||
"numatune", "bootloader", "os", "features", "cpu", "clock",
|
||||
"on_poweroff", "on_reboot", "on_crash", "emulator", "all_devices",
|
||||
"seclabel"]
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
XMLBuilder.__init__(self, conn, parsexml, parsexmlnode)
|
||||
def __init__(self, *args, **kwargs):
|
||||
XMLBuilder.__init__(self, *args, **kwargs)
|
||||
|
||||
self.autostart = False
|
||||
self.replace = False
|
||||
|
@ -105,13 +105,7 @@ class Guest(XMLBuilder):
|
|||
# The libvirt virDomain object we 'Create'
|
||||
self.domain = None
|
||||
|
||||
self.installer = virtinst.DistroInstaller(conn)
|
||||
self.os = OSXML(self.conn, None, self._xml_node)
|
||||
self.features = DomainFeatures(self.conn, None, self._xml_node)
|
||||
self.clock = Clock(self.conn, None, self._xml_node)
|
||||
self.seclabel = Seclabel(self.conn, None, self._xml_node)
|
||||
self.cpu = CPU(self.conn, None, self._xml_node)
|
||||
self.numatune = DomainNumatune(self.conn, None, self._xml_node)
|
||||
self.installer = virtinst.DistroInstaller(self.conn)
|
||||
|
||||
|
||||
######################
|
||||
|
@ -173,6 +167,13 @@ class Guest(XMLBuilder):
|
|||
on_reboot = XMLProperty(xpath="./on_reboot")
|
||||
on_crash = XMLProperty(xpath="./on_crash")
|
||||
|
||||
os = XMLChildProperty(OSXML, is_single=True)
|
||||
features = XMLChildProperty(DomainFeatures, is_single=True)
|
||||
clock = XMLChildProperty(Clock, is_single=True)
|
||||
seclabel = XMLChildProperty(Seclabel, is_single=True)
|
||||
cpu = XMLChildProperty(CPU, is_single=True)
|
||||
numatune = XMLChildProperty(DomainNumatune, is_single=True)
|
||||
|
||||
|
||||
###############################
|
||||
# Distro detection properties #
|
||||
|
@ -225,7 +226,8 @@ class Guest(XMLBuilder):
|
|||
return newlist
|
||||
_devices = XMLChildProperty(
|
||||
[VirtualDevice.virtual_device_classes[_n]
|
||||
for _n in VirtualDevice.virtual_device_types])
|
||||
for _n in VirtualDevice.virtual_device_types],
|
||||
relative_xpath="./devices")
|
||||
|
||||
def get_all_devices(self):
|
||||
"""
|
||||
|
@ -266,11 +268,14 @@ class Guest(XMLBuilder):
|
|||
# We do a shallow copy of the device list here, and set the defaults.
|
||||
# This way, default changes aren't persistent, and we don't need
|
||||
# to worry about when to call set_defaults
|
||||
#
|
||||
# XXX: this is hacky, we should find a way to use xmlbuilder.copy(),
|
||||
# but need to make sure it's not a massive performance hit
|
||||
data = (self._devices[:], self.features, self.os)
|
||||
try:
|
||||
self._propstore["_devices"] = [dev.copy() for dev in self._devices]
|
||||
self.features = self.features.copy()
|
||||
self.os = self.os.copy()
|
||||
self._propstore["features"] = self.features.copy()
|
||||
self._propstore["os"] = self.os.copy()
|
||||
support.set_rhel6(self._is_rhel6())
|
||||
except:
|
||||
self._finish_get_xml(data)
|
||||
|
@ -278,7 +283,9 @@ class Guest(XMLBuilder):
|
|||
return data
|
||||
|
||||
def _finish_get_xml(self, data):
|
||||
self._propstore["_devices"], self.features, self.os = data
|
||||
(self._propstore["_devices"],
|
||||
self._propstore["features"],
|
||||
self._propstore["os"]) = data
|
||||
support.set_rhel6(False)
|
||||
|
||||
def get_install_xml(self, *args, **kwargs):
|
||||
|
|
|
@ -21,7 +21,7 @@ from virtinst.xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty
|
|||
|
||||
|
||||
class _BootDevice(XMLBuilder):
|
||||
_XML_ROOT_XPATH = "/domain/os/boot"
|
||||
_XML_ROOT_NAME = "boot"
|
||||
dev = XMLProperty("./@dev")
|
||||
|
||||
|
||||
|
@ -54,7 +54,7 @@ class OSXML(XMLBuilder):
|
|||
def is_pseries(self):
|
||||
return self.is_ppc64 and self.machine == "pseries"
|
||||
|
||||
_XML_ROOT_XPATH = "/domain/os"
|
||||
_XML_ROOT_NAME = "os"
|
||||
_XML_PROP_ORDER = ["arch", "os_type", "loader",
|
||||
"kernel", "initrd", "kernel_args", "dtb",
|
||||
"_bootdevs"]
|
||||
|
@ -72,17 +72,17 @@ class OSXML(XMLBuilder):
|
|||
_bootdevs = XMLChildProperty(_BootDevice)
|
||||
bootorder = property(_get_bootorder, _set_bootorder)
|
||||
|
||||
enable_bootmenu = XMLProperty(xpath="./os/bootmenu/@enable", is_yesno=True)
|
||||
useserial = XMLProperty(xpath="./os/bios/@useserial", is_yesno=True)
|
||||
enable_bootmenu = XMLProperty(xpath="./bootmenu/@enable", is_yesno=True)
|
||||
useserial = XMLProperty(xpath="./bios/@useserial", is_yesno=True)
|
||||
|
||||
kernel = XMLProperty(xpath="./os/kernel")
|
||||
initrd = XMLProperty(xpath="./os/initrd")
|
||||
kernel_args = XMLProperty(xpath="./os/cmdline")
|
||||
dtb = XMLProperty(xpath="./os/dtb")
|
||||
kernel = XMLProperty(xpath="./kernel")
|
||||
initrd = XMLProperty(xpath="./initrd")
|
||||
kernel_args = XMLProperty(xpath="./cmdline")
|
||||
dtb = XMLProperty(xpath="./dtb")
|
||||
|
||||
init = XMLProperty(xpath="./os/init")
|
||||
loader = XMLProperty(xpath="./os/loader")
|
||||
arch = XMLProperty(xpath="./os/type/@arch",
|
||||
init = XMLProperty(xpath="./init")
|
||||
loader = XMLProperty(xpath="./loader")
|
||||
arch = XMLProperty(xpath="./type/@arch",
|
||||
default_cb=lambda s: s.conn.caps.host.arch)
|
||||
machine = XMLProperty(xpath="./os/type/@machine")
|
||||
os_type = XMLProperty(xpath="./os/type", default_cb=lambda s: "xen")
|
||||
machine = XMLProperty(xpath="./type/@machine")
|
||||
os_type = XMLProperty(xpath="./type", default_cb=lambda s: "xen")
|
||||
|
|
|
@ -38,7 +38,7 @@ class Seclabel(XMLBuilder):
|
|||
MODEL_NONE = "none"
|
||||
MODELS = [MODEL_SELINUX, MODEL_DAC, MODEL_NONE]
|
||||
|
||||
_XML_ROOT_XPATH = "/domain/seclabel"
|
||||
_XML_ROOT_NAME = "seclabel"
|
||||
_XML_PROP_ORDER = ["type", "model", "relabel", "label", "imagelabel"]
|
||||
|
||||
def _guess_secmodel(self):
|
||||
|
@ -75,7 +75,7 @@ class Seclabel(XMLBuilder):
|
|||
if self.type is None or self.type == self.TYPE_DEFAULT:
|
||||
return None
|
||||
return self._guess_secmodel()
|
||||
model = XMLProperty(xpath="./seclabel/@model",
|
||||
model = XMLProperty(xpath="./@model",
|
||||
default_cb=_get_default_model,
|
||||
default_name=MODEL_DEFAULT)
|
||||
|
||||
|
@ -83,10 +83,10 @@ class Seclabel(XMLBuilder):
|
|||
if self.model is None or self.model == self.MODEL_DEFAULT:
|
||||
return None
|
||||
return self.TYPE_DYNAMIC
|
||||
type = XMLProperty(xpath="./seclabel/@type",
|
||||
type = XMLProperty(xpath="./@type",
|
||||
default_cb=_get_default_type,
|
||||
default_name=TYPE_DEFAULT)
|
||||
|
||||
label = XMLProperty(xpath="./seclabel/label")
|
||||
imagelabel = XMLProperty(xpath="./seclabel/imagelabel")
|
||||
relabel = XMLProperty(xpath="./seclabel/@relabel", is_yesno=True)
|
||||
label = XMLProperty(xpath="./label")
|
||||
imagelabel = XMLProperty(xpath="./imagelabel")
|
||||
relabel = XMLProperty(xpath="./@relabel", is_yesno=True)
|
||||
|
|
|
@ -21,7 +21,7 @@ from virtinst.xmlbuilder import XMLBuilder, XMLProperty
|
|||
|
||||
|
||||
class DomainSnapshot(XMLBuilder):
|
||||
_XML_ROOT_XPATH = "/domainsnapshot"
|
||||
_XML_ROOT_NAME = "domainsnapshot"
|
||||
_XML_PROP_ORDER = ["name", "description", "creationTime"]
|
||||
|
||||
name = XMLProperty(xpath="./name")
|
||||
|
|
|
@ -259,9 +259,15 @@ class XMLChildProperty(property):
|
|||
interfaces rooted at /interface/bridge/interface, so we pass
|
||||
./bridge/interface here for example.
|
||||
"""
|
||||
def __init__(self, child_classes, relative_xpath="."):
|
||||
def __init__(self, child_classes, relative_xpath=".", is_single=False):
|
||||
self.child_classes = util.listify(child_classes)
|
||||
self.relative_xpath = relative_xpath
|
||||
self.is_single = is_single
|
||||
|
||||
if self.is_single and len(self.child_classes) > 1:
|
||||
raise RuntimeError("programming error: Can't specify multiple "
|
||||
"child_classes with is_single")
|
||||
|
||||
property.__init__(self, self._fget)
|
||||
|
||||
def __repr__(self):
|
||||
|
@ -273,23 +279,33 @@ class XMLChildProperty(property):
|
|||
return key
|
||||
raise RuntimeError("Didn't find expected property=%s" % self)
|
||||
|
||||
def _get_list(self, xmlbuilder):
|
||||
def _get(self, xmlbuilder):
|
||||
propname = self._findpropname(xmlbuilder)
|
||||
if propname not in xmlbuilder._propstore:
|
||||
if propname not in xmlbuilder._propstore and not self.is_single:
|
||||
xmlbuilder._propstore[propname] = []
|
||||
return xmlbuilder._propstore[propname]
|
||||
|
||||
def _fget(self, xmlbuilder):
|
||||
return self._get_list(xmlbuilder)[:]
|
||||
if self.is_single:
|
||||
return self._get(xmlbuilder)
|
||||
return self._get(xmlbuilder)[:]
|
||||
|
||||
def clear(self, xmlbuilder):
|
||||
if self.is_single:
|
||||
self._get(xmlbuilder).clear()
|
||||
else:
|
||||
for obj in self._get(xmlbuilder)[:]:
|
||||
xmlbuilder._remove_child(obj)
|
||||
|
||||
def append(self, xmlbuilder, obj):
|
||||
self._get_list(xmlbuilder).append(obj)
|
||||
self._get(xmlbuilder).append(obj)
|
||||
def remove(self, xmlbuilder, obj):
|
||||
self._get_list(xmlbuilder).remove(obj)
|
||||
self._get(xmlbuilder).remove(obj)
|
||||
def set(self, xmlbuilder, obj):
|
||||
xmlbuilder._propstore[self._findpropname(xmlbuilder)] = obj
|
||||
|
||||
def get_prop_xpath(self, xmlbuilder, child_class):
|
||||
child_root = child_class._XML_ROOT_XPATH
|
||||
relative_xpath = self.relative_xpath
|
||||
def get_prop_xpath(self, xmlbuilder, obj):
|
||||
relative_xpath = self.relative_xpath + "/" + obj._XML_ROOT_NAME
|
||||
|
||||
match = re.search("%\((.*)\)", self.relative_xpath)
|
||||
if match:
|
||||
|
@ -297,8 +313,8 @@ class XMLChildProperty(property):
|
|||
for paramname in match.groups():
|
||||
valuedict[paramname] = getattr(xmlbuilder, paramname)
|
||||
relative_xpath = relative_xpath % valuedict
|
||||
return child_root.replace(xmlbuilder._xmlstate.get_node_top_xpath(),
|
||||
relative_xpath)
|
||||
|
||||
return relative_xpath
|
||||
|
||||
|
||||
class XMLProperty(property):
|
||||
|
@ -543,7 +559,7 @@ class XMLProperty(property):
|
|||
propname = self._findpropname(xmlbuilder)
|
||||
return xmlbuilder._propstore.get(propname, None)
|
||||
|
||||
def _clear(self, xmlbuilder):
|
||||
def clear(self, xmlbuilder):
|
||||
self.setter(xmlbuilder, None)
|
||||
self._set_xml(xmlbuilder, None)
|
||||
|
||||
|
@ -628,13 +644,10 @@ class XMLProperty(property):
|
|||
|
||||
|
||||
class _XMLState(object):
|
||||
def __init__(self, xpath, parsexml, parsexmlnode):
|
||||
if xpath is None or not xpath.startswith("/"):
|
||||
raise RuntimeError("xpath=%s must start with /" % xpath)
|
||||
|
||||
self.orig_root_xpath = xpath
|
||||
self.root_name = xpath.split("/")[-1]
|
||||
self.indent = (xpath.count("/") - 1) * 2
|
||||
def __init__(self, root_name, parsexml, parsexmlnode,
|
||||
parent_xpath, relative_object_xpath):
|
||||
self.root_name = root_name
|
||||
self.stub_path = "/%s" % self.root_name
|
||||
|
||||
self.xml_ctx = None
|
||||
self.xml_node = None
|
||||
|
@ -643,12 +656,12 @@ class _XMLState(object):
|
|||
# xpath of this object relative to its parent. So for a standalone
|
||||
# <disk> this is empty, but if the disk is the forth one in a <domain>
|
||||
# it will be set to ./devices/disk[4]
|
||||
self._relative_object_xpath = ""
|
||||
self._relative_object_xpath = relative_object_xpath or ""
|
||||
|
||||
# xpath of the parent. For a disk in a standalone <domain>, this
|
||||
# is empty, but if the <domain> is part of a <domainsnapshot>,
|
||||
# it will be "./domain"
|
||||
self._parent_xpath = ""
|
||||
self._parent_xpath = parent_xpath or ""
|
||||
|
||||
self.is_build = False
|
||||
if not parsexml and not parsexmlnode:
|
||||
|
@ -668,7 +681,7 @@ class _XMLState(object):
|
|||
self.xml_root_doc = _DocCleanupWrapper(doc)
|
||||
self.xml_node = doc.children
|
||||
self.xml_node.virtinst_is_build = self.is_build
|
||||
self.xml_node.virtinst_node_top_xpath = self.orig_root_xpath
|
||||
self.xml_node.virtinst_node_top_xpath = self.stub_path
|
||||
|
||||
# This just stores a reference to our root doc wrapper in
|
||||
# the root node, so when the node goes away it triggers
|
||||
|
@ -678,29 +691,24 @@ class _XMLState(object):
|
|||
self.xml_ctx = _make_xml_context(self.xml_node)
|
||||
|
||||
def make_xml_stub(self):
|
||||
return _indent(("<%s/>" % self.root_name), self.indent)
|
||||
return "<%s/>" % self.root_name
|
||||
|
||||
def set_relative_object_xpath(self, xpath):
|
||||
self._relative_object_xpath = xpath or ""
|
||||
def get_relative_object_xpath(self):
|
||||
return self._relative_object_xpath
|
||||
|
||||
def set_parent_xpath(self, xpath):
|
||||
self._parent_xpath = xpath or ""
|
||||
def get_parent_xpath(self):
|
||||
return self._parent_xpath
|
||||
|
||||
def get_root_xpath(self):
|
||||
fullpath = self._parent_xpath or ""
|
||||
if not fullpath:
|
||||
return self._relative_object_xpath
|
||||
if self._relative_object_xpath:
|
||||
fullpath += "/" + self._relative_object_xpath[2:]
|
||||
return fullpath
|
||||
relpath = self._relative_object_xpath
|
||||
if not self._parent_xpath:
|
||||
return relpath
|
||||
return self._parent_xpath + (relpath.startswith(".") and
|
||||
relpath[1:] or relpath)
|
||||
|
||||
def fix_relative_xpath(self, xpath):
|
||||
fullpath = self.get_root_xpath()
|
||||
if not fullpath:
|
||||
if not fullpath or fullpath == self.stub_path:
|
||||
return xpath
|
||||
if xpath.startswith("."):
|
||||
return "%s%s" % (fullpath, xpath.strip("."))
|
||||
|
@ -714,16 +722,11 @@ class _XMLState(object):
|
|||
"""
|
||||
return self.xml_node.virtinst_node_top_xpath
|
||||
|
||||
def _get_dump_xpath(self):
|
||||
if self.xml_root_doc or self.get_root_xpath():
|
||||
return self.fix_relative_xpath(".")
|
||||
return self.orig_root_xpath
|
||||
|
||||
def get_node_xml(self, ctx=None):
|
||||
if ctx is None:
|
||||
ctx = self.xml_ctx
|
||||
|
||||
node = _get_xpath_node(ctx, self._get_dump_xpath())
|
||||
node = _get_xpath_node(ctx, self.fix_relative_xpath("."))
|
||||
if not node:
|
||||
return ""
|
||||
return _sanitize_libxml_xml(node.serialize())
|
||||
|
@ -737,10 +740,11 @@ class XMLBuilder(object):
|
|||
# consistent with what the test suite expects.
|
||||
_XML_PROP_ORDER = []
|
||||
|
||||
# Absolute xpath this object is rooted at
|
||||
_XML_ROOT_XPATH = None
|
||||
# Name of the root XML element
|
||||
_XML_ROOT_NAME = None
|
||||
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None):
|
||||
def __init__(self, conn, parsexml=None, parsexmlnode=None,
|
||||
parent_xpath=None, relative_object_xpath=None):
|
||||
"""
|
||||
Initialize state
|
||||
|
||||
|
@ -748,26 +752,45 @@ class XMLBuilder(object):
|
|||
@type conn: VirtualConnection
|
||||
@param parsexml: Optional XML string to parse
|
||||
@type parsexml: C{str}
|
||||
@param parsexmlnode: Option xpathNode to use
|
||||
|
||||
The rest of the parameters are for internal use only
|
||||
"""
|
||||
self.conn = conn
|
||||
|
||||
self._propstore = {}
|
||||
self._proporder = []
|
||||
self._xmlstate = _XMLState(self._XML_ROOT_XPATH,
|
||||
parsexml, parsexmlnode)
|
||||
self._xmlstate = _XMLState(self._XML_ROOT_NAME,
|
||||
parsexml, parsexmlnode,
|
||||
parent_xpath, relative_object_xpath)
|
||||
|
||||
# Walk the XML tree and hand of parsing to any registered
|
||||
# child classes
|
||||
for xmlprop in self._all_child_props().values():
|
||||
if xmlprop.is_single:
|
||||
child_class = xmlprop.child_classes[0]
|
||||
prop_path = xmlprop.get_prop_xpath(self, child_class)
|
||||
obj = child_class(self.conn,
|
||||
parsexmlnode=self._xml_node,
|
||||
parent_xpath=self.get_root_xpath(),
|
||||
relative_object_xpath=prop_path)
|
||||
xmlprop.set(self, obj)
|
||||
continue
|
||||
|
||||
if self._xmlstate.is_build:
|
||||
continue
|
||||
|
||||
for child_class in xmlprop.child_classes:
|
||||
prop_path = xmlprop.get_prop_xpath(self, child_class)
|
||||
|
||||
nodecount = int(self._xml_node.xpathEval(
|
||||
"count(%s)" % prop_path))
|
||||
for ignore in range(nodecount):
|
||||
xmlprop.append(self,
|
||||
child_class(self.conn, parsexmlnode=self._xml_node))
|
||||
"count(%s)" % self.fix_relative_xpath(prop_path)))
|
||||
for idx in range(nodecount):
|
||||
idxstr = "[%d]" % (idx + 1)
|
||||
obj = child_class(self.conn,
|
||||
parsexmlnode=self._xml_node,
|
||||
parent_xpath=self.get_root_xpath(),
|
||||
relative_object_xpath=(prop_path + idxstr))
|
||||
xmlprop.append(self, obj)
|
||||
self._set_child_xpaths()
|
||||
|
||||
|
||||
|
@ -817,11 +840,10 @@ class XMLBuilder(object):
|
|||
"""
|
||||
Wipe out all properties of the object
|
||||
"""
|
||||
for prop in self._all_xml_props().values():
|
||||
prop._clear(self)
|
||||
for prop in self._all_child_props().values():
|
||||
for obj in prop._get_list(self)[:]:
|
||||
self._remove_child(obj)
|
||||
props = self._all_xml_props().values()
|
||||
props += self._all_child_props().values()
|
||||
for prop in props:
|
||||
prop.clear(self)
|
||||
|
||||
def validate(self):
|
||||
"""
|
||||
|
@ -897,6 +919,8 @@ class XMLBuilder(object):
|
|||
def _find_child_prop(self, child_class):
|
||||
xmlprops = self._all_child_props()
|
||||
for xmlprop in xmlprops.values():
|
||||
if xmlprop.is_single:
|
||||
continue
|
||||
if child_class in xmlprop.child_classes:
|
||||
return xmlprop
|
||||
raise RuntimeError("programming error: "
|
||||
|
@ -968,17 +992,18 @@ class XMLBuilder(object):
|
|||
"""
|
||||
typecount = {}
|
||||
for propname, xmlprop in self._all_child_props().items():
|
||||
for obj in getattr(self, propname):
|
||||
class_type = obj.__class__
|
||||
if class_type not in typecount:
|
||||
typecount[class_type] = 0
|
||||
idx = typecount[class_type]
|
||||
for obj in util.listify(getattr(self, propname)):
|
||||
idxstr = ""
|
||||
if not xmlprop.is_single:
|
||||
class_type = obj.__class__
|
||||
if class_type not in typecount:
|
||||
typecount[class_type] = 0
|
||||
typecount[class_type] += 1
|
||||
idxstr = "[%d]" % typecount[class_type]
|
||||
|
||||
prop_path = xmlprop.get_prop_xpath(self, obj)
|
||||
obj._set_parent_xpath(self.get_root_xpath())
|
||||
obj._set_relative_object_xpath(prop_path + ("[%d]" % (idx + 1)))
|
||||
typecount[class_type] += 1
|
||||
|
||||
obj._set_relative_object_xpath(prop_path + idxstr)
|
||||
|
||||
def _do_get_xml_config(self):
|
||||
xmlstub = self._xmlstate.make_xml_stub()
|
||||
|
|
Loading…
Reference in New Issue