virt-manager/virtinst/devices/graphics.py
Cole Robinson f107e39989 Switch to more traditional logging structure
Init a shared log instance in virtinst/logger.py, and use that
throughout the code base, so we aren't calling directly into
'logging'. This helps protect our logging output from being
cluttered with other library output, as happens with some
'requests' usage
2019-06-17 00:12:31 -04:00

271 lines
8.3 KiB
Python

#
# Copyright 2006-2009, 2013 Red Hat, Inc.
#
# This work is licensed under the GNU GPLv2 or later.
# See the COPYING file in the top-level directory.
import os
from .device import Device
from ..logger import log
from ..xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty
def _get_mode_prop(channel_type):
xpath = "./channel[@name='%s']/@mode" % channel_type
return XMLProperty(xpath)
def _validate_port(name, val):
if val is None:
return val
val = int(val)
if val < 5900 and val != -1:
raise ValueError(_("%s must be above 5900, or "
"-1 for auto allocation") % name)
return val
class _GraphicsListen(XMLBuilder):
XML_NAME = "listen"
type = XMLProperty("./@type")
address = XMLProperty("./@address")
network = XMLProperty("./@network")
socket = XMLProperty("./@socket")
class DeviceGraphics(Device):
XML_NAME = "graphics"
TYPE_SDL = "sdl"
TYPE_VNC = "vnc"
TYPE_RDP = "rdp"
TYPE_SPICE = "spice"
CHANNEL_TYPE_MAIN = "main"
CHANNEL_TYPE_DISPLAY = "display"
CHANNEL_TYPE_INPUTS = "inputs"
CHANNEL_TYPE_CURSOR = "cursor"
CHANNEL_TYPE_PLAYBACK = "playback"
CHANNEL_TYPE_RECORD = "record"
KEYMAP_LOCAL = "local"
@staticmethod
def valid_keymaps():
"""
Return a list of valid keymap values.
"""
from .. import hostkeymap
orig_list = list(hostkeymap.keytable.values())
sort_list = []
orig_list.sort()
for k in orig_list:
if k not in sort_list:
sort_list.append(k)
return sort_list
def __init__(self, *args, **kwargs):
Device.__init__(self, *args, **kwargs)
self._local_keymap = -1
_XML_PROP_ORDER = ["type", "gl", "_port", "_tlsPort", "autoport",
"_keymap", "_listen",
"passwd", "display", "xauth"]
def _get_local_keymap(self):
if self._local_keymap == -1:
from .. import hostkeymap
self._local_keymap = hostkeymap.default_keymap()
return self._local_keymap
def _set_keymap(self, val):
if val == self.KEYMAP_LOCAL:
val = self._get_local_keymap()
self._keymap = val
def _get_keymap(self):
return self._keymap
_keymap = XMLProperty("./@keymap")
keymap = property(_get_keymap, _set_keymap)
def _set_port(self, val):
val = _validate_port("Port", val)
self.autoport = self._get_default_autoport()
self._port = val
def _get_port(self):
return self._port
_port = XMLProperty("./@port", is_int=True)
port = property(_get_port, _set_port)
def _set_tlsport(self, val):
val = _validate_port("TLS Port", val)
self.autoport = self._get_default_autoport()
self._tlsPort = val
def _get_tlsport(self):
return self._tlsPort
_tlsPort = XMLProperty("./@tlsPort", is_int=True)
tlsPort = property(_get_tlsport, _set_tlsport)
autoport = XMLProperty("./@autoport", is_yesno=True)
channel_main_mode = _get_mode_prop(CHANNEL_TYPE_MAIN)
channel_display_mode = _get_mode_prop(CHANNEL_TYPE_DISPLAY)
channel_inputs_mode = _get_mode_prop(CHANNEL_TYPE_INPUTS)
channel_cursor_mode = _get_mode_prop(CHANNEL_TYPE_CURSOR)
channel_playback_mode = _get_mode_prop(CHANNEL_TYPE_PLAYBACK)
channel_record_mode = _get_mode_prop(CHANNEL_TYPE_RECORD)
xauth = XMLProperty("./@xauth")
display = XMLProperty("./@display")
def _set_listen(self, val):
if val == "none":
self._set_listen_none()
elif val == "socket":
self._remove_all_listens()
obj = self.listens.add_new()
obj.type = "socket"
else:
self._remove_all_listens()
self._listen = val
def _get_listen(self):
return self._listen
_listen = XMLProperty("./@listen")
listen = property(_get_listen, _set_listen)
type = XMLProperty("./@type")
passwd = XMLProperty("./@passwd")
passwdValidTo = XMLProperty("./@passwdValidTo")
socket = XMLProperty("./@socket")
connected = XMLProperty("./@connected")
defaultMode = XMLProperty("./@defaultMode")
listens = XMLChildProperty(_GraphicsListen)
def _remove_all_listens(self):
for listen in self.listens:
self.remove_child(listen)
def get_first_listen_type(self):
if len(self.listens) > 0:
return self.listens[0].type
return None
def _set_listen_none(self):
self._remove_all_listens()
self.listen = None
self.port = None
self.tlsPort = None
self.autoport = None
self.socket = None
if self.conn.support.conn_graphics_listen_none():
obj = self.listens.add_new()
obj.type = "none"
# Spice bits
image_compression = XMLProperty("./image/@compression")
streaming_mode = XMLProperty("./streaming/@mode")
clipboard_copypaste = XMLProperty("./clipboard/@copypaste", is_yesno=True)
mouse_mode = XMLProperty("./mouse/@mode")
filetransfer_enable = XMLProperty("./filetransfer/@enable", is_yesno=True)
gl = XMLProperty("./gl/@enable", is_yesno=True)
rendernode = XMLProperty("./gl/@rendernode")
zlib_compression = XMLProperty("./zlib/@compression")
##################
# Default config #
##################
def _spice_supported(self):
if not self.conn.is_qemu() and not self.conn.is_test():
return False
# Spice has issues on some host arches, like ppc, so whitelist it
if self.conn.caps.host.cpu.arch not in ["i686", "x86_64"]:
return False
return True
def _listen_need_port(self):
listen = self.get_first_listen_type()
return not listen or listen in ["address", "network"]
def _get_default_port(self):
if self.type in ["vnc", "spice"] and self._listen_need_port():
return -1
return None
def _get_default_tlsport(self):
if self.type == "spice" and self._listen_need_port():
return -1
return None
def _get_default_autoport(self):
# By default, don't do this for VNC to maintain back compat with
# old libvirt that didn't support 'autoport'
if self.type != "spice":
return None
if (self.port == -1 and self.tlsPort == -1):
return True
return None
def _default_type(self, guest):
gtype = guest.default_graphics_type
log.debug("Using default_graphics=%s", gtype)
if gtype == "spice" and not self._spice_supported():
log.debug("spice requested but HV doesn't support it. "
"Using vnc.")
gtype = "vnc"
return gtype
def _default_image_compression(self, _guest):
if self.type != "spice":
return None
if not self.conn.is_remote():
log.debug("Local connection, disabling spice image "
"compression.")
return "off"
return None
def _default_spice_gl(self, _guest):
if not self.conn.support.conn_spice_gl(): # pragma: no cover
raise ValueError(_("Host does not support spice GL"))
# If spice GL but rendernode wasn't specified, hardcode
# the first one
if not self.rendernode and self.conn.support.conn_spice_rendernode():
for nodedev in self.conn.fetch_all_nodedevs():
if not nodedev.is_drm_render():
continue
self.rendernode = nodedev.get_devnode().path
break
def set_defaults(self, guest):
if not self.type:
self.type = self._default_type(guest)
if self.type == "sdl":
if not self.xauth:
self.xauth = os.path.expanduser("~/.Xauthority")
if not self.display:
self.display = os.environ.get("DISPLAY")
if self.port is None:
self.port = self._get_default_port()
if self.tlsPort is None:
self.tlsPort = self._get_default_tlsport()
if self.autoport is None:
self.autoport = self._get_default_autoport()
if not self.image_compression:
self.image_compression = self._default_image_compression(guest)
if self.type == "spice" and self.gl:
self._default_spice_gl(guest)