mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-10 23:45:49 -06:00
Currently, virt-manager supports adding spicevmc channel, and cannot add channels with char device backends like pty or unix, which is often used by guest agents. On the other hand, spicevmc shows up for serial and parallel devices, that causes an error if chosen. This enables virt-manager to add channels with a char device backend other than spicevmc, and hides spicevmc from non-channel devices. Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama@hds.com>
280 lines
10 KiB
Python
280 lines
10 KiB
Python
#
|
|
# Copyright 2009 Red Hat, Inc.
|
|
# Cole Robinson <crobinso@redhat.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
# MA 02110-1301 USA.
|
|
|
|
from virtinst.VirtualDevice import VirtualDevice
|
|
from virtinst.xmlbuilder import XMLProperty
|
|
|
|
|
|
class _VirtualCharDevice(VirtualDevice):
|
|
"""
|
|
Base class for all character devices. Shouldn't be instantiated
|
|
directly.
|
|
"""
|
|
|
|
TYPE_PTY = "pty"
|
|
TYPE_DEV = "dev"
|
|
TYPE_STDIO = "stdio"
|
|
TYPE_PIPE = "pipe"
|
|
TYPE_FILE = "file"
|
|
TYPE_VC = "vc"
|
|
TYPE_NULL = "null"
|
|
TYPE_TCP = "tcp"
|
|
TYPE_UDP = "udp"
|
|
TYPE_UNIX = "unix"
|
|
TYPE_SPICEVMC = "spicevmc"
|
|
_TYPES_FOR_ALL = [TYPE_PTY, TYPE_DEV, TYPE_STDIO, TYPE_FILE, TYPE_VC,
|
|
TYPE_PIPE, TYPE_NULL, TYPE_TCP, TYPE_UDP, TYPE_UNIX]
|
|
_TYPES_FOR_CHANNEL = [TYPE_SPICEVMC]
|
|
TYPES = _TYPES_FOR_ALL
|
|
|
|
MODE_CONNECT = "connect"
|
|
MODE_BIND = "bind"
|
|
MODES = [MODE_CONNECT, MODE_BIND]
|
|
|
|
PROTOCOL_RAW = "raw"
|
|
PROTOCOL_TELNET = "telnet"
|
|
PROTOCOLS = [PROTOCOL_RAW, PROTOCOL_TELNET]
|
|
|
|
CHANNEL_TARGET_GUESTFWD = "guestfwd"
|
|
CHANNEL_TARGET_VIRTIO = "virtio"
|
|
CHANNEL_TARGETS = [CHANNEL_TARGET_GUESTFWD,
|
|
CHANNEL_TARGET_VIRTIO]
|
|
|
|
CONSOLE_TARGET_SERIAL = "serial"
|
|
CONSOLE_TARGET_UML = "uml"
|
|
CONSOLE_TARGET_XEN = "xen"
|
|
CONSOLE_TARGET_VIRTIO = "virtio"
|
|
CONSOLE_TARGETS = [CONSOLE_TARGET_SERIAL, CONSOLE_TARGET_UML,
|
|
CONSOLE_TARGET_XEN, CONSOLE_TARGET_VIRTIO]
|
|
|
|
@staticmethod
|
|
def pretty_type(ctype):
|
|
"""
|
|
Return a human readable description of the passed char type
|
|
"""
|
|
desc = ""
|
|
|
|
if ctype == _VirtualCharDevice.TYPE_PTY:
|
|
desc = _("Pseudo TTY")
|
|
elif ctype == _VirtualCharDevice.TYPE_DEV:
|
|
desc = _("Physical host character device")
|
|
elif ctype == _VirtualCharDevice.TYPE_STDIO:
|
|
desc = _("Standard input/output")
|
|
elif ctype == _VirtualCharDevice.TYPE_PIPE:
|
|
desc = _("Named pipe")
|
|
elif ctype == _VirtualCharDevice.TYPE_FILE:
|
|
desc = _("Output to a file")
|
|
elif ctype == _VirtualCharDevice.TYPE_VC:
|
|
desc = _("Virtual console")
|
|
elif ctype == _VirtualCharDevice.TYPE_NULL:
|
|
desc = _("Null device")
|
|
elif ctype == _VirtualCharDevice.TYPE_TCP:
|
|
desc = _("TCP net console")
|
|
elif ctype == _VirtualCharDevice.TYPE_UDP:
|
|
desc = _("UDP net console")
|
|
elif ctype == _VirtualCharDevice.TYPE_UNIX:
|
|
desc = _("Unix socket")
|
|
elif ctype == _VirtualCharDevice.TYPE_SPICEVMC:
|
|
desc = _("Spice agent")
|
|
|
|
return desc
|
|
|
|
@staticmethod
|
|
def pretty_mode(char_mode):
|
|
"""
|
|
Return a human readable description of the passed char type
|
|
"""
|
|
desc = ""
|
|
|
|
if char_mode == _VirtualCharDevice.MODE_CONNECT:
|
|
desc = _("Client mode")
|
|
elif char_mode == _VirtualCharDevice.MODE_BIND:
|
|
desc = _("Server mode")
|
|
|
|
return desc
|
|
|
|
|
|
def supports_property(self, propname, ro=False):
|
|
"""
|
|
Whether the character dev type supports the passed property name
|
|
"""
|
|
users = {
|
|
"source_path" : [self.TYPE_FILE, self.TYPE_UNIX,
|
|
self.TYPE_DEV, self.TYPE_PIPE],
|
|
"source_mode" : [self.TYPE_UNIX, self.TYPE_TCP],
|
|
"source_host" : [self.TYPE_TCP, self.TYPE_UDP],
|
|
"source_port" : [self.TYPE_TCP, self.TYPE_UDP],
|
|
"protocol" : [self.TYPE_TCP],
|
|
"bind_host" : [self.TYPE_UDP],
|
|
"bind_port" : [self.TYPE_UDP],
|
|
}
|
|
|
|
if ro:
|
|
users["source_path"] += [self.TYPE_PTY]
|
|
|
|
channel_users = {
|
|
"target_name" : [self.CHANNEL_TARGET_VIRTIO],
|
|
}
|
|
|
|
if users.get(propname):
|
|
return self.type in users[propname]
|
|
if channel_users.get(propname):
|
|
return (self.virtual_device_type == "channel" and
|
|
self.target_type in channel_users[propname])
|
|
return hasattr(self, propname)
|
|
|
|
|
|
_XML_PROP_ORDER = ["type", "_has_mode_bind", "_has_mode_connect",
|
|
"bind_host", "bind_port",
|
|
"source_mode", "source_path",
|
|
"source_host", "source_port",
|
|
"target_type", "target_name"]
|
|
|
|
type = XMLProperty(
|
|
doc=_("Method used to expose character device in the host."),
|
|
xpath="./@type")
|
|
|
|
def _sourcepath_get_xpath(self):
|
|
ret = "./source/@path"
|
|
for xpath in [ret, "./@tty"]:
|
|
if self._xmlstate.xml_ctx.xpathEval(
|
|
self.fix_relative_xpath(xpath)):
|
|
ret = xpath
|
|
break
|
|
return ret
|
|
source_path = XMLProperty(make_getter_xpath_cb=_sourcepath_get_xpath,
|
|
doc=_("Host input path to attach to the guest."),
|
|
xpath="./source/@path")
|
|
|
|
def _get_default_source_mode(self):
|
|
if self.type == self.TYPE_UDP:
|
|
return self.MODE_CONNECT
|
|
if not self.supports_property("source_mode"):
|
|
return None
|
|
return self.MODE_BIND
|
|
def _sourcemode_xpath(self):
|
|
if self.type == self.TYPE_UDP:
|
|
return "./source[@mode='connect']/@mode"
|
|
return "./source/@mode"
|
|
source_mode = XMLProperty(name="char sourcemode",
|
|
doc=_("Target connect/listen mode."),
|
|
make_getter_xpath_cb=_sourcemode_xpath,
|
|
make_setter_xpath_cb=_sourcemode_xpath,
|
|
default_cb=_get_default_source_mode)
|
|
|
|
def _get_default_sourcehost(self):
|
|
if not self.supports_property("source_host"):
|
|
return None
|
|
return "127.0.0.1"
|
|
def _set_source_validate(self, val):
|
|
if val is None or self.type != self.TYPE_UDP:
|
|
return val
|
|
if not self._has_mode_connect:
|
|
self._has_mode_connect = self.MODE_CONNECT
|
|
return val
|
|
def _sourcehost_xpath(self):
|
|
mode = self.source_mode
|
|
if self.type == self.TYPE_UDP:
|
|
mode = "connect"
|
|
return "./source[@mode='%s']/@host" % mode
|
|
source_host = XMLProperty(name="char sourcehost",
|
|
doc=_("Address to connect/listen to."),
|
|
make_getter_xpath_cb=_sourcehost_xpath,
|
|
make_setter_xpath_cb=_sourcehost_xpath,
|
|
default_cb=_get_default_sourcehost,
|
|
set_converter=_set_source_validate)
|
|
|
|
def _sourceport_xpath(self):
|
|
return "./source[@mode='%s']/@service" % self.source_mode
|
|
source_port = XMLProperty(name="char sourceport",
|
|
doc=_("Port on target host to connect/listen to."),
|
|
make_getter_xpath_cb=_sourceport_xpath,
|
|
make_setter_xpath_cb=_sourceport_xpath,
|
|
set_converter=_set_source_validate, is_int=True)
|
|
|
|
_has_mode_connect = XMLProperty(xpath="./source[@mode='connect']/@mode")
|
|
_has_mode_bind = XMLProperty(xpath="./source[@mode='bind']/@mode")
|
|
|
|
def _set_bind_validate(self, val):
|
|
if val is None:
|
|
return None
|
|
if not self._has_mode_bind:
|
|
self._has_mode_bind = self.MODE_BIND
|
|
return val
|
|
bind_host = XMLProperty(xpath="./source[@mode='bind']/@host",
|
|
doc=_("Host addresss to bind to."),
|
|
set_converter=_set_bind_validate)
|
|
bind_port = XMLProperty(xpath="./source[@mode='bind']/@service",
|
|
doc=_("Host port to bind to."),
|
|
set_converter=_set_bind_validate, is_int=True)
|
|
|
|
def _get_default_protocol(self):
|
|
if not self.supports_property("protocol"):
|
|
return None
|
|
return self.PROTOCOL_RAW
|
|
protocol = XMLProperty(xpath="./protocol/@type",
|
|
doc=_("Format used when sending data."),
|
|
default_cb=_get_default_protocol)
|
|
|
|
def _get_default_target_type(self):
|
|
if self.virtual_device_type == "channel":
|
|
return self.CHANNEL_TARGET_VIRTIO
|
|
return None
|
|
target_type = XMLProperty(xpath="./target/@type",
|
|
doc=_("Channel type as exposed in the guest."),
|
|
default_cb=_get_default_target_type)
|
|
|
|
target_address = XMLProperty(xpath="./target/@address",
|
|
doc=_("Guest forward channel address in the guest."))
|
|
|
|
target_port = XMLProperty(xpath="./target/@port", is_int=True,
|
|
doc=_("Guest forward channel port in the guest."))
|
|
|
|
def _default_target_name(self):
|
|
if self.type == self.TYPE_SPICEVMC:
|
|
return "com.redhat.spice.0"
|
|
return None
|
|
target_name = XMLProperty(xpath="./target/@name",
|
|
doc=_("Sysfs name of virtio port in the guest"),
|
|
default_cb=_default_target_name)
|
|
|
|
|
|
class VirtualConsoleDevice(_VirtualCharDevice):
|
|
virtual_device_type = "console"
|
|
|
|
|
|
class VirtualSerialDevice(_VirtualCharDevice):
|
|
virtual_device_type = "serial"
|
|
|
|
|
|
class VirtualParallelDevice(_VirtualCharDevice):
|
|
virtual_device_type = "parallel"
|
|
|
|
|
|
class VirtualChannelDevice(_VirtualCharDevice):
|
|
virtual_device_type = "channel"
|
|
TYPES = _VirtualCharDevice._TYPES_FOR_CHANNEL + \
|
|
_VirtualCharDevice._TYPES_FOR_ALL
|
|
|
|
|
|
VirtualConsoleDevice.register_type()
|
|
VirtualSerialDevice.register_type()
|
|
VirtualParallelDevice.register_type()
|
|
VirtualChannelDevice.register_type()
|