[virt-tools-list] [PATCH 2/4] Add advanced --controller support, augmenting VirtualController

Marc-André Lureau marcandre.lureau at gmail.com
Fri Sep 2 01:21:17 UTC 2011


This allow support for USB companion controllers and such.
See man/en/virt-install.pod.in doc.

We may want to add too a simpler --controller ich9-with-companions, or
just --controller usb2.
---
 man/en/virt-install.1                         |   31 ++++++++++-
 man/en/virt-install.pod.in                    |   39 ++++++++++++-
 tests/cli-test-xml/compare/many-devices.xml   |   30 ++++++++++
 tests/clitest.py                              |   26 ++++++++
 tests/utils.py                                |    8 +-
 tests/xmlparse-xml/change-controllers-in.xml  |    4 +
 tests/xmlparse-xml/change-controllers-out.xml |    4 +
 tests/xmlparse.py                             |    9 +++
 virt-install                                  |    1 +
 virtinst/VirtualController.py                 |   78 +++++++++++++++++++++++--
 virtinst/VirtualDevice.py                     |   49 +++++++++++++++-
 virtinst/XMLBuilderDomain.py                  |   10 +++
 virtinst/cli.py                               |   43 ++++++++++++++
 13 files changed, 317 insertions(+), 15 deletions(-)

diff --git a/man/en/virt-install.1 b/man/en/virt-install.1
index 0b73192..7bd35df 100644
--- a/man/en/virt-install.1
+++ b/man/en/virt-install.1
@@ -847,7 +847,7 @@ completeness).
 .IP "\-\-virt\-type" 2
 .IX Item "--virt-type"
 The hypervisor to install on. Example choices are kvm, qemu, xen, or kqemu.
-Availabile options are listed via 'virsh capabilities' in the <domain> tags.
+Available options are listed via 'virsh capabilities' in the <domain> tags.
 .IP "\-\-accelerate" 2
 .IX Item "--accelerate"
 Prefer \s-1KVM\s0 or \s-1KQEMU\s0 (in that order) if installing a \s-1QEMU\s0 guest. This behavior
@@ -861,6 +861,35 @@ Force disable \s-1APIC\s0 for the guest.
 Force disable \s-1ACPI\s0 for the guest.
 .SS "Device Options"
 .IX Subsection "Device Options"
+.IP "\-\-controller=TYPE[,OPTS]" 2
+.IX Item "--controller=TYPE[,OPTS]"
+Attach a controller device to the guest. \s-1TYPE\s0 is one of:
+\&\fBide\fR, \fBfdc\fR, \fBscsi\fR, \fBsata\fR, \fBvirtio-serial\fR, or \fBusb\fR.
+.RS 2
+.IP "\fBmodel\fR" 4
+.IX Item "model"
+Controller model.
+.IP "\fBaddress\fR" 4
+.IX Item "address"
+Controller address, current \s-1PCI\s0 of form 'bus:domain:slot:function'.
+.IP "\fBindex\fR" 4
+.IX Item "index"
+A decimal integer describing in which order the bus controller is
+encountered, and to reference the controller bus.
+.IP "\fBmaster\fR" 4
+.IX Item "master"
+Applicable to \s-1USB\s0 companion controllers, to define the master bus startport.
+.RE
+.RS 2
+.Sp
+Example:
+.IP "\fB\-\-controller usb,model=ich9\-uhci2,address=0:0:4.7,index=0,master=2\fR" 4
+.IX Item "--controller usb,model=ich9-uhci2,address=0:0:4.7,index=0,master=2"
+Adds a \s-1ICH9\s0 \s-1USB\s0 companion controller on \s-1PCI\s0 address 0:0:4.7 with
+master bus 0 and first port 2.
+.RE
+.RS 2
+.RE
 .IP "\-\-host\-device=HOSTDEV" 2
 .IX Item "--host-device=HOSTDEV"
 Attach a physical host device to the guest. Some example values for \s-1HOSTDEV:\s0
