From b690557a53bc46bbcc9ad0750e93e4eeef3acaa9 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Sun, 22 Sep 2013 18:13:24 -0400 Subject: [PATCH] Convert NodeDevice to XMLBuilder --- tests/nodedev.py | 41 ++-- virtManager/mediadev.py | 6 +- virtManager/nodedev.py | 4 +- virtinst/__init__.py | 2 +- virtinst/devicehostdev.py | 14 +- virtinst/nodedev.py | 502 ++++++++++++-------------------------- virtinst/xmlbuilder.py | 9 +- 7 files changed, 196 insertions(+), 382 deletions(-) diff --git a/tests/nodedev.py b/tests/nodedev.py index ce0c7538d..1aeea7d95 100644 --- a/tests/nodedev.py +++ b/tests/nodedev.py @@ -17,7 +17,7 @@ import os.path import unittest -from virtinst import NodeDeviceParser as nodeparse +from virtinst import NodeDevice from virtinst import VirtualHostDevice from tests import utils @@ -42,15 +42,20 @@ class TestNodeDev(unittest.TestCase): def _nodeDevFromName(self, devname): node = conn.nodeDeviceLookupByName(devname) xml = node.XMLDesc(0) - return nodeparse.parse(xml) + return NodeDevice.parse(conn, xml) def _testCompare(self, devname, vals, devxml=None): if devxml: - dev = nodeparse.parse(devxml) + dev = NodeDevice.parse(conn, devxml) else: dev = self._nodeDevFromName(devname) for attr in vals.keys(): + expect = vals[attr] + actual = getattr(dev, attr) + if expect != actual: + raise AssertionError("devname=%s attribute=%s did not match:\n" + "expect=%s\nactual=%s" % (devname, attr, expect, actual)) self.assertEqual(vals[attr], getattr(dev, attr)) def _testNode2DeviceCompare(self, nodename, devfile, @@ -70,14 +75,14 @@ class TestNodeDev(unittest.TestCase): "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, + "device_type": NodeDevice.CAPABILITY_TYPE_SYSTEM, "name": "computer", "parent": None} self._testCompare(devname, vals) def testNetDevice1(self): devname = "net_00_1c_25_10_b1_e4" vals = {"name": "net_00_1c_25_10_b1_e4", "parent": "pci_8086_1049", - "device_type": nodeparse.CAPABILITY_TYPE_NET, + "device_type": NodeDevice.CAPABILITY_TYPE_NET, "interface": "eth0", "address": "00:1c:25:10:b1:e4", "capability_type": "80203"} self._testCompare(devname, vals) @@ -85,7 +90,7 @@ class TestNodeDev(unittest.TestCase): def testNetDevice2(self): devname = "net_00_1c_bf_04_29_a4" vals = {"name": "net_00_1c_bf_04_29_a4", "parent": "pci_8086_4227", - "device_type": nodeparse.CAPABILITY_TYPE_NET, + "device_type": NodeDevice.CAPABILITY_TYPE_NET, "interface": "wlan0", "address": "00:1c:bf:04:29:a4", "capability_type": "80211"} self._testCompare(devname, vals) @@ -93,7 +98,7 @@ class TestNodeDev(unittest.TestCase): def testPCIDevice1(self): devname = "pci_1180_592" vals = {"name": "pci_1180_592", "parent": "pci_8086_2448", - "device_type": nodeparse.CAPABILITY_TYPE_PCI, + "device_type": NodeDevice.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", @@ -103,7 +108,7 @@ class TestNodeDev(unittest.TestCase): def testPCIDevice2(self): devname = "pci_8086_1049" vals = {"name": "pci_8086_1049", "parent": "computer", - "device_type": nodeparse.CAPABILITY_TYPE_PCI, + "device_type": NodeDevice.CAPABILITY_TYPE_PCI, "domain": "0", "bus": "0", "slot": "25", "function": "0", "product_id": "0x1049", "vendor_id": "0x8086", "product_name": "82566MM Gigabit Network Connection", @@ -114,7 +119,7 @@ class TestNodeDev(unittest.TestCase): devname = "usb_device_781_5151_2004453082054CA1BEEE" vals = {"name": "usb_device_781_5151_2004453082054CA1BEEE", "parent": "usb_device_1d6b_2_0000_00_1a_7", - "device_type": nodeparse.CAPABILITY_TYPE_USBDEV, + "device_type": NodeDevice.CAPABILITY_TYPE_USBDEV, "bus": "1", "device": "4", "product_id": '0x5151', "vendor_id": '0x0781', "vendor_name": "SanDisk Corp.", @@ -125,7 +130,7 @@ class TestNodeDev(unittest.TestCase): devname = "usb_device_483_2016_noserial" vals = {"name": "usb_device_483_2016_noserial", "parent": "usb_device_1d6b_1_0000_00_1a_0", - "device_type": nodeparse.CAPABILITY_TYPE_USBDEV, + "device_type": NodeDevice.CAPABILITY_TYPE_USBDEV, "bus": "3", "device": "2", "product_id": '0x2016', "vendor_id": '0x0483', "vendor_name": "SGS Thomson Microelectronics", @@ -136,21 +141,21 @@ class TestNodeDev(unittest.TestCase): devname = "storage_serial_SATA_WDC_WD1600AAJS__WD_WCAP95119685" vals = {"name": "storage_serial_SATA_WDC_WD1600AAJS__WD_WCAP95119685", "parent": "pci_8086_27c0_scsi_host_scsi_device_lun0", - "device_type": nodeparse.CAPABILITY_TYPE_STORAGE, + "device_type": NodeDevice.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, "media_label": None} + "hotpluggable": False, "media_available": None, + "media_size": None, "media_label": None} self._testCompare(devname, vals) def testStorageDevice2(self): devname = "storage_serial_SanDisk_Cruzer_Micro_2004453082054CA1BEEE_0_0" 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, + "device_type": NodeDevice.CAPABILITY_TYPE_STORAGE, "block": "/dev/sdb", "bus": "usb", "drive_type": "disk", - "model": "Cruzer Micro", "vendor": "SanDisk", "size": 0, + "model": "Cruzer Micro", "vendor": "SanDisk", "size": None, "removable": True, "hotpluggable": True, "media_available": True, "media_size": 12345678} self._testCompare(devname, vals) @@ -159,7 +164,7 @@ class TestNodeDev(unittest.TestCase): devname = "usb_device_1d6b_1_0000_00_1d_1_if0" vals = {"name": "usb_device_1d6b_1_0000_00_1d_1_if0", "parent": "usb_device_1d6b_1_0000_00_1d_1", - "device_type": nodeparse.CAPABILITY_TYPE_USBBUS, + "device_type": NodeDevice.CAPABILITY_TYPE_USBBUS, "number": "0", "classval": "9", "subclass": "0", "protocol": "0"} self._testCompare(devname, vals) @@ -168,14 +173,14 @@ class TestNodeDev(unittest.TestCase): devname = "pci_8086_2829_scsi_host_1" vals = {"name": "pci_8086_2829_scsi_host_1", "parent": "pci_8086_2829", - "device_type": nodeparse.CAPABILITY_TYPE_SCSIBUS, + "device_type": NodeDevice.CAPABILITY_TYPE_SCSIBUS, "host": "2"} self._testCompare(devname, vals) def testNPIV(self): devname = "pci_10df_fe00_0_scsi_host" vals = {"name": "pci_10df_fe00_0_scsi_host", - "device_type": nodeparse.CAPABILITY_TYPE_SCSIBUS, + "device_type": NodeDevice.CAPABILITY_TYPE_SCSIBUS, "host": "4", "fc_host": True, "vport_ops" : True, "wwnn": "20000000c9848141", "wwpn": "10000000c9848141"} self._testCompare(devname, vals) diff --git a/virtManager/mediadev.py b/virtManager/mediadev.py index b8d88438b..69749a608 100644 --- a/virtManager/mediadev.py +++ b/virtManager/mediadev.py @@ -24,7 +24,7 @@ from gi.repository import GObject import logging -import virtinst +from virtinst import NodeDevice from virtManager.baseclass import vmmGObject @@ -131,8 +131,8 @@ class vmmMediaDevice(vmmGObject): return try: - vobj = virtinst.NodeDeviceParser.parse(xml) - has_media = vobj.media_available + vobj = NodeDevice.parse(self.nodedev_obj.conn.get_backend(), xml) + has_media = vobj.media_available or False except: logging.exception("Node device CDROM polling failed") return diff --git a/virtManager/nodedev.py b/virtManager/nodedev.py index 003354daa..0dff39dbe 100644 --- a/virtManager/nodedev.py +++ b/virtManager/nodedev.py @@ -18,7 +18,7 @@ # MA 02110-1301 USA. # -import virtinst +from virtinst import NodeDevice from virtManager.libvirtobject import vmmLibvirtObject @@ -41,7 +41,7 @@ class vmmNodeDevice(vmmLibvirtObject): def get_virtinst_obj(self): if not self._virtinst_obj: - self._virtinst_obj = virtinst.NodeDeviceParser.parse( + self._virtinst_obj = NodeDevice.parse(self.conn.get_backend(), self._backend.XMLDesc(0)) return self._virtinst_obj diff --git a/virtinst/__init__.py b/virtinst/__init__.py index f48239a97..a2fc25beb 100644 --- a/virtinst/__init__.py +++ b/virtinst/__init__.py @@ -29,10 +29,10 @@ from virtinst.clock import Clock from virtinst.cpu import CPU, CPUFeature from virtinst.seclabel import Seclabel -import virtinst.nodedev as NodeDeviceParser import virtinst.capabilities as CapabilitiesParser from virtinst.interface import Interface, InterfaceProtocol from virtinst.network import Network +from virtinst.nodedev import NodeDevice from virtinst.storage import StoragePool, StorageVolume from virtinst.device import VirtualDevice diff --git a/virtinst/devicehostdev.py b/virtinst/devicehostdev.py index a1315a99f..7f8793aee 100644 --- a/virtinst/devicehostdev.py +++ b/virtinst/devicehostdev.py @@ -18,7 +18,7 @@ # MA 02110-1301 USA. from virtinst import VirtualDevice -from virtinst import NodeDeviceParser +from virtinst import NodeDevice from virtinst.xmlbuilder import XMLProperty @@ -31,7 +31,7 @@ class VirtualHostDevice(VirtualDevice): """ Convert the passed device name to a VirtualHostDevice instance, with proper error reporting. Name can be any of the - values accepted by NodeDeviceParser.lookupNodeName. If a node + values accepted by NodeDevice.lookupNodeName. If a node device name is not specified, a virtinst.NodeDevice instance can be passed in to create a dev from. @@ -47,11 +47,11 @@ class VirtualHostDevice(VirtualDevice): if nodedev: nodeinst = nodedev else: - nodeinst, addr_type = NodeDeviceParser.lookupNodeName(conn, name) - if addr_type == NodeDeviceParser.HOSTDEV_ADDR_TYPE_USB_BUSADDR: + nodeinst, addr_type = NodeDevice.lookupNodeName(conn, name) + if addr_type == NodeDevice.HOSTDEV_ADDR_TYPE_USB_BUSADDR: is_dup = True - if isinstance(nodeinst, NodeDeviceParser.NetDevice): + if nodeinst.device_type == nodeinst.CAPABILITY_TYPE_NET: parentname = nodeinst.parent return VirtualHostDevice.device_from_node(conn, name=parentname) @@ -61,14 +61,14 @@ class VirtualHostDevice(VirtualDevice): return dev def set_from_nodedev(self, nodedev, is_dup=False): - if isinstance(nodedev, NodeDeviceParser.PCIDevice): + if nodedev.device_type == NodeDevice.CAPABILITY_TYPE_PCI: self.type = "pci" self.domain = nodedev.domain self.bus = nodedev.bus self.slot = nodedev.slot self.function = nodedev.function - elif isinstance(nodedev, NodeDeviceParser.USBDevice): + elif nodedev.device_type == NodeDevice.CAPABILITY_TYPE_USBDEV: self.type = "usb" self.vendor = nodedev.vendor_id self.product = nodedev.product_id diff --git a/virtinst/nodedev.py b/virtinst/nodedev.py index 86dc03540..74b34b680 100644 --- a/virtinst/nodedev.py +++ b/virtinst/nodedev.py @@ -21,32 +21,86 @@ import logging import libvirt -from virtinst import util +from virtinst.xmlbuilder import XMLBuilder +from virtinst.xmlbuilder import XMLProperty as OrigXMLProperty -# 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" - -HOSTDEV_ADDR_TYPE_LIBVIRT = 0 -HOSTDEV_ADDR_TYPE_PCI = 1 -HOSTDEV_ADDR_TYPE_USB_BUSADDR = 2 -HOSTDEV_ADDR_TYPE_USB_VENPRO = 3 +# 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 NodeDevice(object): - def __init__(self, node): - self.name = None - self.parent = None - self.device_type = None +def _lookupNodeName(conn, name): + nodedev = conn.nodeDeviceLookupByName(name) + xml = nodedev.XMLDesc(0) + return NodeDevice.parse(conn, xml) - self._parseNodeXML(node) + +class NodeDevice(XMLBuilder): + 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" + + (HOSTDEV_ADDR_TYPE_LIBVIRT, + HOSTDEV_ADDR_TYPE_PCI, + HOSTDEV_ADDR_TYPE_USB_BUSADDR, + HOSTDEV_ADDR_TYPE_USB_VENPRO) = range(1, 5) + + @staticmethod + def lookupNodeName(conn, name): + """ + Convert the passed libvirt node device name to a NodeDevice + instance, with proper error reporting. If the name is name is not + found, we will attempt to parse the name as would be passed to + devAddressToNodeDev + + @param conn: libvirt.virConnect instance to perform the lookup on + @param name: libvirt node device name to lookup, or address for + devAddressToNodedev + + @rtype: L{NodeDevice} instance + """ + if not conn.check_conn_support(conn.SUPPORT_CONN_NODEDEV): + raise ValueError(_("Connection does not support host device " + "enumeration.")) + + try: + return (_lookupNodeName(conn, name), + NodeDevice.HOSTDEV_ADDR_TYPE_LIBVIRT) + except libvirt.libvirtError, e: + ret = _isAddressStr(name) + if not ret: + raise e + + return devAddressToNodedev(conn, name) + + @staticmethod + def parse(conn, xml): + tmpdev = NodeDevice(conn, parsexml=xml, allow_node_instantiate=True) + cls = _typeToDeviceClass(tmpdev.device_type) + return cls(conn, parsexml=xml, allow_node_instantiate=True) + + def __init__(self, *args, **kwargs): + instantiate = kwargs.pop("allow_node_instantiate", False) + if self.__class__ is NodeDevice and not instantiate: + raise RuntimeError("Can not instantiate NodeDevice directly") + XMLBuilder.__init__(self, *args, **kwargs) + + _XML_ROOT_NAME = "device" + + name = XMLProperty("./name") + parent = XMLProperty("./parent") + device_type = XMLProperty("./capability/@type") def pretty_name(self, child_dev=None): """ @@ -62,66 +116,16 @@ class NodeDevice(object): ignore = child_dev return self.name - 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 node.name in value_map: - 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) + hw_vendor = XMLProperty("./capability/hardware/vendor") + hw_version = XMLProperty("./capability/hardware/version") + hw_serial = XMLProperty("./capability/hardware/serial") + hw_uuid = XMLProperty("./capability/hardware/uuid") - 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 + fw_vendor = XMLProperty("./capability/firmware/vendor") + fw_version = XMLProperty("./capability/firmware/version") + fw_date = XMLProperty("./capability/firmware/release_date") def pretty_name(self, child_dev=None): ignore = child_dev @@ -135,25 +139,9 @@ class SystemDevice(NodeDevice): 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 + interface = XMLProperty("./capability/interface") + address = XMLProperty("./capability/address") + capability_type = XMLProperty("./capability/capability/@type") def pretty_name(self, child_dev=None): ignore = child_dev @@ -165,40 +153,15 @@ class NetDevice(NodeDevice): class PCIDevice(NodeDevice): - def __init__(self, node): - NodeDevice.__init__(self, node) + domain = XMLProperty("./capability/domain") + bus = XMLProperty("./capability/bus") + slot = XMLProperty("./capability/slot") + function = XMLProperty("./capability/function") - 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 + product_name = XMLProperty("./capability/product") + product_id = XMLProperty("./capability/product/@id") + vendor_name = XMLProperty("./capability/vendor") + vendor_id = XMLProperty("./capability/vendor/@id") def pretty_name(self, child_dev=None): devstr = "%.2X:%.2X:%X" % (int(self.bus), @@ -213,35 +176,13 @@ class PCIDevice(NodeDevice): class USBDevice(NodeDevice): - def __init__(self, node): - NodeDevice.__init__(self, node) + bus = XMLProperty("./capability/bus") + device = XMLProperty("./capability/device") - 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 + product_name = XMLProperty("./capability/product") + product_id = XMLProperty("./capability/product/@id") + vendor_name = XMLProperty("./capability/vendor") + vendor_id = XMLProperty("./capability/vendor/@id") def pretty_name(self, child_dev=None): ignore = child_dev @@ -252,56 +193,34 @@ class USBDevice(NodeDevice): class StorageDevice(NodeDevice): - def __init__(self, node): - NodeDevice.__init__(self, node) + block = XMLProperty("./capability/block") + bus = XMLProperty("./capability/bus") + drive_type = XMLProperty("./capability/drive_type") + size = XMLProperty("./capability/size", is_int=True) - self.block = None - self.bus = None - self.drive_type = None - self.size = 0 + model = XMLProperty("./capability/model") + vendor = XMLProperty("./capability/vendor") - self.model = None - self.vendor = None + hotpluggable = XMLProperty( + "./capability/capability[@type='hotpluggable']", is_bool=True) + removable = XMLProperty( + "./capability/capability[@type='removable']", is_bool=True) - self.removable = False - self.media_available = False - self.media_size = 0 - self.media_label = None - - 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) - elif rmchild.name == "media_label": - self.media_label = rmchild.content - rmchild = rmchild.next - else: - self._parseValueHelper(child, val_map) - - child = child.next + media_size = XMLProperty( + "./capability/capability[@type='removable']/media_size", is_int=True) + media_label = XMLProperty( + "./capability/capability[@type='removable']/media_label") + _media_available = XMLProperty( + "./capability/capability[@type='removable']/media_available", + is_int=True) + def _get_media_available(self): + m = self._media_available + if m is None: + return None + return bool(m) + def _set_media_available(self, val): + self._media_available = val + media_available = property(_get_media_available, _set_media_available) def pretty_name(self, child_dev=None): ignore = child_dev @@ -319,116 +238,30 @@ class StorageDevice(NodeDevice): 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) + number = XMLProperty("./capability/number") + classval = XMLProperty("./capability/class") + subclass = XMLProperty("./capability/subclass") + protocol = XMLProperty("./capability/protocol") 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) + host = XMLProperty("./capability/host") + bus = XMLProperty("./capability/bus") + target = XMLProperty("./capability/target") + lun = XMLProperty("./capability/lun") + type = XMLProperty("./capability/type") class SCSIBus(NodeDevice): - def __init__(self, node): - NodeDevice.__init__(self, node) + host = XMLProperty("./capability/host") - self.host = None + vport_ops = XMLProperty( + "./capability/capability[@type='vport_ops']", is_bool=True) - self.vport_ops = False - - self.fc_host = False - self.wwnn = None - self.wwpn = None - - self.parseXML(self._getCapabilityNode(node)) - - def parseXML(self, node): - val_map = {"host" : "host"} - - child = node.children - while child: - if child.name == "capability": - captype = child.prop("type") - - if captype == "vport_ops": - self.vport_ops = True - elif captype == "fc_host": - self.fc_host = True - fcchild = child.children - while fcchild: - if fcchild.name == "wwnn": - self.wwnn = fcchild.content - elif fcchild.name == "wwpn": - self.wwpn = fcchild.content - fcchild = fcchild.next - else: - self._parseValueHelper(child, val_map) - - child = child.next - - -def _lookupNodeName(conn, name): - nodedev = conn.nodeDeviceLookupByName(name) - xml = nodedev.XMLDesc(0) - return parse(xml) - - -def lookupNodeName(conn, name): - """ - Convert the passed libvirt node device name to a NodeDevice - instance, with proper error reporting. If the name is name is not - found, we will attempt to parse the name as would be passed to - devAddressToNodeDev - - @param conn: libvirt.virConnect instance to perform the lookup on - @param name: libvirt node device name to lookup, or address for - devAddressToNodedev - - @rtype: L{NodeDevice} instance - """ - if not conn.check_conn_support(conn.SUPPORT_CONN_NODEDEV): - raise ValueError(_("Connection does not support host device " - "enumeration.")) - - try: - return (_lookupNodeName(conn, name), - HOSTDEV_ADDR_TYPE_LIBVIRT) - except libvirt.libvirtError, e: - ret = _isAddressStr(name) - if not ret: - raise e - - return devAddressToNodedev(conn, name) + fc_host = XMLProperty( + "./capability/capability[@type='fc_host']", is_bool=True) + wwnn = XMLProperty("./capability/capability[@type='fc_host']/wwnn") + wwpn = XMLProperty("./capability/capability[@type='fc_host']/wwpn") def _isAddressStr(addrstr): @@ -438,7 +271,7 @@ def _isAddressStr(addrstr): try: # Determine addrstr type if addrstr.count(":") in [1, 2] and addrstr.count("."): - devtype = CAPABILITY_TYPE_PCI + devtype = NodeDevice.CAPABILITY_TYPE_PCI addrstr, func = addrstr.split(".", 1) addrstr, slot = addrstr.rsplit(":", 1) domain = "0" @@ -458,10 +291,10 @@ def _isAddressStr(addrstr): (int(nodedev.bus) == bus) and (int(nodedev.slot) == slot)) cmp_func = pci_cmp - addr_type = HOSTDEV_ADDR_TYPE_PCI + addr_type = NodeDevice.HOSTDEV_ADDR_TYPE_PCI elif addrstr.count(":"): - devtype = CAPABILITY_TYPE_USBDEV + devtype = NodeDevice.CAPABILITY_TYPE_USBDEV vendor, product = addrstr.split(":") vendor = int(vendor, 16) product = int(product, 16) @@ -470,10 +303,10 @@ def _isAddressStr(addrstr): return ((int(nodedev.vendor_id, 16) == vendor) and (int(nodedev.product_id, 16) == product)) cmp_func = usbprod_cmp - addr_type = HOSTDEV_ADDR_TYPE_USB_VENPRO + addr_type = NodeDevice.HOSTDEV_ADDR_TYPE_USB_VENPRO elif addrstr.count("."): - devtype = CAPABILITY_TYPE_USBDEV + devtype = NodeDevice.CAPABILITY_TYPE_USBDEV bus, addr = addrstr.split(".", 1) bus = int(bus) addr = int(addr) @@ -482,7 +315,7 @@ def _isAddressStr(addrstr): return ((int(nodedev.bus) == bus) and (int(nodedev.device) == addr)) cmp_func = usbaddr_cmp - addr_type = HOSTDEV_ADDR_TYPE_USB_BUSADDR + addr_type = NodeDevice.HOSTDEV_ADDR_TYPE_USB_BUSADDR except: logging.exception("Error parsing node device string.") return None @@ -533,49 +366,22 @@ def devAddressToNodedev(conn, addrstr): addrstr) -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 - """ - def _parse_func(root): - t = _findNodeType(root) - devclass = _typeToDeviceClass(t) - device = devclass(root) - return device - - return util.parse_node_helper(xml, "device", _parse_func) - - -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: + if t == NodeDevice.CAPABILITY_TYPE_SYSTEM: return SystemDevice - elif t == CAPABILITY_TYPE_NET: + elif t == NodeDevice.CAPABILITY_TYPE_NET: return NetDevice - elif t == CAPABILITY_TYPE_PCI: + elif t == NodeDevice.CAPABILITY_TYPE_PCI: return PCIDevice - elif t == CAPABILITY_TYPE_USBDEV: + elif t == NodeDevice.CAPABILITY_TYPE_USBDEV: return USBDevice - elif t == CAPABILITY_TYPE_USBBUS: + elif t == NodeDevice.CAPABILITY_TYPE_USBBUS: return USBBus - elif t == CAPABILITY_TYPE_STORAGE: + elif t == NodeDevice.CAPABILITY_TYPE_STORAGE: return StorageDevice - elif t == CAPABILITY_TYPE_SCSIBUS: + elif t == NodeDevice.CAPABILITY_TYPE_SCSIBUS: return SCSIBus - elif t == CAPABILITY_TYPE_SCSIDEV: + elif t == NodeDevice.CAPABILITY_TYPE_SCSIDEV: return SCSIDevice else: return NodeDevice diff --git a/virtinst/xmlbuilder.py b/virtinst/xmlbuilder.py index 7c880c4d1..78daaf648 100644 --- a/virtinst/xmlbuilder.py +++ b/virtinst/xmlbuilder.py @@ -333,7 +333,8 @@ class XMLProperty(property): set_converter=None, validate_cb=None, make_getter_xpath_cb=None, make_setter_xpath_cb=None, is_bool=False, is_int=False, is_yesno=False, is_onoff=False, - clear_first=None, default_cb=None, default_name=None): + clear_first=None, default_cb=None, default_name=None, + track=True): """ Set a XMLBuilder class property that represents a value in the XML. For example @@ -374,6 +375,8 @@ 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 @@ -404,7 +407,7 @@ class XMLProperty(property): if self._default_name and not self._default_cb: raise RuntimeError("default_name requires default_cb.") - if _trackprops: + if _trackprops and track: _allprops.append(self) property.__init__(self, fget=self.getter, fset=self.setter) @@ -907,7 +910,7 @@ class XMLBuilder(object): ret = {} for c in reversed(type.mro(self.__class__)[:-1]): for key, val in c.__dict__.items(): - if val.__class__ is checkclass: + if isinstance(val, checkclass): ret[key] = val setattr(self.__class__, cachename, ret) return getattr(self.__class__, cachename)