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-clone.1 | 6 ++- man/en/virt-image.1 | 45 +++++++-------- man/en/virt-install.1 | 34 ++++++++++- 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 ++++++++++++++ 15 files changed, 345 insertions(+), 41 deletions(-) diff --git a/man/en/virt-clone.1 b/man/en/virt-clone.1 index 9df2fea..20ec173 100644 --- a/man/en/virt-clone.1 +++ b/man/en/virt-clone.1 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "VIRT-CLONE 1" -.TH VIRT-CLONE 1 "2010-12-17" "" "Virtual Machine Install Tools" +.TH VIRT-CLONE 1 "2011-08-01" "" "Virtual Machine Install Tools" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -232,6 +232,10 @@ guest \s-1XML\s0. .IP "\-\-print\-xml" 2 .IX Item "--print-xml" Print the generated clone \s-1XML\s0 and exit without cloning. +.IP "\-\-replace" 2 +.IX Item "--replace" +Shutdown and remove any existing guest with the passed \f(CW\*(C`\-\-name\*(C'\fR before +cloning the original guest. .IP "\-d, \-\-debug" 2 .IX Item "-d, --debug" Print debugging information to the terminal when running the install process. diff --git a/man/en/virt-image.1 b/man/en/virt-image.1 index 520cc5e..b6ee7b7 100644 --- a/man/en/virt-image.1 +++ b/man/en/virt-image.1 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "VIRT-IMAGE 1" -.TH VIRT-IMAGE 1 "2011-06-09" "" "Virtual Machine Install Tools" +.TH VIRT-IMAGE 1 "2011-08-01" "" "Virtual Machine Install Tools" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -205,48 +205,49 @@ values. Parameters specific only to fully virtualized guest installs. .IP "\-\-noapic" 2 .IX Item "--noapic" -Disables \s-1APIC\s0 for fully virtualized guest (overrides value in \s-1XML\s0 descriptor) +Force disable \s-1APIC\s0 for the guest. .IP "\-\-noacpi" 2 .IX Item "--noacpi" -Disables \s-1ACPI\s0 for fully virtualized guest (overrides value in \s-1XML\s0 descriptor) +Force disable \s-1ACPI\s0 for the guest. .SS "Networking Configuration" .IX Subsection "Networking Configuration" +.IP "\-w \s-1NETWORK\s0, \-\-network=NETWORK" 2 +.IX Item "-w NETWORK, --network=NETWORK" +Connect the guest to the host network. See \fIvirt\-install\fR\|(1) for details .IP "\-m \s-1MAC\s0, \-\-mac=MAC" 2 .IX Item "-m MAC, --mac=MAC" This is deprecated in favor of \f(CW\*(C`\-\-network ...,mac=MAC,...\*(C'\fR .IP "\-b \s-1BRIDGE\s0, \-\-bridge=BRIDGE" 2 .IX Item "-b BRIDGE, --bridge=BRIDGE" This is deprecated in favor of \f(CW\*(C`\-\-network bridge=BRIDGE\*(C'\fR -.IP "\-w \s-1NETWORK\s0, \-\-network=NETWORK" 2 -.IX Item "-w NETWORK, --network=NETWORK" -Connect the guest to the host network. See \fIvirt\-install\fR\|(1) for details .SS "Graphics Configuration" .IX Subsection "Graphics Configuration" -If no graphics option is specified, \f(CW\*(C`virt\-install\*(C'\fR will default to \-\-vnc -if the \s-1DISPLAY\s0 environment variable is set, otherwise \-\-nographics is used. +If no graphics option is specified, \f(CW\*(C`virt\-image\*(C'\fR will default to +\&'\-\-graphics vnc' if the \s-1DISPLAY\s0 environment variable is set, otherwise +\&'\-\-graphics none' is used. +.IP "\-\-graphics \s-1TYPE\s0,opt1=arg1,opt2=arg2,..." 2 +.IX Item "--graphics TYPE,opt1=arg1,opt2=arg2,..." +Specifies the graphical display configuration. This does not configure any +virtual hardware, just how the guest's graphical display can be accessed. +See \fIvirt\-install\fR\|(1) for details usage info. .IP "\-\-vnc" 2 .IX Item "--vnc" -Setup a virtual console in the guest and export it as a \s-1VNC\s0 server in -the host. See \fIvirt\-install\fR\|(1) for details +This option is deprecated in favor of \f(CW\*(C`\-\-graphics vnc,...\*(C'\fR .IP "\-\-vncport=VNCPORT" 2 .IX Item "--vncport=VNCPORT" -Request a permanent, statically assigned port number for the guest \s-1VNC\s0 -console. See \fIvirt\-install\fR\|(1) for details +This option is deprecated in favor of \f(CW\*(C`\-\-graphics vnc,port=PORT,...\*(C'\fR .IP "\-\-vnclisten=VNCLISTEN" 2 .IX Item "--vnclisten=VNCLISTEN" -Address to listen on for \s-1VNC\s0 connections. See \fIvirt\-install\fR\|(1) for details. +This option is deprecated in favor of \f(CW\*(C`\-\-graphics vnc,listen=LISTEN,...\*(C'\fR .IP "\-k \s-1KEYMAP\s0, \-\-keymap=KEYMAP" 2 .IX Item "-k KEYMAP, --keymap=KEYMAP" -Request that the virtual \s-1VNC\s0 console be configured to run with a non-English -keyboard layout. +This option is deprecated in favor of \f(CW\*(C`\-\-graphics vnc,keymap=KEYMAP,...\*(C'\fR .IP "\-\-sdl" 2 .IX Item "--sdl" -Setup a virtual console in the guest and display an \s-1SDL\s0 window in the -host to render the output. See \fIvirt\-install\fR\|(1) for details +This option is deprecated in favor of \f(CW\*(C`\-\-graphics sdl,...\*(C'\fR .IP "\-\-nographics" 2 .IX Item "--nographics" -Do not attach a graphical device to the guest. See -\&\fIvirt\-install\fR\|(1) for details +This option is deprecated in favor of \f(CW\*(C`\-\-graphics none\*(C'\fR .SS "Miscellaneous Options" .IX Subsection "Miscellaneous Options" .IP "\-p, \-\-print" 2 @@ -272,11 +273,7 @@ Do not check disk images against checksums (if they are listed in the image xml). .IP "\-d, \-\-debug" 2 .IX Item "-d, --debug" -Print debugging information -.IP "\-\-force" 2 -.IX Item "--force" -Prevent interactive prompts. If the intended prompt was a yes/no prompt, always -say yes. For any other prompts, the application will exit. +Print debugging information. .SH "EXAMPLES" .IX Header "EXAMPLES" Create and start a guest called \f(CW\*(C`example\*(C'\fR with a \s-1VNC\s0 console from diff --git a/man/en/virt-install.1 b/man/en/virt-install.1 index 5a2e244..e30bc64 100644 --- a/man/en/virt-install.1 +++ b/man/en/virt-install.1 @@ -124,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "VIRT-INSTALL 1" -.TH VIRT-INSTALL 1 "2011-07-26" "" "Virtual Machine Install Tools" +.TH VIRT-INSTALL 1 "2011-08-23" "" "Virtual Machine Install Tools" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -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,36 @@ 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" +Define the master bus, currently applicable to \s-1USB\s0 companion controllers. +The value expected is of the form 'bus:startport'. +.RE +.RS 2 +.Sp +Example: +.IP "\fB\-\-controller usb,model=ich9\-uhci2,address=0:0:4.7,master=0:2\fR" 4 +.IX Item "--controller usb,model=ich9-uhci2,address=0:0:4.7,master=0: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 629b906..392137f 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 7f332dc..246b5cd 100644 --- a/tests/clitest.py +++ b/tests/clitest.py @@ -545,6 +545,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 " @@ -599,6 +603,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: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 6e672e9..837475d 100755 --- a/virt-install +++ b/virt-install @@ -479,6 +479,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 386eb00..08df6d3 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 @@ -223,4 +253,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 e130e7d..07481dd 100644 --- a/virtinst/cli.py +++ b/virtinst/cli.py @@ -994,6 +994,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 # ############################# @@ -1062,6 +1072,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", @@ -1680,6 +1693,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list