diff --git a/man/en/virt-install.pod.in b/man/en/virt-install.pod.in
index 155cfa2..da4142d 100644
--- a/man/en/virt-install.pod.in
+++ b/man/en/virt-install.pod.in
@@ -797,7 +797,7 @@ completeness).
 =item --virt-type
 
 The hypervisor to install on. Example choices are kvm, qemu, xen, or kqemu.
-Availabile options are listed via 'virsh capabilities' in the <domain> tags.
+Available options are listed via 'virsh capabilities' in the <domain> tags.
 
 =item  --accelerate
 
@@ -823,6 +823,43 @@ Force disable ACPI for the guest.
 
 =over 2
 
+=item --controller=TYPE[,OPTS]
+
+Attach a controller device to the guest. TYPE is one of:
+B<ide>, B<fdc>, B<scsi>, B<sata>, B<virtio-serial>, or B<usb>.
+
+=over 4
+
+=item B<model>
+
+Controller model.
+
+=item B<address>
+
+Controller address, current PCI of form 'bus:domain:slot:function'.
+
+=item B<index>
+
+A decimal integer describing in which order the bus controller is
+encountered, and to reference the controller bus.
+
+=item B<master>
+
+Applicable to USB companion controllers, to define the master bus startport.
+
+=back
+
+Example:
+
+=over 4
+
+=item B<--controller usb,model=ich9-uhci2,address=0:0:4.7,index=0,master=2>
+
+Adds a ICH9 USB companion controller on PCI address 0:0:4.7 with
+master bus 0 and first port 2.
+
+=back
+
 =item --host-device=HOSTDEV
 
 Attach a physical host device to the guest. Some example values for HOSTDEV:
diff --git a/tests/cli-test-xml/compare/many-devices.xml b/tests/cli-test-xml/compare/many-devices.xml
index c37f189..6b4995d 100644
--- a/tests/cli-test-xml/compare/many-devices.xml
+++ b/tests/cli-test-xml/compare/many-devices.xml
@@ -38,6 +38,21 @@
       <target dev='hdc' bus='ide'/>
       <readonly/>
     </disk>
+    <controller type='usb' index='0' model='ich9-ehci1'>
+      <address type='pci' domain='0' bus='0' slot='4' function='7'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci1'>
+      <master startport='0'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='0'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci2'>
+      <master startport='2'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='1'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci3'>
+      <master startport='4'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='2'/>
+    </controller>
     <filesystem accessmode='squash'>
       <source dir='/source'/>
       <target dir='/target'/>
@@ -104,6 +119,21 @@
       <target dev='hdc' bus='ide'/>
       <readonly/>
     </disk>
+    <controller type='usb' index='0' model='ich9-ehci1'>
+      <address type='pci' domain='0' bus='0' slot='4' function='7'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci1'>
+      <master startport='0'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='0'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci2'>
+      <master startport='2'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='1'/>
+    </controller>
+    <controller type='usb' index='0' model='ich9-uhci3'>
+      <master startport='4'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='2'/>
+    </controller>
     <filesystem accessmode='squash'>
       <source dir='/source'/>
       <target dir='/target'/>
