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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list