Add NodeDeviceParser module for parsing libvirt host device xml, associated helper functions and tests. Thanks, Cole
# HG changeset patch # User Cole Robinson <crobinso@xxxxxxxxxx> # 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@xxxxxxxxxx> +# +# 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)
_______________________________________________ et-mgmt-tools mailing list et-mgmt-tools@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/et-mgmt-tools