diff --git a/tests/clitest.py b/tests/clitest.py
index 6b17dd6..9fe2d2f 100644
--- a/tests/clitest.py
+++ b/tests/clitest.py
@@ -598,6 +598,10 @@ args_dict = {
         ("--hvm --cdrom %(EXISTIMG2)s --file %(EXISTIMG1)s --os-variant win2k3 --wait 0 --vcpus cores=4", "w2k3-cdrom"),
         # Lot's of devices
         ("--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 %(EXISTIMG1)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 "
@@ -652,6 +656,28 @@ args_dict = {
 
      }, # category "network"
 
+     "controller": {
+      "args": "--noautoconsole --nodisks --pxe",
+
+      "valid": [
+        "--controller usb,model=ich9-ehci1,address=0:0:4.7",
+        "--controller usb,model=ich9-ehci1,address=0:0:4.7,index=0",
+        "--controller usb,model=ich9-ehci1,address=0:0:4.7,index=1,master=0",
+      ],
+
+      "invalid": [
+        # Missing argument
+        "--controller",
+        # Invalid argument
+        "--controller foo",
+        # Invalid values
+        "--controller usb,model=ich9-ehci1,address=0:0:4.7,index=bar,master=foo",
+        # --bogus
+        "--controller host,foobar=baz",
+      ],
+
+     }, # category "controller"
+
      "hostdev" : {
       "args": "--noautoconsole --nographics --nodisks --pxe",
 
diff --git a/tests/utils.py b/tests/utils.py
index 1a542e5..1cf5fec 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -96,10 +96,10 @@ def sanitize_xml_for_define(xml):
 def test_create(testconn, xml):
     xml = sanitize_xml_for_define(xml)
 
-    try:
-        dom = testconn.defineXML(xml)
-    except Exception, e:
-        raise RuntimeError(str(e) + "\n" + xml)
+#    try:
+    dom = testconn.defineXML(xml)
+#    except Exception, e:
+#        raise RuntimeError(str(e) + "\n" + xml)
 
     try:
         dom.create()
diff --git a/tests/xmlparse-xml/change-controllers-in.xml b/tests/xmlparse-xml/change-controllers-in.xml
index 4ea5be6..34de7e1 100644
--- a/tests/xmlparse-xml/change-controllers-in.xml
+++ b/tests/xmlparse-xml/change-controllers-in.xml
@@ -22,5 +22,9 @@
     <controller type="ide" index="3"/>
     <controller type="virtio-serial" index="0" ports="32" vectors="17"/>
     <controller type="scsi" index="1"/>
+    <controller type='usb' index='3' model='ich9-uhci3'>
+      <master startport='4'/>
+      <address type='pci' domain='0' bus='0' slot='4' function='2'/>
+    </controller>
   </devices>
 </domain>
diff --git a/tests/xmlparse-xml/change-controllers-out.xml b/tests/xmlparse-xml/change-controllers-out.xml
index 93f9362..4a26f1a 100644
--- a/tests/xmlparse-xml/change-controllers-out.xml
+++ b/tests/xmlparse-xml/change-controllers-out.xml
@@ -22,5 +22,9 @@
     <controller type="ide" index="1"/>
     <controller type="virtio-serial" index="7" ports="5"/>
     <controller type="scsi" index="2"/>
+    <controller type="usb" index="9" model="ich9-uhci3">
+      <master startport="2"/>
+      <address type="pci" domain="0" bus="0" slot="4" function="2"/>
+    </controller>
   </devices>
 </domain>
diff --git a/tests/xmlparse.py b/tests/xmlparse.py
index c30a7d3..0ec0ad9 100644
--- a/tests/xmlparse.py
+++ b/tests/xmlparse.py
@@ -343,6 +343,7 @@ class XMLParseTest(unittest.TestCase):
         dev1 = guest.get_devices("controller")[0]
         dev2 = guest.get_devices("controller")[1]
         dev3 = guest.get_devices("controller")[2]
+        dev4 = guest.get_devices("controller")[3]
 
         check = self._make_checker(dev1)
         check("type", "ide")
@@ -358,6 +359,14 @@ class XMLParseTest(unittest.TestCase):
         check("type", "scsi")
         check("index", "1", "2")
 
+        check = self._make_checker(dev4)
+        check("type", "usb")
+        check("index", "3", "9")
+        check("model", "ich9-uhci3")
+
+        check = self._make_checker(dev4.get_master())
+        check("startport", "4", "2")
+
         self._alter_compare(guest.get_config_xml(), outfile)
 
     def testAlterNics(self):
diff --git a/virt-install b/virt-install
index ef2c582..e398481 100755
--- a/virt-install
+++ b/virt-install
@@ -490,6 +490,7 @@ def build_guest_instance(conn, options):
 
 
     # Non-default devices
+    cli.get_controller(guest, options.controller)
     if not options.nonetworks:
         get_networks(guest, options)
     get_graphics(guest, options)
diff --git a/virtinst/VirtualController.py b/virtinst/VirtualController.py
index 8e5d19d..d9297ae 100644
--- a/virtinst/VirtualController.py
+++ b/virtinst/VirtualController.py
@@ -19,7 +19,8 @@
 
 import VirtualDevice
 #from virtinst import _gettext as _
-from XMLBuilderDomain import _xml_property
+from XMLBuilderDomain import XMLBuilderDomain, _xml_property
+import logging
 
 class VirtualController(VirtualDevice.VirtualDevice):
 
@@ -30,9 +31,10 @@ class VirtualController(VirtualDevice.VirtualDevice):
     CONTROLLER_TYPE_SCSI            = "scsi"
     CONTROLLER_TYPE_SATA            = "sata"
     CONTROLLER_TYPE_VIRTIOSERIAL    = "virtio-serial"
+    CONTROLLER_TYPE_USB             = "usb"
     CONTROLLER_TYPES = [CONTROLLER_TYPE_IDE, CONTROLLER_TYPE_FDC,
                         CONTROLLER_TYPE_SCSI, CONTROLLER_TYPE_SATA,
-                        CONTROLLER_TYPE_VIRTIOSERIAL]
+                        CONTROLLER_TYPE_VIRTIOSERIAL, CONTROLLER_TYPE_USB]
 
     @staticmethod
     def pretty_type(ctype):
@@ -41,7 +43,8 @@ class VirtualController(VirtualDevice.VirtualDevice):
             VirtualController.CONTROLLER_TYPE_FDC           : "Floppy",
             VirtualController.CONTROLLER_TYPE_SCSI          : "SCSI",
             VirtualController.CONTROLLER_TYPE_SATA          : "SATA",
-            VirtualController.CONTROLLER_TYPE_VIRTIOSERIAL  : "Virtio Serial"
+            VirtualController.CONTROLLER_TYPE_VIRTIOSERIAL  : "Virtio Serial",
+            VirtualController.CONTROLLER_TYPE_USB           : "USB"
         }
 
         if ctype not in pretty_mappings:
@@ -63,22 +66,42 @@ class VirtualController(VirtualDevice.VirtualDevice):
             return VirtualControllerSATA
         elif ctype == VirtualController.CONTROLLER_TYPE_VIRTIOSERIAL:
             return VirtualControllerVirtioSerial
+        elif ctype == VirtualController.CONTROLLER_TYPE_USB:
+            return VirtualControllerUSB
 
     _controller_type = None
 
-    def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
+    def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None,
+                 model=None):
         VirtualDevice.VirtualDevice.__init__(self, conn,
                                              parsexml, parsexmlnode, caps)
 
         self._index = 0
         self._ports = None
         self._vectors = None
