From 309b82d9b1ef47239d1d6fe6f0d72e7eedd1071b Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Wed, 17 Sep 2014 14:56:52 -0400
Subject: [PATCH 08/12] virtinst: Add DomainCapabilities parser
Closes: https://bugzilla.redhat.com/show_bug.cgi?id=1111986
(cherry picked from commit 052220cfc80a9e262b39a15a4c5bdb09d5686602)
---
tests/capabilities-xml/domain-capabilities.xml | 71 ++++++++++++++++++++++
tests/capabilities.py | 12 ++++
virtinst/__init__.py | 1 +
virtinst/domcapabilities.py | 81 ++++++++++++++++++++++++++
virtinst/nodedev.py | 12 +---
virtinst/xmlbuilder.py | 9 ++-
6 files changed, 172 insertions(+), 14 deletions(-)
create mode 100644 tests/capabilities-xml/domain-capabilities.xml
create mode 100644 virtinst/domcapabilities.py
diff --git a/tests/capabilities-xml/domain-capabilities.xml b/tests/capabilities-xml/domain-capabilities.xml
new file mode 100644
index 0000000..96202bc
--- /dev/null
+++ b/tests/capabilities-xml/domain-capabilities.xml
@@ -0,0 +1,71 @@
+<domainCapabilities>
+ <path>/bin/emulatorbin</path>
+ <domain>kvm</domain>
+ <machine>my-machine-type</machine>
+ <arch>x86_64</arch>
+ <vcpu max='255'/>
+ <os supported='yes'>
+ <loader supported='yes'>
+ <value>/foo/bar</value>
+ <value>/tmp/my_path</value>
+ <enum name='type'>
+ <value>rom</value>
+ <value>pflash</value>
+ </enum>
+ <enum name='readonly'>
+ <value>default</value>
+ <value>yes</value>
+ <value>no</value>
+ </enum>
+ </loader>
+ </os>
+ <devices>
+ <disk supported='yes'>
+ <enum name='diskDevice'>
+ <value>disk</value>
+ <value>cdrom</value>
+ <value>floppy</value>
+ <value>lun</value>
+ </enum>
+ <enum name='bus'>
+ <value>ide</value>
+ <value>fdc</value>
+ <value>scsi</value>
+ <value>virtio</value>
+ <value>xen</value>
+ <value>usb</value>
+ <value>uml</value>
+ <value>sata</value>
+ <value>sd</value>
+ </enum>
+ </disk>
+ <hostdev supported='yes'>
+ <enum name='mode'>
+ <value>subsystem</value>
+ <value>capabilities</value>
+ </enum>
+ <enum name='startupPolicy'>
+ <value>default</value>
+ <value>mandatory</value>
+ <value>requisite</value>
+ <value>optional</value>
+ </enum>
+ <enum name='subsysType'>
+ <value>usb</value>
+ <value>pci</value>
+ <value>scsi</value>
+ </enum>
+ <enum name='capsType'>
+ <value>storage</value>
+ <value>misc</value>
+ <value>net</value>
+ </enum>
+ <enum name='pciBackend'>
+ <value>default</value>
+ <value>kvm</value>
+ <value>vfio</value>
+ <value>xen</value>
+ </enum>
+ </hostdev>
+ </devices>
+</domainCapabilities>
diff --git a/tests/capabilities.py b/tests/capabilities.py
index 394d6ed..8f6eaae 100644
--- a/tests/capabilities.py
+++ b/tests/capabilities.py
@@ -21,6 +21,7 @@ import unittest
from tests import utils
from virtinst import CapabilitiesParser as capabilities
from virtinst.capabilities import _CPUMapFileValues
+from virtinst import DomainCapabilities
def build_host_feature_dict(feature_list):
@@ -249,6 +250,17 @@ class TestCapabilities(unittest.TestCase):
cpu_64 = caps.get_cpu_values(conn, "x86_64")
self.assertTrue(len(cpu_64) > 0)
+ def testDomainCapabilities(self):
+ xml = file("tests/capabilities-xml/domain-capabilities.xml").read()
+ caps = DomainCapabilities(utils.open_testdriver(), xml)
+
+ self.assertEqual(caps.os.loader.supported, True)
+ self.assertEquals(caps.os.loader.get_values(),
+ ["/foo/bar", "/tmp/my_path"])
+ self.assertEquals(caps.os.loader.enum_names(), ["type", "readonly"])
+ self.assertEquals(caps.os.loader.get_enum("type").get_values(),
+ ["rom", "pflash"])
+
if __name__ == "__main__":
unittest.main()
diff --git a/virtinst/__init__.py b/virtinst/__init__.py
index 3a81173..e416054 100644
--- a/virtinst/__init__.py
+++ b/virtinst/__init__.py
@@ -51,6 +51,7 @@ from virtinst.pm import PM
from virtinst.idmap import IdMap
from virtinst import capabilities as CapabilitiesParser
+from virtinst.domcapabilities import DomainCapabilities
from virtinst.interface import Interface, InterfaceProtocol
from virtinst.network import Network
from virtinst.nodedev import NodeDevice
diff --git a/virtinst/domcapabilities.py b/virtinst/domcapabilities.py
new file mode 100644
index 0000000..6de7afb
--- /dev/null
+++ b/virtinst/domcapabilities.py
@@ -0,0 +1,81 @@
+#
+# Support for parsing libvirt's domcapabilities XML
+#
+# Copyright 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+
+from .xmlbuilder import XMLBuilder, XMLChildProperty
+from .xmlbuilder import XMLProperty as _XMLProperty
+
+
+class XMLProperty(_XMLProperty):
+ # We don't care about full parsing coverage, so tell the test suite
+ # not to warn
+ _track = False
+
+
+class _Value(XMLBuilder):
+ _XML_ROOT_NAME = "value"
+ value = XMLProperty(".")
+
+
+class _HasValues(XMLBuilder):
+ values = XMLChildProperty(_Value)
+
+ def get_values(self):
+ return [v.value for v in self.values]
+
+
+class _Enum(_HasValues):
+ _XML_ROOT_NAME = "enum"
+ name = XMLProperty("./@name")
+
+
+class _CapsBlock(_HasValues):
+ supported = XMLProperty("./@supported", is_yesno=True)
+ enums = XMLChildProperty(_Enum)
+
+ def enum_names(self):
+ return [e.name for e in self.enums]
+
+ def get_enum(self, name):
+ d = dict((e.name, e) for e in self.enums)
+ return d[name]
+
+
+def _make_capsblock(xml_root_name):
+ class TmpClass(_CapsBlock):
+ pass
+ setattr(TmpClass, "_XML_ROOT_NAME", xml_root_name)
+ return TmpClass
+
+
+class _OS(_CapsBlock):
+ _XML_ROOT_NAME = "os"
+ loader = XMLChildProperty(_make_capsblock("loader"), is_single=True)
+
+
+class _Devices(_CapsBlock):
+ _XML_ROOT_NAME = "devices"
+ hostdev = XMLChildProperty(_make_capsblock("hostdev"), is_single=True)
+ disk = XMLChildProperty(_make_capsblock("disk"), is_single=True)
+
+
+class DomainCapabilities(XMLBuilder):
+ _XML_ROOT_NAME = "domainCapabilities"
+ os = XMLChildProperty(_OS, is_single=True)
+ devices = XMLChildProperty(_Devices, is_single=True)
diff --git a/virtinst/nodedev.py b/virtinst/nodedev.py
index a42c20d..836f596 100644
--- a/virtinst/nodedev.py
+++ b/virtinst/nodedev.py
@@ -22,17 +22,11 @@ import logging
import libvirt
from .xmlbuilder import XMLBuilder
-from .xmlbuilder import XMLProperty as OrigXMLProperty
+from .xmlbuilder import XMLProperty as _XMLProperty
-# We had a pre-existing set of parse tests when this was converted to
-# XMLBuilder. We do this to appease the check in xmlparse.py without
-# moving all the nodedev.py tests to one file. Should find a way to
-# drop it.
-class XMLProperty(OrigXMLProperty):
- def __init__(self, *args, **kwargs):
- kwargs["track"] = False
- OrigXMLProperty.__init__(self, *args, **kwargs)
+class XMLProperty(_XMLProperty):
+ _track = False
def _lookupNodeName(conn, name):
diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py
index 77f8173..c906337 100644
--- a/virtinst/xmlbuilder.py
+++ b/virtinst/xmlbuilder.py
@@ -329,11 +329,12 @@ class XMLChildProperty(property):
class XMLProperty(property):
+ _track = True
+
def __init__(self, xpath=None, name=None, doc=None,
set_converter=None, validate_cb=None, make_xpath_cb=None,
is_bool=False, is_int=False, is_yesno=False, is_onoff=False,
- clear_first=None, default_cb=None, default_name=None,
- track=True):
+ clear_first=None, default_cb=None, default_name=None):
"""
Set a XMLBuilder class property that represents a value in the
<domain> XML. For example
@@ -373,8 +374,6 @@ class XMLProperty(property):
first explicit 'set'.
@param default_name: If the user does a set and passes in this
value, instead use the value of default_cb()
- @param track: If False, opt out of property tracking for the
- test suite.
"""
self._xpath = xpath
@@ -403,7 +402,7 @@ class XMLProperty(property):
if self._default_name and not self._default_cb:
raise RuntimeError("default_name requires default_cb.")
- if _trackprops and track:
+ if _trackprops and self._track:
_allprops.append(self)
property.__init__(self, fget=self.getter, fset=self.setter)
--
1.9.3