Blob Blame History Raw
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