+        self._model = None
+        self._master = VirtualDeviceMaster(conn,
+                                           parsexml=parsexml,
+                                           parsexmlnode=parsexmlnode,
+                                           caps=caps)
+
+        if self._is_parse():
+            return
+
+        self.model = model
 
     def get_type(self):
         return self._controller_type
     type = _xml_property(get_type,
                          xpath="./@type")
 
+    def get_model(self):
+        return self._model
+    def set_model(self, model):
+        self._model = model
+    model = _xml_property(get_model, set_model,
+                         xpath="./@model")
+
     def get_index(self):
         return self._index
     def set_index(self, val):
@@ -100,6 +123,11 @@ class VirtualController(VirtualDevice.VirtualDevice):
     ports = _xml_property(get_ports, set_ports,
                           xpath="./@ports")
 
+    def set_master(self, masterstr):
+        self._master.parse_friendly_master(masterstr)
+    def get_master(self):
+        return self._master
+
     def _extra_config(self):
         return ""
 
@@ -107,9 +135,16 @@ class VirtualController(VirtualDevice.VirtualDevice):
         extra = self._extra_config()
 
         xml = "    <controller type='%s' index='%s'" % (self.type, self.index)
+        if self.model:
+            xml += " model='%s'" % self.model
         xml += extra
