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 | 33 ++++++++++-
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, 344 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..5f15e8c 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-29" "" "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,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 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..c0f9294 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",
+ ],
+
+ "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