diff --git a/tests/cli-test-xml/compare/many-devices.xml b/tests/cli-test-xml/compare/many-devices.xml
index b5254729a..ee5da2a04 100644
--- a/tests/cli-test-xml/compare/many-devices.xml
+++ b/tests/cli-test-xml/compare/many-devices.xml
@@ -76,6 +76,11 @@
+
+
+
+
+
@@ -164,6 +169,11 @@
+
+
+
+
+
diff --git a/tests/clitest.py b/tests/clitest.py
index f8e2b0458..c59d8fad3 100644
--- a/tests/clitest.py
+++ b/tests/clitest.py
@@ -479,7 +479,7 @@ c = vinst.add_category("misc", "--nographics --noautoconsole")
c.add_compare("", "noargs-fail") # No arguments
c.add_compare("--hvm --nodisks --pxe --print-step all", "simple-pxe") # Diskless PXE install
c.add_compare("--hvm --cdrom %(EXISTIMG2)s --file %(EXISTIMG1)s --os-variant win2k3 --wait 0 --vcpus cores=4", "w2k3-cdrom") # HVM windows install with disk
-c.add_compare("""--hvm --pxe --controller usb,model=ich9-ehci1,address=0:0:4.7,index=0 --controller usb,model=ich9-uhci1,address=0:0:4.0,index=0,master=0 --controller usb,model=ich9-uhci2,address=0:0:4.1,index=0,master=2 --controller usb,model=ich9-uhci3,address=0:0:4.2,index=0,master=4 --disk %(MANAGEDEXISTUPPER)s,cache=writeback,io=threads,perms=sh,serial=WD-WMAP9A966149 --disk %(NEWIMG1)s,sparse=false,size=.001,perms=ro,error_policy=enospace --disk device=cdrom,bus=sata --serial tcp,host=:2222,mode=bind,protocol=telnet --filesystem /source,/target,mode=squash --network user,mac=12:34:56:78:11:22 --network bridge=foobar,model=virtio --channel spicevmc --smartcard passthrough,type=spicevmc --tpm passthrough,model=tpm-tis,path=/dev/tpm0 --security type=static,label='system_u:object_r:svirt_image_t:s0:c100,c200',relabel=yes --numatune \\"1-3,5\\",mode=preferred --boot loader=/foo/bar """, "many-devices") # Lots of devices
+c.add_compare("""--hvm --pxe --controller usb,model=ich9-ehci1,address=0:0:4.7,index=0 --controller usb,model=ich9-uhci1,address=0:0:4.0,index=0,master=0 --controller usb,model=ich9-uhci2,address=0:0:4.1,index=0,master=2 --controller usb,model=ich9-uhci3,address=0:0:4.2,index=0,master=4 --disk %(MANAGEDEXISTUPPER)s,cache=writeback,io=threads,perms=sh,serial=WD-WMAP9A966149 --disk %(NEWIMG1)s,sparse=false,size=.001,perms=ro,error_policy=enospace --disk device=cdrom,bus=sata --serial tcp,host=:2222,mode=bind,protocol=telnet --filesystem /source,/target,mode=squash --network user,mac=12:34:56:78:11:22 --network bridge=foobar,model=virtio --channel spicevmc --smartcard passthrough,type=spicevmc --tpm passthrough,model=tpm-tis,path=/dev/tpm0 --security type=static,label='system_u:object_r:svirt_image_t:s0:c100,c200',relabel=yes --numatune \\"1-3,5\\",mode=preferred --boot loader=/foo/bar --host-device net_00_1c_25_10_b1_e4""", "many-devices") # Lots of devices
c.add_valid("--hvm --disk path=virt-install,device=cdrom") # Specifying cdrom media via --disk
c.add_valid("--hvm --import --disk path=virt-install") # FV Import install
c.add_valid("--hvm --import --disk path=virt-install --prompt --force") # Working scenario w/ prompt shouldn't ask anything
diff --git a/tests/nodedev.py b/tests/nodedev.py
index 1aeea7d95..d549c67e6 100644
--- a/tests/nodedev.py
+++ b/tests/nodedev.py
@@ -64,8 +64,8 @@ class TestNodeDev(unittest.TestCase):
if not nodedev:
nodedev = self._nodeDevFromName(nodename)
- dev = VirtualHostDevice.device_from_node(conn, nodedev=nodedev,
- is_dup=is_dup)
+ dev = VirtualHostDevice(conn)
+ dev.set_from_nodedev(nodedev, use_full_usb=is_dup)
utils.diff_compare(dev.get_xml_config() + "\n", devfile)
def testSystemDevice(self):
diff --git a/virtManager/addhardware.py b/virtManager/addhardware.py
index 7a1dc8f99..cf0f15a7a 100644
--- a/virtManager/addhardware.py
+++ b/virtManager/addhardware.py
@@ -1485,16 +1485,13 @@ class vmmAddHardware(vmmGObjectUI):
raise RuntimeError(_("Could not find USB device "
"(vendorId: %s, productId: %s) "
% (vendor, product)))
-
if count > 1:
is_dup = True
try:
- self._dev = virtinst.VirtualHostDevice.device_from_node(
- conn=self.conn.get_backend(),
- name=nodedev_name,
- nodedev=nodedev,
- is_dup=is_dup)
+ dev = virtinst.VirtualHostDevice(self.conn.get_backend())
+ dev.set_from_nodedev(nodedev, use_full_usb=is_dup)
+ self._dev = dev
except Exception, e:
return self.err.val_err(_("Host device parameter error"), e)
diff --git a/virtManager/details.py b/virtManager/details.py
index 4ee2dee65..58789b735 100644
--- a/virtManager/details.py
+++ b/virtManager/details.py
@@ -278,8 +278,7 @@ def lookup_nodedev(vmmconn, hostdev):
devtype = hostdev.type
found_dev = None
- vendor_id = product_id = bus = device = \
- domain = slot = func = None
+ vendor_id = product_id = bus = device = domain = slot = func = None
# For USB we want a device, not a bus
if devtype == 'usb':
diff --git a/virtinst/cli.py b/virtinst/cli.py
index 11ec3b933..4556b2858 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -1919,8 +1919,11 @@ def parse_sound(guest, optstr, dev=None):
#####################
def parse_hostdev(guest, optstr, dev=None):
- return virtinst.VirtualHostDevice.device_from_node(guest.conn,
- name=optstr,
- dev=dev)
+ if not dev:
+ dev = virtinst.VirtualHostDevice(guest.conn)
+
+ nodedev = virtinst.NodeDevice.lookupNodeName(guest.conn, optstr)
+ dev.set_from_nodedev(nodedev)
+ return dev
get_hostdevs = _make_handler("hostdev", parse_hostdev)
diff --git a/virtinst/devicehostdev.py b/virtinst/devicehostdev.py
index 7f8793aee..5253d65b1 100644
--- a/virtinst/devicehostdev.py
+++ b/virtinst/devicehostdev.py
@@ -25,42 +25,17 @@ from virtinst.xmlbuilder import XMLProperty
class VirtualHostDevice(VirtualDevice):
virtual_device_type = VirtualDevice.VIRTUAL_DEV_HOSTDEV
- @staticmethod
- def device_from_node(conn, name=None, nodedev=None, is_dup=False,
- dev=None):
+ def set_from_nodedev(self, nodedev, use_full_usb=None):
"""
- Convert the passed device name to a VirtualHostDevice
- instance, with proper error reporting. Name can be any of the
- 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.
-
- @param conn: libvirt.virConnect instance to perform the lookup on
- @param name: optional libvirt node device name to lookup
- @param nodedev: optional L{virtinst.NodeDevice} instance to use
-
- @rtype: L{virtinst.VirtualHostDevice} instance
+ @use_full_usb: If set, and nodedev is USB, specify both
+ vendor and product. Used if user requests bus/add on virt-install
+ command line, or if virt-manager detects a dup USB device
+ and we need to differentiate
"""
- if not name and not nodedev:
- raise ValueError("'name' or 'nodedev' required.")
+ if (use_full_usb is None and
+ nodedev.addr_type == nodedev.HOSTDEV_ADDR_TYPE_USB_BUSADDR):
+ use_full_usb = True
- if nodedev:
- nodeinst = nodedev
- else:
- nodeinst, addr_type = NodeDevice.lookupNodeName(conn, name)
- if addr_type == NodeDevice.HOSTDEV_ADDR_TYPE_USB_BUSADDR:
- is_dup = True
-
- if nodeinst.device_type == nodeinst.CAPABILITY_TYPE_NET:
- parentname = nodeinst.parent
- return VirtualHostDevice.device_from_node(conn,
- name=parentname)
- if not dev:
- dev = VirtualHostDevice(conn)
- dev.set_from_nodedev(nodeinst, is_dup)
- return dev
-
- def set_from_nodedev(self, nodedev, is_dup=False):
if nodedev.device_type == NodeDevice.CAPABILITY_TYPE_PCI:
self.type = "pci"
self.domain = nodedev.domain
@@ -73,9 +48,14 @@ class VirtualHostDevice(VirtualDevice):
self.vendor = nodedev.vendor_id
self.product = nodedev.product_id
- if is_dup:
+ if use_full_usb:
self.bus = nodedev.bus
self.device = nodedev.device
+
+ elif nodedev.device_type == nodedev.CAPABILITY_TYPE_NET:
+ parentnode = nodedev.lookupNodeName(self.conn, nodedev.parent)
+ self.set_from_nodedev(parentnode, use_full_usb=use_full_usb)
+
else:
raise ValueError("Unknown node device type %s" % nodedev)
diff --git a/virtinst/nodedev.py b/virtinst/nodedev.py
index 74b34b680..7907a8d20 100644
--- a/virtinst/nodedev.py
+++ b/virtinst/nodedev.py
@@ -36,7 +36,13 @@ class XMLProperty(OrigXMLProperty):
def _lookupNodeName(conn, name):
- nodedev = conn.nodeDeviceLookupByName(name)
+ try:
+ nodedev = conn.nodeDeviceLookupByName(name)
+ except libvirt.libvirtError, e:
+ raise libvirt.libvirtError(
+ _("Did not find node device '%s': %s" %
+ (name, str(e))))
+
xml = nodedev.XMLDesc(0)
return NodeDevice.parse(conn, xml)
@@ -66,7 +72,7 @@ class NodeDevice(XMLBuilder):
@param conn: libvirt.virConnect instance to perform the lookup on
@param name: libvirt node device name to lookup, or address for
- devAddressToNodedev
+ _devAddressToNodedev
@rtype: L{NodeDevice} instance
"""
@@ -75,14 +81,13 @@ class NodeDevice(XMLBuilder):
"enumeration."))
try:
- return (_lookupNodeName(conn, name),
- NodeDevice.HOSTDEV_ADDR_TYPE_LIBVIRT)
+ return _lookupNodeName(conn, name)
except libvirt.libvirtError, e:
ret = _isAddressStr(name)
if not ret:
raise e
- return devAddressToNodedev(conn, name)
+ return _devAddressToNodedev(conn, name)
@staticmethod
def parse(conn, xml):
@@ -94,6 +99,9 @@ class NodeDevice(XMLBuilder):
instantiate = kwargs.pop("allow_node_instantiate", False)
if self.__class__ is NodeDevice and not instantiate:
raise RuntimeError("Can not instantiate NodeDevice directly")
+
+ self.addr_type = None
+
XMLBuilder.__init__(self, *args, **kwargs)
_XML_ROOT_NAME = "device"
@@ -316,6 +324,8 @@ def _isAddressStr(addrstr):
(int(nodedev.device) == addr))
cmp_func = usbaddr_cmp
addr_type = NodeDevice.HOSTDEV_ADDR_TYPE_USB_BUSADDR
+ else:
+ return None
except:
logging.exception("Error parsing node device string.")
return None
@@ -323,7 +333,7 @@ def _isAddressStr(addrstr):
return cmp_func, devtype, addr_type
-def devAddressToNodedev(conn, addrstr):
+def _devAddressToNodedev(conn, addrstr):
"""
Look up the passed host device address string as a libvirt node device,
parse its xml, and return a NodeDevice instance.
@@ -335,10 +345,6 @@ def devAddressToNodedev(conn, addrstr):
- (domain:)bus:slot.func (ex. 00:10.0 for a pci device)
@param addrstr: C{str}
"""
- if not conn.check_conn_support(conn.SUPPORT_CONN_NODEDEV):
- raise ValueError(_("Connection does not support host device "
- "enumeration."))
-
ret = _isAddressStr(addrstr)
if not ret:
raise ValueError(_("Could not determine format of '%s'") % addrstr)
@@ -357,7 +363,8 @@ def devAddressToNodedev(conn, addrstr):
count += 1
if count == 1:
- return nodedev, addr_type
+ nodedev.addr_type = addr_type
+ return nodedev
elif count > 1:
raise ValueError(_("%s corresponds to multiple node devices") %
addrstr)