-        xml += "/>"
-
+        childxml = self.indent(self._master.get_xml_config(), 6)
+        childxml += self.indent(self.address.get_xml_config(), 6)
+        if len(childxml) == 0:
+            return xml + "/>"
+        xml += ">\n"
+        xml += childxml
+        xml += "    </controller>"
         return xml
 
 
@@ -136,3 +171,34 @@ class VirtualControllerVirtioSerial(VirtualController):
             xml += " vectors='%s'" % self.vectors
 
         return xml
+
+class VirtualControllerUSB(VirtualController):
+    _controller_type = VirtualController.CONTROLLER_TYPE_USB
+
+
+class VirtualDeviceMaster(XMLBuilderDomain):
+    def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
+        XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
+                                  caps=caps)
+
+        self._startport = None
+
+    def parse_friendly_master(self, masterstr):
+        try:
+            int(masterstr)
+            self._startport = masterstr
+        except:
+            logging.exception("Error parsing device master.")
+            return None
+
+    def _get_startport(self):
+        return self._startport
+    def _set_startport(self, val):
+        self._startport = val
+    startport = _xml_property(_get_startport, _set_startport, xpath="./master/@startport")
+
+    def _get_xml_config(self):
+        if self.startport is None:
+            return
+
+        return "<master startport='%s'/>" % self.startport
diff --git a/virtinst/VirtualDevice.py b/virtinst/VirtualDevice.py
index 869d50e..e817bf7 100644
--- a/virtinst/VirtualDevice.py
+++ b/virtinst/VirtualDevice.py
@@ -21,6 +21,7 @@
 
 from XMLBuilderDomain import XMLBuilderDomain, _xml_property
 from virtinst import _gettext as _
