2
# Copyright 2009 Red Hat, Inc.
3
# Cole Robinson <crobinso@redhat.com>
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
import NodeDeviceParser
23
from virtinst import _virtinst as _
25
class VirtualHostDevice(VirtualDevice.VirtualDevice):
27
def device_from_node(conn, name=None, nodedev=None):
29
Convert the passed libvirt node device name to a VirtualHostDevice
30
instance, with proper error reporting.
32
@param conn: libvirt.virConnect instance to perform the lookup on
33
@param name: libvirt node device name to lookup
35
@rtype: L{virtinst.VirtualHostDevice} instance
38
if not name and not nodedev:
39
raise ValueError(_("'name' or 'nodedev' required."))
44
nodeinst = NodeDeviceParser.lookupNodeName(conn, name)
46
if isinstance(nodeinst, NodeDeviceParser.PCIDevice):
47
return VirtualHostDevicePCI(conn, nodedev=nodeinst)
48
elif isinstance(nodeinst, NodeDeviceParser.USBDevice):
49
return VirtualHostDeviceUSB(conn, nodedev=nodeinst)
50
elif isinstance(nodeinst, NodeDeviceParser.NetDevice):
51
parentname = nodeinst.parent
53
return VirtualHostDevice.device_from_node(conn,
56
logging.exception("Fetching net parent device failed.")
58
raise ValueError(_("Node device type '%s' cannot be attached to "
59
" guest.") % nodeinst.device_type)
61
device_from_node = staticmethod(device_from_node)
63
def __init__(self, conn, nodedev):
65
@param conn: Connection the device/guest will be installed on
66
@type conn: libvirt.virConnect
67
@param nodedev: Optional NodeDevice instance for device being
69
@type nodedev: L{virtinst.NodeDeviceParser.NodeDevice}
71
VirtualDevice.VirtualDevice.__init__(self, conn)
78
self._nodedev = nodedev
80
def _get_source_xml(self):
81
raise NotImplementedError("Must be implemented in subclass")
83
def setup(self, conn = None):
85
Perform DeviceDetach and DeviceReset calls if necessary
87
@param conn: libvirt virConnect instance to use (defaults to devices
90
raise NotImplementedError
92
def get_xml_config(self):
93
xml = (" <hostdev mode='%s' type='%s' managed='%s'>\n" % \
94
(self.mode, self.type, self.managed and "yes" or "no"))
96
xml += self._get_source_xml()
98
xml += " </hostdev>\n"
102
class VirtualHostDeviceUSB(VirtualHostDevice):
104
def __init__(self, conn, nodedev=None):
105
VirtualHostDevice.__init__(self, conn, nodedev)
107
self.mode = "subsystem"
116
self._set_from_nodedev(self._nodedev)
119
def _set_from_nodedev(self, nodedev):
123
if not isinstance(nodedev, NodeDeviceParser.USBDevice):
124
raise ValueError(_("'nodedev' must be a USBDevice instance."))
126
self.vendor = nodedev.vendor_id
127
self.product = nodedev.product_id
128
self.bus = nodedev.bus
129
self.device = nodedev.device
131
def _get_source_xml(self):
133
if self.vendor and self.product:
134
xml += " <vendor id='%s'/>\n" % self.vendor
135
xml += " <product id='%s'/>\n" % self.product
136
elif self.bus and self.device:
137
xml += " <address bus='%s' device='%s'/>\n" % (self.bus,
140
raise RuntimeError(_("'vendor' and 'product', or 'bus' and "
141
" 'device' are required."))
145
def setup(self, conn = None):
149
# No libvirt api support for USB Detach/Reset yet
152
class VirtualHostDevicePCI(VirtualHostDevice):
154
def __init__(self, conn, nodedev=None):
155
VirtualHostDevice.__init__(self, conn, nodedev)
157
self.mode = "subsystem"
165
self._set_from_nodedev(self._nodedev)
168
def _set_from_nodedev(self, nodedev):
172
if not isinstance(nodedev, NodeDeviceParser.PCIDevice):
173
raise ValueError(_("'nodedev' must be a PCIDevice instance."))
175
self.domain = nodedev.domain
176
self.bus = nodedev.bus
177
self.slot = nodedev.slot
178
self.function = nodedev.function
180
def _get_source_xml(self):
181
if not (self.domain and self.bus and self.slot and self.function):
182
raise RuntimeError(_("'domain', 'bus', 'slot', and 'function' "
183
"must be specified."))
185
xml = " <address domain='%s' bus='%s' slot='%s' function='%s'/>\n"
186
return xml % (self.domain, self.bus, self.slot, self.function)
188
def setup(self, conn = None):
190
Perform DeviceDetach and DeviceReset calls if necessary
192
@param conn: libvirt virConnect instance to use (defaults to devices
198
if not NodeDeviceParser.is_pci_detach_capable(conn):
202
# Do this as a sanity check, so that we don't fail at domain
204
self._nodedev.deviceDetach()
205
self._nodedev.deviceReset()
207
raise RuntimeError(_("Could not detach PCI device: %s" % str(e)))