[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[et-mgmt-tools] [PATCH 1/3]: Add NodeDeviceParser module



Add NodeDeviceParser module for parsing libvirt host device xml,
associated helper functions and tests.

Thanks,
Cole
# HG changeset patch
# User Cole Robinson <crobinso redhat com>
# Node ID 391354aef31a1a8e21e43ba3799af3a79c69985e
# Parent  9f02b1bb16e2d47088ab928ccc1ba2a59d26d1c8
Add NodeDeviceParser module for parsing libvirt host device xml.

diff -r 9f02b1bb16e2 -r 391354aef31a tests/__init__.py
--- a/tests/__init__.py	Sun Mar 01 21:19:29 2009 -0500
+++ b/tests/__init__.py	Sun Mar 01 21:29:18 2009 -0500
@@ -70,4 +70,5 @@
 import storage
 import urltest
 import clonetest
+import nodedev
 
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/net1.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/net1.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,9 @@
+<device>
+  <name>net_00_1c_25_10_b1_e4</name>
+  <parent>pci_8086_1049</parent>
+  <capability type='net'>
+    <interface>eth0</interface>
+    <address>00:1c:25:10:b1:e4</address>
+    <capability type='80203'/>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/net2.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/net2.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,9 @@
+<device>
+  <name>net_00_1c_bf_04_29_a4</name>
+  <parent>pci_8086_4227</parent>
+  <capability type='net'>
+    <interface>wlan0</interface>
+    <address>00:1c:bf:04:29:a4</address>
+    <capability type='80211'/>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/pci1.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/pci1.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,12 @@
+<device>
+  <name>pci_1180_592</name>
+  <parent>pci_8086_2448</parent>
+  <capability type='pci'>
+    <domain>0</domain>
+    <bus>21</bus>
+    <slot>0</slot>
+    <function>4</function>
+    <product id='0x0592'>R5C592 Memory Stick Bus Host Adapter</product>
+    <vendor id='0x1180'>Ricoh Co Ltd</vendor>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/pci2.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/pci2.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,12 @@
+<device>
+  <name>pci_8086_1049</name>
+  <parent>computer</parent>
+  <capability type='pci'>
+    <domain>0</domain>
+    <bus>0</bus>
+    <slot>25</slot>
+    <function>0</function>
+    <product id='0x1049'>82566MM Gigabit Network Connection</product>
+    <vendor id='0x8086'>Intel Corporation</vendor>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/scsibus.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/scsibus.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,7 @@
+<device>
+  <name>usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0</name>
+  <parent>usb_device_781_5151_2004453082054CA1BEEE_if0</parent>
+  <capability type='scsi_host'>
+    <host>5</host>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/scsidev.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/scsidev.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,11 @@
+<device>
+  <name>usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0_scsi_device_lun0</name>
+  <parent>usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0</parent>
+  <capability type='scsi'>
+    <host>5</host>
+    <bus>0</bus>
+    <target>0</target>
+    <lun>0</lun>
+    <type>disk</type>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/storage1.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/storage1.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,12 @@
+<device>
+  <name>storage_serial_SATA_WDC_WD1600AAJS__WD_WCAP95119685</name>
+  <parent>pci_8086_27c0_scsi_host_scsi_device_lun0</parent>
+  <capability type='storage'>
+    <block>/dev/sda</block>
+    <bus>scsi</bus>
+    <drive_type>disk</drive_type>
+    <model>WDC WD1600AAJS-2</model>
+    <vendor>ATA</vendor>
+    <size>160041885696</size>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/storage2.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/storage2.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,16 @@
+<device>
+  <name>storage_serial_SanDisk_Cruzer_Micro_2004453082054CA1BEEE_0_0</name>
+  <parent>usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0_scsi_device_lun0</parent>
+  <capability type='storage'>
+    <block>/dev/sdb</block>
+    <bus>usb</bus>
+    <drive_type>disk</drive_type>
+    <model>Cruzer Micro</model>
+    <vendor>SanDisk</vendor>
+    <capability type='removable'>
+      <media_available>1</media_available>
+      <media_size>12345678</media_size>
+    </capability>
+    <capability type='hotpluggable' />
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/system.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/system.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,17 @@
+<device>
+  <name>computer</name>
+  <capability type='system'>
+    <hardware>
+      <vendor>LENOVO</vendor>
+      <version>ThinkPad T61</version>
+      <serial>L3B2616</serial>
+      <uuid>97e80381-494f-11cb-8e0e-cbc168f7d753</uuid>
+    </hardware>
+    <firmware>
+      <vendor>LENOVO</vendor>
+      <version>7LET51WW (1.21 )</version>
+      <release_date>08/22/2007</release_date>
+    </firmware>
+  </capability>
+</device>
+
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/usbbus.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/usbbus.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,10 @@
+<device>
+  <name>usb_device_781_5151_2004453082054CA1BEEE_if0</name>
+  <parent>usb_device_781_5151_2004453082054CA1BEEE</parent>
+  <capability type='usb'>
+    <number>0</number>
+    <class>8</class>
+    <subclass>6</subclass>
+    <protocol>80</protocol>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/usbdev1.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/usbdev1.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,10 @@
+<device>
+  <name>usb_device_781_5151_2004453082054CA1BEEE</name>
+  <parent>usb_device_1d6b_2_0000_00_1a_7</parent>
+  <capability type='usb_device'>
+    <bus>1</bus>
+    <device>4</device>
+    <product id='0x5151'>Cruzer Micro 256/512MB Flash Drive</product>
+    <vendor id='0x0781'>SanDisk Corp.</vendor>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev-xml/nodexml/usbdev2.xml
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/nodexml/usbdev2.xml	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,10 @@
+<device>
+  <name>usb_device_483_2016_noserial</name>
+  <parent>usb_device_1d6b_1_0000_00_1a_0</parent>
+  <capability type='usb_device'>
+    <bus>3</bus>
+    <device>3</device>
+    <product id='0x2016'>Fingerprint Reader</product>
+    <vendor id='0x0483'>SGS Thomson Microelectronics</vendor>
+  </capability>
+</device>
diff -r 9f02b1bb16e2 -r 391354aef31a tests/nodedev.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev.py	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,154 @@
+#
+# 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.
+
+import os.path
+import unittest
+import virtinst.NodeDeviceParser as nodeparse
+import libvirt
+
+conn = libvirt.open("test:///default")
+
+class TestNodeDev(unittest.TestCase):
+
+    def _nodeDevFromFile(self, filename):
+        xml = file(os.path.join("tests/nodedev-xml/nodexml", filename)).read()
+        return nodeparse.parse(xml)
+
+    def _testCompare(self, filename, vals):
+        dev = self._nodeDevFromFile(filename)
+
+        for attr in vals.keys():
+            self.assertEqual(vals[attr], getattr(dev, attr))
+
+    def testSystemDevice(self):
+        filename = "system.xml"
+        vals = {"hw_vendor": "LENOVO", "hw_version": "ThinkPad T61",
+                "hw_serial": "L3B2616",
+                "hw_uuid": "97e80381-494f-11cb-8e0e-cbc168f7d753",
+                "fw_vendor": "LENOVO", "fw_version": "7LET51WW (1.21 )",
+                "fw_date": "08/22/2007",
+                "device_type": nodeparse.CAPABILITY_TYPE_SYSTEM,
+                "name": "computer", "parent": None}
+        self._testCompare(filename, vals)
+
+    def testNetDevice1(self):
+        filename = "net1.xml"
+        vals = {"name": "net_00_1c_25_10_b1_e4", "parent": "pci_8086_1049",
+                "device_type": nodeparse.CAPABILITY_TYPE_NET,
+                "interface": "eth0", "address": "00:1c:25:10:b1:e4",
+                "capability_type": "80203"}
+        self._testCompare(filename, vals)
+
+    def testNetDevice2(self):
+        filename = "net2.xml"
+        vals = {"name": "net_00_1c_bf_04_29_a4", "parent": "pci_8086_4227",
+                "device_type": nodeparse.CAPABILITY_TYPE_NET,
+                "interface": "wlan0", "address": "00:1c:bf:04:29:a4",
+                "capability_type": "80211"}
+        self._testCompare(filename, vals)
+
+    def testPCIDevice1(self):
+        filename = "pci1.xml"
+        vals = {"name": "pci_1180_592", "parent": "pci_8086_2448",
+                "device_type": nodeparse.CAPABILITY_TYPE_PCI,
+                "domain": "0", "bus": "21", "slot": "0", "function": "4",
+                "product_id": "0x0592", "vendor_id": "0x1180",
+                "product_name": "R5C592 Memory Stick Bus Host Adapter",
+                "vendor_name": "Ricoh Co Ltd",}
+        self._testCompare(filename, vals)
+
+    def testPCIDevice2(self):
+        filename = "pci2.xml"
+        vals = {"name": "pci_8086_1049", "parent": "computer",
+                "device_type": nodeparse.CAPABILITY_TYPE_PCI,
+                "domain": "0", "bus": "0", "slot": "25", "function": "0",
+                "product_id": "0x1049", "vendor_id": "0x8086",
+                "product_name": "82566MM Gigabit Network Connection",
+                "vendor_name": "Intel Corporation",}
+        self._testCompare(filename, vals)
+
+    def testUSBDevDevice1(self):
+        filename = "usbdev1.xml"
+        vals = {"name": "usb_device_781_5151_2004453082054CA1BEEE",
+                "parent": "usb_device_1d6b_2_0000_00_1a_7",
+                "device_type": nodeparse.CAPABILITY_TYPE_USBDEV,
+                "bus": "1", "device": "4", "product_id": '0x5151',
+                "vendor_id": '0x0781',
+                "vendor_name": "SanDisk Corp.",
+                "product_name": "Cruzer Micro 256/512MB Flash Drive" }
+        self._testCompare(filename, vals)
+
+    def testUSBDevDevice2(self):
+        filename = "usbdev2.xml"
+        vals = {"name": "usb_device_483_2016_noserial",
+                "parent": "usb_device_1d6b_1_0000_00_1a_0",
+                "device_type": nodeparse.CAPABILITY_TYPE_USBDEV,
+                "bus": "3", "device": "3", "product_id": '0x2016',
+                "vendor_id": '0x0483',
+                "vendor_name": "SGS Thomson Microelectronics",
+                "product_name": "Fingerprint Reader" }
+        self._testCompare(filename, vals)
+
+    def testStorageDevice1(self):
+        filename = "storage1.xml"
+        vals = {"name": "storage_serial_SATA_WDC_WD1600AAJS__WD_WCAP95119685",
+                "parent": "pci_8086_27c0_scsi_host_scsi_device_lun0",
+                "device_type": nodeparse.CAPABILITY_TYPE_STORAGE,
+                "block": "/dev/sda", "bus": "scsi", "drive_type": "disk",
+                "model": "WDC WD1600AAJS-2", "vendor": "ATA",
+                "size": 160041885696, "removable": False,
+                "hotpluggable": False, "media_available": False,
+                "media_size": 0}
+        self._testCompare(filename, vals)
+
+    def testStorageDevice2(self):
+        filename = "storage2.xml"
+        vals = {"name": "storage_serial_SanDisk_Cruzer_Micro_2004453082054CA1BEEE_0_0",
+                "parent": "usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0_scsi_device_lun0",
+                "device_type": nodeparse.CAPABILITY_TYPE_STORAGE,
+                "block": "/dev/sdb", "bus": "usb", "drive_type": "disk",
+                "model": "Cruzer Micro", "vendor": "SanDisk", "size": 0,
+                "removable": True, "hotpluggable": True,
+                "media_available": True, "media_size": 12345678}
+        self._testCompare(filename, vals)
+
+    def testUSBBus(self):
+        filename = "usbbus.xml"
+        vals = {"name": "usb_device_781_5151_2004453082054CA1BEEE_if0",
+                "parent": "usb_device_781_5151_2004453082054CA1BEEE",
+                "device_type": nodeparse.CAPABILITY_TYPE_USBBUS,
+                "number": "0", "classval": "8", "subclass": "6",
+                "protocol": "80"}
+        self._testCompare(filename, vals)
+
+    def testSCSIBus(self):
+        filename = "scsibus.xml"
+        vals = {"name": "usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0",
+                "parent": "usb_device_781_5151_2004453082054CA1BEEE_if0",
+                "device_type": nodeparse.CAPABILITY_TYPE_SCSIBUS,
+                "host": "5"}
+        self._testCompare(filename, vals)
+
+    def testSCSIDevice(self):
+        filename = "scsidev.xml"
+        vals = {"name": "usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0_scsi_device_lun0",
+                "parent": "usb_device_781_5151_2004453082054CA1BEEE_if0_scsi_host_0",
+                "host": "5", "bus": "0", "target": "0", "lun": "0",
+                "type": "disk"}
+        self._testCompare(filename, vals)
+
+if __name__ == "__main__":
+    unittest.main()
diff -r 9f02b1bb16e2 -r 391354aef31a virtinst/NodeDeviceParser.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/virtinst/NodeDeviceParser.py	Sun Mar 01 21:29:18 2009 -0500
@@ -0,0 +1,421 @@
+#
+# Copyright 2009  Red Hat, Inc.
+# Cole Robinson <crobinso redhat com>
+#
+# 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.
+
+import libxml2
+import libvirt
+from virtinst import _virtinst as _
+
+# class USBDevice
+
+CAPABILITY_TYPE_SYSTEM = "system"
+CAPABILITY_TYPE_NET = "net"
+CAPABILITY_TYPE_PCI = "pci"
+CAPABILITY_TYPE_USBDEV = "usb_device"
+CAPABILITY_TYPE_USBBUS = "usb"
+CAPABILITY_TYPE_STORAGE = "storage"
+CAPABILITY_TYPE_SCSIBUS = "scsi_host"
+CAPABILITY_TYPE_SCSIDEV = "scsi"
+
+class NodeDevice(object):
+    def __init__(self, node):
+        self.name = None
+        self.parent = None
+        self.device_type = None
+
+        self._parseNodeXML(node)
+
+    def getVirtualHostDevice(self, conn):
+        """
+        Convert this NodeDevice to a VirtualHostDevice for attaching to a
+        guest.
+
+        @param conn: connection to pass to the VirtualHostDevice instance
+        @type conn: libvirt.virConnect
+
+        @rtype: L{virtinst.VirtualHostDevice}
+        """
+        raise ValueError(_("Node device type '%s' cannot be "
+                           "attached.") % self.device_type)
+
+    def _parseNodeXML(self, node):
+        child = node.children
+        while child:
+            if child.name == "name":
+                self.name = child.content
+            elif child.name == "parent":
+                self.parent = child.content
+            elif child.name == "capability":
+                self.device_type = child.prop("type")
+            child = child.next
+
+    def _getCapabilityNode(self, node):
+        child = node.children
+        while child:
+            if child.name == "capability":
+                return child
+            child = child.next
+        return None
+
+    def _parseValueHelper(self, node, value_map):
+        if value_map.has_key(node.name):
+            setattr(self, value_map[node.name], node.content)
+
+    def _parseHelper(self, main_node, value_map):
+        node = main_node.children
+        while node:
+            self._parseValueHelper(node, value_map)
+            node = node.next
+
+class SystemDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.hw_vendor = None
+        self.hw_version = None
+        self.hw_serial = None
+        self.hw_uuid = None
+
+        self.fw_vendor = None
+        self.fw_version = None
+        self.fw_date = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        child = node.children
+        hardware_map = {"vendor": "hw_vendor",
+                        "version": "hw_version",
+                        "serial": "hw_serial",
+                        "uuid": "hw_uuid"}
+        firmware_map = {"vendor": "fw_vendor",
+                        "version": "fw_version",
+                        "release_date": "fw_date" }
+        while child:
+            if child.name == "hardware":
+                self._parseHelper(child, hardware_map)
+            elif child.name == "firmware":
+                self._parseHelper(child, firmware_map)
+            child = child.next
+
+class NetDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.interface = None
+        self.address = None
+        self.capability_type = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        value_map = { "interface" : "interface",
+                      "address" : "address", }
+        child = node.children
+        while child:
+            if child.name == "capability":
+                self.capability_type = child.prop("type")
+            else:
+                self._parseValueHelper(child, value_map)
+            child = child.next
+
+class PCIDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.domain = None
+        self.bus = None
+        self.slot = None
+        self.function = None
+
+        self.product_id = None
+        self.product_name = None
+        self.vendor_id = None
+        self.vendor_name = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "domain" : "domain",
+                    "bus" : "bus",
+                    "slot" : "slot",
+                    "function" : "function" }
+        child = node.children
+        while child:
+            if child.name == "vendor":
+                self.vendor_name = child.content
+                self.vendor_id = child.prop("id")
+
+            elif child.name == "product":
+                self.product_name = child.content
+                self.product_id = child.prop("id")
+
+            else:
+                self._parseValueHelper(child, val_map)
+
+            child = child.next
+
+class USBDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.bus = None
+        self.device = None
+
+        self.product_id = None
+        self.product_name = None
+        self.vendor_id = None
+        self.vendor_name = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "bus": "bus", "device": "device"}
+        child = node.children
+        while child:
+            if child.name == "vendor":
+                self.vendor_name = child.content
+                self.vendor_id = child.prop("id")
+
+            elif child.name == "product":
+                self.product_name = child.content
+                self.product_id = child.prop("id")
+
+            else:
+                self._parseValueHelper(child, val_map)
+
+            child = child.next
+
+class StorageDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.block = None
+        self.bus = None
+        # FIXME: Map this to virtinst.device?
+        self.drive_type = None
+        self.size = 0
+
+        self.model = None
+        self.vendor = None
+
+        self.removable = False
+        self.media_available = False
+        self.media_size = 0
+
+        self.hotpluggable = False
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "block" : "block",
+                    "bus" : "bus",
+                    "drive_type" : "drive_type",
+                    "model" : "model",
+                    "vendor" : "vendor"}
+        child = node.children
+        while child:
+            if child.name == "size":
+                self.size = int(child.content)
+            elif child.name == "capability":
+
+                captype = child.prop("type")
+                if captype == "hotpluggable":
+                    self.hotpluggable = True
+                elif captype == "removable":
+                    self.removable = True
+                    rmchild = child.children
+                    while rmchild:
+                        if rmchild.name == "media_available":
+                            self.media_available = bool(int(rmchild.content))
+                        elif rmchild.name == "media_size":
+                            self.media_size = int(rmchild.content)
+                        rmchild = rmchild.next
+            else:
+                self._parseValueHelper(child, val_map)
+
+            child = child.next
+
+class USBBus(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.number = None
+        self.classval = None
+        self.subclass = None
+        self.protocol = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "number" : "number",
+                    "class" : "classval",
+                    "subclass" : "subclass",
+                    "protocol" : "protocol" }
+        self._parseHelper(node, val_map)
+
+class SCSIDevice(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.host = None
+        self.bus = None
+        self.target = None
+        self.lun = None
+        self.disk = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "host" : "host",
+                    "bus" : "bus",
+                    "target": "target",
+                    "lun" : "lun",
+                    "type" : "type"}
+        self._parseHelper(node, val_map)
+
+class SCSIBus(NodeDevice):
+    def __init__(self, node):
+        NodeDevice.__init__(self, node)
+
+        self.host = None
+
+        self.parseXML(self._getCapabilityNode(node))
+
+    def parseXML(self, node):
+        val_map = { "host" : "host" }
+        self._parseHelper(node, val_map)
+
+
+def is_nodedev_capable(conn):
+    """
+    Check if the passed libvirt connection supports host device routines
+
+    @param conn: Connection to check
+    @type conn: libvirt.virConnect
+
+    @rtype: C{bool}
+    """
+    if not conn:
+        return False
+    if not isinstance(conn, libvirt.virConnect):
+        raise ValueError(_("'conn' must be a virConnect instance."))
+
+    if dir(libvirt).count("virNodeDevice") == 0:
+        # Local libvirt doesn't support it
+        return False
+
+    try:
+        conn.listDevices(None, 0)
+        return True
+    except Exception, e:
+        if (e.get_error_code() == libvirt.VIR_ERR_RPC or
+            e.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT):
+            return False
+
+    return True
+
+def lookupNodeName(conn, name):
+    """
+    Convert the passed libvirt node device name to a NodeDevice
+    instance, with proper error reporting.
+
+    @param conn: libvirt.virConnect instance to perform the lookup on
+    @param name: libvirt node device name to lookup
+
+    @rtype: L{NodeDevice} instance
+    """
+
+    if not is_nodedev_capable(conn):
+        raise ValueError(_("Connection does not support host device "
+                           "enumeration."))
+
+    nodedev = conn.nodeDeviceLookupByName(name)
+    xml = nodedev.XMLDesc(0)
+    return parse(xml)
+
+
+def parse(xml):
+    """
+    Convert the passed libvirt node device xml into a NodeDevice object
+
+    @param xml: libvirt node device xml
+    @type xml: C{str}
+
+    @returns: L{NodeDevice} instance
+    """
+
+    class ErrorHandler:
+        def __init__(self):
+            self.msg = ""
+        def handler(self, ignore, s):
+            self.msg += s
+    error = ErrorHandler()
+    libxml2.registerErrorHandler(error.handler, None)
+
+    try:
+        # try/except/finally is only available in python-2.5
+        try:
+            doc = libxml2.readMemory(xml, len(xml),
+                                     None, None,
+                                     libxml2.XML_PARSE_NOBLANKS)
+        except (libxml2.parserError, libxml2.treeError), e:
+            raise ValueError("%s\n%s" % (e, error.msg))
+    finally:
+        libxml2.registerErrorHandler(None, None)
+
+    try:
+        root = doc.getRootElement()
+        if root.name != "device":
+            raise ValueError("Root element is not 'device'")
+
+        t = _findNodeType(root)
+        devclass = _typeToDeviceClass(t)
+        device = devclass(root)
+    finally:
+        doc.freeDoc()
+
+    return device
+
+def _findNodeType(node):
+    child = node.children
+    while child:
+        if child.name == "capability":
+            return child.prop("type")
+        child = child.next
+    return None
+
+def _typeToDeviceClass(t):
+    if t == CAPABILITY_TYPE_SYSTEM:
+        return SystemDevice
+    elif t == CAPABILITY_TYPE_NET:
+        return NetDevice
+    elif t == CAPABILITY_TYPE_PCI:
+        return PCIDevice
+    elif t == CAPABILITY_TYPE_USBDEV:
+        return USBDevice
+    elif t == CAPABILITY_TYPE_USBBUS:
+        return USBBus
+    elif t == CAPABILITY_TYPE_STORAGE:
+        return StorageDevice
+    elif t == CAPABILITY_TYPE_SCSIBUS:
+        return SCSIBus
+    elif t == CAPABILITY_TYPE_SCSIDEV:
+        return SCSIDevice
+
+    raise ValueError(_("Unknown host device capability '%s'.") % t)

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]