mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-06 13:17:58 +03:00
2f89ecf4a9
Similar to what was done in libvirt. See these commits:600462834f
c99e954973
227 lines
7.1 KiB
Python
227 lines
7.1 KiB
Python
#
|
|
# Copyright 2009, 2013 Red Hat, Inc.
|
|
#
|
|
# This work is licensed under the GNU GPLv2 or later.
|
|
# See the COPYING file in the top-level directory.
|
|
|
|
from .device import Device
|
|
from ..xmlbuilder import XMLProperty
|
|
|
|
|
|
class _DeviceChar(Device):
|
|
"""
|
|
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"
|
|
TYPE_SPICEPORT = "spiceport"
|
|
TYPE_NMDM = "nmdm"
|
|
|
|
CHANNEL_NAME_SPICE = "com.redhat.spice.0"
|
|
CHANNEL_NAME_QEMUGA = "org.qemu.guest_agent.0"
|
|
CHANNEL_NAME_LIBGUESTFS = "org.libguestfs.channel.0"
|
|
CHANNEL_NAME_SPICE_WEBDAV = "org.spice-space.webdav.0"
|
|
CHANNEL_NAMES = [CHANNEL_NAME_SPICE,
|
|
CHANNEL_NAME_QEMUGA,
|
|
CHANNEL_NAME_LIBGUESTFS,
|
|
CHANNEL_NAME_SPICE_WEBDAV]
|
|
|
|
@classmethod
|
|
def get_recommended_types(cls, _guest):
|
|
if cls.XML_NAME == "console":
|
|
return [cls.TYPE_PTY]
|
|
|
|
ret = [cls.TYPE_PTY, cls.TYPE_FILE, cls.TYPE_UNIX]
|
|
if cls.XML_NAME == "channel":
|
|
ret = [cls.TYPE_SPICEVMC, cls.TYPE_SPICEPORT] + ret
|
|
return ret
|
|
|
|
@staticmethod
|
|
def pretty_channel_name(val):
|
|
if val == _DeviceChar.CHANNEL_NAME_SPICE:
|
|
return "spice"
|
|
if val == _DeviceChar.CHANNEL_NAME_QEMUGA:
|
|
return "qemu-ga"
|
|
if val == _DeviceChar.CHANNEL_NAME_LIBGUESTFS:
|
|
return "libguestfs"
|
|
if val == _DeviceChar.CHANNEL_NAME_SPICE_WEBDAV:
|
|
return "spice-webdav"
|
|
return None
|
|
|
|
@staticmethod
|
|
def pretty_type(ctype):
|
|
"""
|
|
Return a human readable description of the passed char type
|
|
"""
|
|
desc = ""
|
|
|
|
if ctype == _DeviceChar.TYPE_PTY:
|
|
desc = _("Pseudo TTY")
|
|
elif ctype == _DeviceChar.TYPE_DEV:
|
|
desc = _("Physical host character device")
|
|
elif ctype == _DeviceChar.TYPE_STDIO:
|
|
desc = _("Standard input/output")
|
|
elif ctype == _DeviceChar.TYPE_PIPE:
|
|
desc = _("Named pipe")
|
|
elif ctype == _DeviceChar.TYPE_FILE:
|
|
desc = _("Output to a file")
|
|
elif ctype == _DeviceChar.TYPE_VC:
|
|
desc = _("Virtual console")
|
|
elif ctype == _DeviceChar.TYPE_NULL:
|
|
desc = _("Null device")
|
|
elif ctype == _DeviceChar.TYPE_TCP:
|
|
desc = _("TCP net console")
|
|
elif ctype == _DeviceChar.TYPE_UDP:
|
|
desc = _("UDP net console")
|
|
elif ctype == _DeviceChar.TYPE_UNIX:
|
|
desc = _("Unix socket")
|
|
elif ctype == _DeviceChar.TYPE_SPICEVMC:
|
|
desc = _("Spice agent")
|
|
elif ctype == _DeviceChar.TYPE_SPICEPORT:
|
|
desc = _("Spice port")
|
|
|
|
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],
|
|
"source_channel": [self.TYPE_SPICEPORT],
|
|
"source_master": [self.TYPE_NMDM],
|
|
"source_slave": [self.TYPE_NMDM],
|
|
"protocol": [self.TYPE_TCP],
|
|
"bind_host": [self.TYPE_UDP],
|
|
"bind_port": [self.TYPE_UDP],
|
|
}
|
|
|
|
if ro:
|
|
users["source_path"] += [self.TYPE_PTY]
|
|
|
|
if users.get(propname):
|
|
return self.type in users[propname]
|
|
return hasattr(self, propname)
|
|
|
|
def _set_host_helper(self, hostparam, portparam, val):
|
|
def parse_host(val):
|
|
host, ignore, port = (val or "").partition(":")
|
|
return host or None, port or None
|
|
|
|
host, port = parse_host(val)
|
|
if not host:
|
|
host = "127.0.0.1"
|
|
if host:
|
|
setattr(self, hostparam, host)
|
|
if port:
|
|
setattr(self, portparam, port)
|
|
|
|
def set_friendly_source(self, val):
|
|
self._set_host_helper("source_host", "source_port", val)
|
|
def set_friendly_bind(self, val):
|
|
self._set_host_helper("bind_host", "bind_port", val)
|
|
def set_friendly_target(self, val):
|
|
self._set_host_helper("target_address", "target_port", val)
|
|
|
|
|
|
_XML_PROP_ORDER = ["type",
|
|
"bind_host", "bind_port",
|
|
"source_mode", "source_host", "source_port",
|
|
"_source_path", "source_channel",
|
|
"target_type", "target_name", "target_state"]
|
|
|
|
type = XMLProperty("./@type")
|
|
_tty = XMLProperty("./@tty")
|
|
_source_path = XMLProperty("./source/@path")
|
|
|
|
def _get_source_path(self):
|
|
source = self._source_path
|
|
if source is None and self._tty:
|
|
return self._tty
|
|
return source
|
|
def _set_source_path(self, val):
|
|
self._source_path = val
|
|
source_path = property(_get_source_path, _set_source_path)
|
|
|
|
source_channel = XMLProperty("./source/@channel")
|
|
source_master = XMLProperty("./source/@master")
|
|
source_slave = XMLProperty("./source/@slave")
|
|
|
|
target_state = XMLProperty("./target/@state")
|
|
|
|
|
|
###################
|
|
# source handling #
|
|
###################
|
|
|
|
source_mode = XMLProperty("./source/@mode")
|
|
|
|
source_host = XMLProperty("./source[@mode='connect']/@host")
|
|
source_port = XMLProperty(
|
|
"./source[@mode='connect']/@service", is_int=True)
|
|
|
|
bind_host = XMLProperty("./source[@mode='bind']/@host")
|
|
bind_port = XMLProperty("./source[@mode='bind']/@service", is_int=True)
|
|
|
|
|
|
#######################
|
|
# Remaining XML props #
|
|
#######################
|
|
|
|
protocol = XMLProperty("./protocol/@type")
|
|
|
|
target_address = XMLProperty("./target/@address")
|
|
target_port = XMLProperty("./target/@port", is_int=True)
|
|
target_type = XMLProperty("./target/@type")
|
|
target_name = XMLProperty("./target/@name")
|
|
|
|
log_file = XMLProperty("./log/@file")
|
|
log_append = XMLProperty("./log/@append", is_onoff=True)
|
|
|
|
|
|
##################
|
|
# Default config #
|
|
##################
|
|
|
|
def set_defaults(self, _guest):
|
|
if not self.source_mode and self.supports_property("source_mode"):
|
|
self.source_mode = "bind"
|
|
if not self.protocol and self.supports_property("protocol"):
|
|
self.protocol = "raw"
|
|
if not self.target_type and self.DEVICE_TYPE == "channel":
|
|
self.target_type = "virtio"
|
|
if not self.target_name and self.type == self.TYPE_SPICEVMC:
|
|
self.target_name = self.CHANNEL_NAME_SPICE
|
|
|
|
|
|
|
|
class DeviceConsole(_DeviceChar):
|
|
XML_NAME = "console"
|
|
|
|
|
|
class DeviceSerial(_DeviceChar):
|
|
XML_NAME = "serial"
|
|
|
|
|
|
class DeviceParallel(_DeviceChar):
|
|
XML_NAME = "parallel"
|
|
|
|
|
|
class DeviceChannel(_DeviceChar):
|
|
XML_NAME = "channel"
|