+import logging
 
 class VirtualDevice(XMLBuilderDomain):
     """
@@ -113,6 +114,10 @@ class VirtualDevice(XMLBuilderDomain):
         ignore = meter
         return
 
+    def set_address(self, addrstr):
+        self.address = VirtualDeviceAddress(self.conn, addrstr=addrstr)
+
+
 class VirtualDeviceAlias(XMLBuilderDomain):
     def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
         XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
@@ -132,9 +137,15 @@ class VirtualDeviceAlias(XMLBuilderDomain):
 
 class VirtualDeviceAddress(XMLBuilderDomain):
 
-    TYPES = ["pci", "drive", "virtio-serial", "ccid"]
+    ADDRESS_TYPE_PCI           = "pci"
+    ADDRESS_TYPE_DRIVE         = "drive"
+    ADDRESS_TYPE_VIRTIO_SERIAL = "virtio-serial"
+    ADDRESS_TYPE_CCID          = "ccid"
 
-    def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None):
+    TYPES = [ADDRESS_TYPE_PCI, ADDRESS_TYPE_DRIVE,
+             ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID]
+
+    def __init__(self, conn, parsexml=None, parsexmlnode=None, caps=None, addrstr=None):
         XMLBuilderDomain.__init__(self, conn, parsexml, parsexmlnode,
                                   caps=caps)
 
@@ -160,6 +171,25 @@ class VirtualDeviceAddress(XMLBuilderDomain):
         # CCID address:
         # <address type='ccid' controller='0' slot='0'/>
 
+        if addrstr:
+            self.parse_friendly_address(addrstr)
+
+    def parse_friendly_address(self, addrstr):
+        try:
+            if addrstr.count(":") in [1, 2] and addrstr.count("."):
+                self.type = self.ADDRESS_TYPE_PCI
+                addrstr, self.function = addrstr.split(".", 1)
+                addrstr, self.slot = addrstr.rsplit(":", 1)
+                self.domain = "0"
+                if addrstr.count(":"):
+                    self.domain, self.bus = addrstr.split(":", 1)
+            else:
+                raise ValueError(_("Could not determine or unsupported format of '%s'") % addrstr)
+        except:
+            logging.exception("Error parsing address.")
+            return None
+
+
     def clear(self):
         self._type = None
         self._bus = None
@@ -224,4 +254,17 @@ class VirtualDeviceAddress(XMLBuilderDomain):
     port = _xml_property(_get_port, _set_port, xpath="./address/@port")
 
     def _get_xml_config(self):
-        return ""
+        if not self.type:
+            return
+
+        xml = "<address type='%s'" % self.type
+        if self.type == self.ADDRESS_TYPE_PCI:
+            xml += " domain='%s' bus='%s' slot='%s' function='%s'" % (self.domain, self.bus, self.slot, self.function)
+        elif self.type == self.ADDRESS_TYPE_DRIVE:
+            xml += " controller='%s' bus='%s' unit='%s'" % (self.controller, self.bus, self.unit)
+        elif self.type == self.ADDRESS_TYPE_VIRTIO_SERIAL:
+            xml += " controller='%s' bus='%s' port='%s'" % (self.controller, self.bus, self.port)
+        elif self.type == self.ADDRESS_TYPE_CCID:
+            xml += " controller='%s' slot='%s'" % (self.controller, self.slot)
+        xml += "/>"
+        return xml
diff --git a/virtinst/XMLBuilderDomain.py b/virtinst/XMLBuilderDomain.py
index 6a489b5..d9b263e 100644
--- a/virtinst/XMLBuilderDomain.py
+++ b/virtinst/XMLBuilderDomain.py
@@ -495,3 +495,13 @@ class XMLBuilderDomain(object):
             return _sanitize_libxml_xml(node.serialize())
 
         return self._get_xml_config(*args, **kwargs)
+
+    @staticmethod
+    def indent(xmlstr, level):
+        xml = ""
+        if not xmlstr:
+            return xml
+
+        for l in iter(xmlstr.splitlines()):
+            xml += " " * level + l + "\n"
+        return xml
diff --git a/virtinst/cli.py b/virtinst/cli.py
index d9640cb..40cabff 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -997,6 +997,16 @@ def get_smartcard(guest, sc_opts):
         if dev:
             guest.add_device(dev)
 
+def get_controller(guest, sc_opts):
+    for sc in listify(sc_opts):
+        try:
+            dev = parse_controller(guest, sc)
+        except Exception, e:
+            fail(_("Error in controller device parameters: %s") % str(e))
+
+        if dev:
+            guest.add_device(dev)
+
 #############################
 # Common CLI option/group   #
 #############################
@@ -1065,6 +1075,9 @@ def add_net_option(devg):
              "--network network=mynet,model=virtio,mac=00:11..."))
 
 def add_device_options(devg):
+    devg.add_option("", "--controller", dest="controller", action="append",
+                    help=_("Configure a guest controller device. Ex:\n"
+                           "--controller type=usb,model=ich9-ehci1"))
     devg.add_option("", "--serial", dest="serials", action="append",
                     help=_("Configure a guest serial device"))
     devg.add_option("", "--parallel", dest="parallels", action="append",
@@ -1683,6 +1696,36 @@ def parse_graphics(guest, optstring, dev=None):
     return dev
 
 #######################
+# --controller parsing #
+#######################
+
+def parse_controller(guest, optstring, dev=None):
+    if optstring is None:
+        return None
+
+    # Peel the mode off the front
+    opts = parse_optstr(optstring, remove_first="type")
+    ctrltype = get_opt_param(opts, "type")
+    address = get_opt_param(opts, "address")
+    master = get_opt_param(opts, "master")
+
+    if not dev:
+        cl = virtinst.VirtualController.get_class_for_type(ctrltype)
+        dev = cl(guest.conn, model=opts.get("model"))
+
+    set_param = _build_set_param(dev, opts)
+
+    set_param("model", "model")
+    set_param("index", "index")
+    dev.set_address(address)
+    if master:
+        dev.set_master(master)
+    if opts:
+        raise ValueError(_("Unknown options %s") % opts.keys())
+
+    return dev
+
+#######################
 # --smartcard parsing #
 #######################
 
-- 
1.7.6




More information about the virt-tools-list mailing list