mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-01-06 13:17:58 +03:00
f107e39989
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
271 lines
8.3 KiB
Python
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)
|