[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
Re: [et-mgmt-tools] [PATCH 2/3]: Add VirtualHostDevice classes
- From: Cole Robinson <crobinso redhat com>
- To: Fedora/Linux Management Tools <et-mgmt-tools redhat com>
- Subject: Re: [et-mgmt-tools] [PATCH 2/3]: Add VirtualHostDevice classes
- Date: Mon, 02 Mar 2009 17:48:40 -0500
Cole Robinson wrote:
> Add VirtualHostDevice classes for build domain 'hostdev' device xml,
> along with associated tests.
>
> This is currently incomplete: I'm not entirely clear on how a managed
> vs. unmanaged device interacts with HostDeviceAttach/Reset, and if there
> are differences in whats applicable for USB vs. PCI devices. The libvirt
> API for all this hasn't officially landed yet either so this is blocked
> until then.
>
Okay, I think this updated version should be sufficient now.
Thanks,
Cole
# HG changeset patch
# User Cole Robinson <crobinso redhat com>
# Node ID 17e1c491f429e984e96fb61ca6ae17be4d1e285c
# Parent daf6b88c04485828bd8e8edd68e5a62ef38b4be6
Add VirtualHostDevice classes, for attaching physical host devices to a guest.
diff -r daf6b88c0448 -r 17e1c491f429 tests/nodedev-xml/devxml/pcidev.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/devxml/pcidev.xml Mon Mar 02 10:40:55 2009 -0500
@@ -0,0 +1,5 @@
+ <hostdev mode='subsystem' type='pci' managed='yes'>
+ <source>
+ <address domain='0' bus='21' slot='0' function='4'/>
+ </source>
+ </hostdev>
diff -r daf6b88c0448 -r 17e1c491f429 tests/nodedev-xml/devxml/usbdev1.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/devxml/usbdev1.xml Mon Mar 02 10:40:55 2009 -0500
@@ -0,0 +1,6 @@
+ <hostdev mode='subsystem' type='usb' managed='yes'>
+ <source>
+ <vendor id='0x0781'/>
+ <product id='0x5151'/>
+ </source>
+ </hostdev>
diff -r daf6b88c0448 -r 17e1c491f429 tests/nodedev-xml/devxml/usbdev2.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/nodedev-xml/devxml/usbdev2.xml Mon Mar 02 10:40:55 2009 -0500
@@ -0,0 +1,5 @@
+ <hostdev mode='subsystem' type='usb' managed='yes'>
+ <source>
+ <address bus='1' device='4'/>
+ </source>
+ </hostdev>
diff -r daf6b88c0448 -r 17e1c491f429 tests/nodedev.py
--- a/tests/nodedev.py Mon Mar 02 10:10:18 2009 -0500
+++ b/tests/nodedev.py Mon Mar 02 10:40:55 2009 -0500
@@ -14,9 +14,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
+import tests
import os.path
import unittest
import virtinst.NodeDeviceParser as nodeparse
+from virtinst import VirtualHostDevice
import libvirt
conn = libvirt.open("test:///default")
@@ -33,6 +35,14 @@
for attr in vals.keys():
self.assertEqual(vals[attr], getattr(dev, attr))
+ def _testNode2DeviceCompare(self, nodefile, devfile, nodedev=None):
+ devfile = os.path.join("tests/nodedev-xml/devxml", devfile)
+ if not nodedev:
+ nodedev = self._nodeDevFromFile(nodefile)
+
+ dev = VirtualHostDevice.device_from_node(conn, nodedev=nodedev)
+ tests.diff_compare(dev.get_xml_config(), devfile)
+
def testSystemDevice(self):
filename = "system.xml"
vals = {"hw_vendor": "LENOVO", "hw_version": "ThinkPad T61",
@@ -150,5 +160,37 @@
"type": "disk"}
self._testCompare(filename, vals)
+
+ # NodeDevice 2 Device XML tests
+ def testNodeDev2USB1(self):
+ nodefile = "usbdev1.xml"
+ devfile = "usbdev1.xml"
+ self._testNode2DeviceCompare(nodefile, devfile)
+
+ def testNodeDev2USB2(self):
+ nodefile = "usbdev1.xml"
+ devfile = "usbdev2.xml"
+ nodedev = self._nodeDevFromFile(nodefile)
+
+ # Force xml building to use bus, addr
+ nodedev.product_id = None
+ nodedev.vendor_id = None
+
+ self._testNode2DeviceCompare(nodefile, devfile, nodedev=nodedev)
+
+ def testNodeDev2PCI(self):
+ nodefile = "pci1.xml"
+ devfile = "pcidev.xml"
+ self._testNode2DeviceCompare(nodefile, devfile)
+
+ def testNodeDevFail(self):
+ nodefile = "usbbus.xml"
+ devfile = ""
+
+ # This should exist, since usbbus is not a valid device to
+ # pass to a guest.
+ self.assertRaises(ValueError,
+ self._testNode2DeviceCompare, nodefile, devfile)
+
if __name__ == "__main__":
unittest.main()
diff -r daf6b88c0448 -r 17e1c491f429 virtinst/Guest.py
--- a/virtinst/Guest.py Mon Mar 02 10:10:18 2009 -0500
+++ b/virtinst/Guest.py Mon Mar 02 10:40:55 2009 -0500
@@ -79,6 +79,7 @@
self.disks = []
self.nics = []
self.sound_devs = []
+ self.hostdevs = []
# Device lists to use/alter during install process
self._install_disks = []
@@ -413,6 +414,12 @@
xml = _util.xml_append(xml, sound_dev.get_xml_config())
return xml
+ def _get_hostdev_xml(self):
+ xml = ""
+ for hostdev in self.hostdevs:
+ xml = _util.xml_append(xml, hostdev.get_xml_config())
+ return xml
+
def _get_device_xml(self, install=True):
xml = ""
@@ -421,6 +428,7 @@
xml = _util.xml_append(xml, self._get_input_xml())
xml = _util.xml_append(xml, self._get_graphics_xml())
xml = _util.xml_append(xml, self._get_sound_xml())
+ xml = _util.xml_append(xml, self._get_hostdev_xml())
return xml
def _get_features_xml(self):
@@ -582,12 +590,14 @@
if self._installer.install_disk is not None:
self._install_disks.append(self._installer.install_disk)
- def _create_devices(self,progresscb):
+ def _create_devices(self, progresscb):
"""Ensure that devices are setup"""
for disk in self._install_disks:
disk.setup(progresscb)
for nic in self._install_nics:
nic.setup(self.conn)
+ for hostdev in self.hostdevs:
+ hostdev.setup()
def _do_install(self, consolecb, meter, removeOld=False, wait=True):
vm = None
diff -r daf6b88c0448 -r 17e1c491f429 virtinst/NodeDeviceParser.py
--- a/virtinst/NodeDeviceParser.py Mon Mar 02 10:10:18 2009 -0500
+++ b/virtinst/NodeDeviceParser.py Mon Mar 02 10:40:55 2009 -0500
@@ -330,6 +330,25 @@
return True
+def is_pci_detach_capable(conn):
+ """
+ Check if the passed libvirt connection support pci device Detach/Reset
+
+ @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("virNodeDeviceDettach") == 0:
+ return False
+
+ return True
+
def lookupNodeName(conn, name):
"""
Convert the passed libvirt node device name to a NodeDevice
diff -r daf6b88c0448 -r 17e1c491f429 virtinst/VirtualHostDevice.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/virtinst/VirtualHostDevice.py Mon Mar 02 10:40:55 2009 -0500
@@ -0,0 +1,209 @@
+#
+# 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 VirtualDevice
+import NodeDeviceParser
+import logging
+from virtinst import _virtinst as _
+
+class VirtualHostDevice(VirtualDevice.VirtualDevice):
+
+ def device_from_node(conn, name=None, nodedev=None):
+ """
+ Convert the passed libvirt node device name to a VirtualHostDevice
+ 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{virtinst.VirtualHostDevice} instance
+ """
+
+ if not name and not nodedev:
+ raise ValueError(_("'name' or 'nodedev' required."))
+
+ if nodedev:
+ nodeinst = nodedev
+ else:
+ nodeinst = NodeDeviceParser.lookupNodeName(conn, name)
+
+ if isinstance(nodeinst, NodeDeviceParser.PCIDevice):
+ return VirtualHostDevicePCI(conn, nodedev=nodeinst)
+ elif isinstance(nodeinst, NodeDeviceParser.USBDevice):
+ return VirtualHostDeviceUSB(conn, nodedev=nodeinst)
+ elif isinstance(nodeinst, NodeDeviceParser.NetDevice):
+ parentname = nodeinst.parent
+ try:
+ return VirtualHostDevice.device_from_node(conn,
+ name=parentname)
+ except:
+ logging.exception("Fetching net parent device failed.")
+
+ raise ValueError(_("Node device type '%s' cannot be attached to "
+ " guest.") % nodeinst.device_type)
+
+ device_from_node = staticmethod(device_from_node)
+
+ def __init__(self, conn, nodedev):
+ """
+ @param conn: Connection the device/guest will be installed on
+ @type conn: libvirt.virConnect
+ @param nodedev: Optional NodeDevice instance for device being
+ attached to the guest
+ @type nodedev: L{virtinst.NodeDeviceParser.NodeDevice}
+ """
+ VirtualDevice.VirtualDevice.__init__(self, conn)
+
+ self.mode = None
+ self.type = None
+
+ self.managed = True
+
+ self._nodedev = nodedev
+
+ def _get_source_xml(self):
+ raise NotImplementedError("Must be implemented in subclass")
+
+ def setup(self, conn = None):
+ """
+ Perform DeviceDetach and DeviceReset calls if necessary
+
+ @param conn: libvirt virConnect instance to use (defaults to devices
+ connection)
+ """
+ raise NotImplementedError
+
+ def get_xml_config(self):
+ xml = (" <hostdev mode='%s' type='%s' managed='%s'>\n" % \
+ (self.mode, self.type, self.managed and "yes" or "no"))
+ xml += " <source>\n"
+ xml += self._get_source_xml()
+ xml += " </source>\n"
+ xml += " </hostdev>\n"
+ return xml
+
+
+class VirtualHostDeviceUSB(VirtualHostDevice):
+
+ def __init__(self, conn, nodedev=None):
+ VirtualHostDevice.__init__(self, conn, nodedev)
+
+ self.mode = "subsystem"
+ self.type = "usb"
+
+ self.vendor = None
+ self.product = None
+
+ self.bus = None
+ self.device = None
+
+ self._set_from_nodedev(self._nodedev)
+
+
+ def _set_from_nodedev(self, nodedev):
+ if not nodedev:
+ return
+
+ if not isinstance(nodedev, NodeDeviceParser.USBDevice):
+ raise ValueError(_("'nodedev' must be a USBDevice instance."))
+
+ self.vendor = nodedev.vendor_id
+ self.product = nodedev.product_id
+ self.bus = nodedev.bus
+ self.device = nodedev.device
+
+ def _get_source_xml(self):
+ xml = ""
+ if self.vendor and self.product:
+ xml += " <vendor id='%s'/>\n" % self.vendor
+ xml += " <product id='%s'/>\n" % self.product
+ elif self.bus and self.device:
+ xml += " <address bus='%s' device='%s'/>\n" % (self.bus,
+ self.device)
+ else:
+ raise RuntimeError(_("'vendor' and 'product', or 'bus' and "
+ " 'device' are required."))
+ return xml
+
+
+ def setup(self, conn = None):
+ if not conn:
+ conn = self.conn
+
+ # No libvirt api support for USB Detach/Reset yet
+ return
+
+class VirtualHostDevicePCI(VirtualHostDevice):
+
+ def __init__(self, conn, nodedev=None):
+ VirtualHostDevice.__init__(self, conn, nodedev)
+
+ self.mode = "subsystem"
+ self.type = "pci"
+
+ self.domain = "0x0"
+ self.bus = None
+ self.slot = None
+ self.function = None
+
+ self._set_from_nodedev(self._nodedev)
+
+
+ def _set_from_nodedev(self, nodedev):
+ if not nodedev:
+ return
+
+ if not isinstance(nodedev, NodeDeviceParser.PCIDevice):
+ raise ValueError(_("'nodedev' must be a PCIDevice instance."))
+
+ self.domain = nodedev.domain
+ self.bus = nodedev.bus
+ self.slot = nodedev.slot
+ self.function = nodedev.function
+
+ def _get_source_xml(self):
+ if not (self.domain and self.bus and self.slot and self.function):
+ raise RuntimeError(_("'domain', 'bus', 'slot', and 'function' "
+ "must be specified."))
+
+ xml = " <address domain='%s' bus='%s' slot='%s' function='%s'/>\n"
+ return xml % (self.domain, self.bus, self.slot, self.function)
+
+ def setup(self, conn = None):
+ """
+ Perform DeviceDetach and DeviceReset calls if necessary
+
+ @param conn: libvirt virConnect instance to use (defaults to devices
+ connection)
+ """
+ if not conn:
+ conn = self.conn
+
+ if not NodeDeviceParser.is_pci_detach_capable(conn):
+ return
+
+ try:
+ # Do this as a sanity check, so that we don't fail at domain
+ # start time
+ self._nodedev.deviceDetach()
+ self._nodedev.deviceReset()
+ except Exception, e:
+ raise RuntimeError(_("Could not detach PCI device: %s" % str(e)))
+
+
diff -r daf6b88c0448 -r 17e1c491f429 virtinst/__init__.py
--- a/virtinst/__init__.py Mon Mar 02 10:10:18 2009 -0500
+++ b/virtinst/__init__.py Mon Mar 02 10:40:55 2009 -0500
@@ -32,6 +32,8 @@
from VirtualGraphics import VirtualGraphics
from VirtualAudio import VirtualAudio
from VirtualDisk import VirtualDisk, XenDisk
+from VirtualHostDevice import (VirtualHostDevice, VirtualHostDeviceUSB,
+ VirtualHostDevicePCI)
from FullVirtGuest import FullVirtGuest
from ParaVirtGuest import ParaVirtGuest
from DistroInstaller import DistroInstaller
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]