Allows to add a USB redirected device.
Via TCP server:
--usbredir tcp,server=host:port
Or over Spice:
--usbredir spicevmc
---
man/en/virt-install.1 | 18 ++++++++++
man/en/virt-install.pod.in | 20 ++++++++++++
tests/clitest.py | 26 +++++++++++++++
virt-install | 1 +
virtinst/VirtualHostDevice.py | 70 +++++++++++++++++++++++++++++++++++++++++
virtinst/__init__.py | 5 ++-
virtinst/cli.py | 39 +++++++++++++++++++++++
7 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/man/en/virt-install.1 b/man/en/virt-install.1
index 5f15e8c..21a5ac1 100644
--- a/man/en/virt-install.1
+++ b/man/en/virt-install.1
@@ -1106,6 +1106,24 @@ to the guest
See \f(CW\*(C`http://libvirt.org/formatdomain.html#elementsSmartcard\*(C'\fR for
complete
details.
.RE
+.IP "\-\-usbredir=SOURCE[,OPTS]" 2
+.IX Item "--usbredir=SOURCE[,OPTS]"
+Add a \s-1USB\s0 redirected device.
+.RS 2
+.IP "\fBserver\fR" 4
+.IX Item "server"
+The \s-1USB\s0 server connection details, of the form 'server:port'.
+.RE
+.RS 2
+.Sp
+An example invocation:
+.IP "\fB\-\-usbredir tcp,server=localhost:4000\fR" 4
+.IX Item "--usbredir tcp,server=localhost:4000"
+Add a \s-1USB\s0 redirected device provided by the \s-1TCP\s0 server on
'localhost'
+port 4000.
+.RE
+.RS 2
+.RE
.SS "Miscellaneous Options"
.IX Subsection "Miscellaneous Options"
.IP "\-\-autostart" 2
diff --git a/man/en/virt-install.pod.in b/man/en/virt-install.pod.in
index 392137f..f174250 100644
--- a/man/en/virt-install.pod.in
+++ b/man/en/virt-install.pod.in
@@ -1104,8 +1104,28 @@ to the guest
See
C<http://libvirt.org/formatdomain.html#elementsSmartcard> for complete
details.
+=item --usbredir=SOURCE[,OPTS]
+Add a USB redirected device.
+=over 4
+
+=item B<server>
+
+The USB server connection details, of the form 'server:port'.
+
+=back
+
+An example invocation:
+
+=over 4
+
+=item B<--usbredir tcp,server=localhost:4000>
+
+Add a USB redirected device provided by the TCP server on 'localhost'
+port 4000.
+
+=back
=back
diff --git a/tests/clitest.py b/tests/clitest.py
index c0f9294..d0499a8 100644
--- a/tests/clitest.py
+++ b/tests/clitest.py
@@ -645,6 +645,32 @@ args_dict = {
],
}, # category "hostdev"
+ "usbredir" : {
+ "args": "--noautoconsole --nographics --nodisks --pxe",
+
+ "valid" : [
+ "--usbredir spicevmc",
+ "--usbredir tcp,server=localhost:4000",
+ # Different host server
+ "--usbredir tcp,server=127.0.0.1:4002",
+ ],
+
+ "invalid" : [
+ # Missing argument
+ "--usbredir",
+ # Invalid argument
+ "--usbredir spicevmc,server=foo:12",
+ # Missing argument
+ "--usbredir tcp,server=",
+ # Invalid address
+ "--usbredir tcp,server=localhost:p4000",
+ # Missing address
+ "--usbredir tcp,server=localhost:",
+ # Missing host
+ "--usbredir tcp,server=:399",
+ ],
+ }, # category "usbredir"
+
"remote" : {
"args": "--connect %(REMOTEURI)s --nographics
--noautoconsole",
diff --git a/virt-install b/virt-install
index 837475d..6b20efe 100755
--- a/virt-install
+++ b/virt-install
@@ -480,6 +480,7 @@ def build_guest_instance(conn, options):
# Non-default devices
cli.get_controller(guest, options.controller)
+ cli.get_usbredir(guest, options.usbredir)
if not options.nonetworks:
get_networks(guest, options)
get_graphics(guest, options)
diff --git a/virtinst/VirtualHostDevice.py b/virtinst/VirtualHostDevice.py
index 2175266..dd0604f 100644
--- a/virtinst/VirtualHostDevice.py
+++ b/virtinst/VirtualHostDevice.py
@@ -93,6 +93,9 @@ class VirtualHostDevice(VirtualDevice.VirtualDevice):
self._domain = "0x0"
self._slot = None
self._function = None
+ self._host = None
+ self._service = None
+ self._redirection = None
if self._is_parse():
return
@@ -116,6 +119,13 @@ class VirtualHostDevice(VirtualDevice.VirtualDevice):
type = _xml_property(get_type, set_type,
xpath="./@type")
+ def get_redirection(self):
+ return self._redirection
+ def set_redirection(self, val):
+ self._redirection = val
+ redirection = _xml_property(get_redirection, set_redirection,
+ xpath="./@redirection")
+
def get_managed(self):
return self._managed
def set_managed(self, val):
@@ -174,6 +184,23 @@ class VirtualHostDevice(VirtualDevice.VirtualDevice):
slot = _xml_property(get_slot, set_slot,
xpath="./source/address/@slot")
+ def get_host(self):
+ return self._host
+ def set_host(self, val):
+ if len(val) == 0:
+ raise ValueError(_("Invalid host value"))
+ self._host = val
+ host = _xml_property(get_host, set_host,
+ xpath="./source/@host")
+
+ def get_service(self):
+ return self._service
+ def set_service(self, val):
+ int(val)
+ self._service = val
+ service = _xml_property(get_service, set_service,
+ xpath="./source/@service")
+
def _get_source_xml(self):
raise NotImplementedError("Must be implemented in subclass")
@@ -245,6 +272,49 @@ class VirtualHostDeviceUSB(VirtualHostDevice):
# No libvirt api support for USB Detach/Reset yet
return
+
+class VirtualHostDeviceUSBRedir(VirtualHostDevice):
+
+ def __init__(self, conn, nodedev=None, redirection=None, serverstr=None):
+ VirtualHostDevice.__init__(self, conn, nodedev)
+
+ self.mode = "subsystem"
+ self.type = "usb"
+ self.redirection = redirection
+ if serverstr:
+ self.parse_friendly_server(serverstr)
+
+ def parse_friendly_server(self, serverstr):
+ if serverstr.count(":") == 1:
+ self.host, self.service = serverstr.split(":")
+ else:
+ raise ValueError(_("Could not determine or unsupported format of
'%s'") % serverstr)
+
+ def _get_xml_config(self):
+ xml = (" <hostdev mode='%s' type='%s'
redirection='%s'" % \
+ (self.mode, self.type, self.redirection))
+ if self.redirection == 'spicevmc':
+ xml += "/>"
+ return xml
+ xml += ">\n"
+ xml += (" <source mode='connect' host='%s'
service='%s'/>\n" % \
+ (self.host, self.service))
+ xml += " </hostdev>"
+ return xml
+
+ def _get_source_xml(self): # unused
+ return ""
+
+ def setup(self, conn=None):
+ """
+ DEPRECATED: Please use setup_dev instead
+ """
+ if not conn:
+ conn = self.conn
+
+ # No libvirt api support for USB Detach/Reset yet
+ return
+
class VirtualHostDevicePCI(VirtualHostDevice):
def __init__(self, conn, nodedev=None):
diff --git a/virtinst/__init__.py b/virtinst/__init__.py
index d7c328b..3c4ffd3 100644
--- a/virtinst/__init__.py
+++ b/virtinst/__init__.py
@@ -43,7 +43,7 @@ from VirtualAudio import VirtualAudio
from VirtualInputDevice import VirtualInputDevice
from VirtualDisk import VirtualDisk, XenDisk
from VirtualHostDevice import (VirtualHostDevice, VirtualHostDeviceUSB,
- VirtualHostDevicePCI)
+ VirtualHostDevicePCI, VirtualHostDeviceUSBRedir)
from VirtualCharDevice import VirtualCharDevice
from VirtualVideoDevice import VirtualVideoDevice
from VirtualController import VirtualController
@@ -80,4 +80,5 @@ __all__ = ["Guest", "XenGuest",
"VirtualNetworkInterface",
"VirtualHostDevice", "VirtualHostDeviceUSB",
"VirtualVideoDevice",
"VirtualHostDevicePCI", "VirtualCharDevice",
"VirtualInputDevice",
"VirtualController", "VirtualWatchdog",
- "VirtualFilesystem", "VirtualSmartCardDevice"]
+ "VirtualFilesystem", "VirtualSmartCardDevice",
+ "VirtualHostDeviceUSBRedir"]
diff --git a/virtinst/cli.py b/virtinst/cli.py
index 07481dd..11b46e5 100644
--- a/virtinst/cli.py
+++ b/virtinst/cli.py
@@ -1004,6 +1004,16 @@ def get_controller(guest, sc_opts):
if dev:
guest.add_device(dev)
+def get_usbredir(guest, sc_opts):
+ for sc in listify(sc_opts):
+ try:
+ dev = parse_usbredir(guest, sc)
+ except Exception, e:
+ fail(_("Error in usbredir device parameters: %s") % str(e))
+
+ if dev:
+ guest.add_device(dev)
+
#############################
# Common CLI option/group #
#############################
@@ -1096,6 +1106,9 @@ def add_device_options(devg):
devg.add_option("", "--smartcard", dest="smartcard",
action="append",
help=_("Configure a guest smartcard device. Ex:\n"
"--smartcard mode=passthrough"))
+ devg.add_option("", "--usbredir", dest="usbredir",
action="append",
+ help=_("Configure a guest USB redirection device. Ex:\n"
+ "--usbredir tcp,server=192.168.1.1:4000"))
def add_gfx_option(devg):
devg.add_option("", "--graphics", dest="graphics",
action="append",
@@ -1749,6 +1762,32 @@ def parse_smartcard(guest, optstring, dev=None):
return dev
######################
+# --usbredir parsing #
+######################
+
+def parse_usbredir(guest, optstring, dev=None):
+ if optstring is None:
+ return None
+
+ # Peel the mode off the front
+ opts = parse_optstr(optstring, remove_first="source")
+ source = get_opt_param(opts, "source")
+ server = get_opt_param(opts, "server")
+
+ if source == "none":
+ return None
+
+ if not dev:
+ dev = virtinst.VirtualHostDeviceUSBRedir(guest.conn,
+ redirection=source,
+ serverstr=server)
+
+ if opts:
+ raise ValueError(_("Unknown options %s") % opts.keys())
+
+ return dev
+
+######################
# --watchdog parsing #
######################
--
1.7.6