2013-03-18 01:06:52 +04:00
#
2013-10-28 00:59:46 +04:00
# Copyright 2006-2009, 2013 Red Hat, Inc.
2013-03-18 01:06:52 +04:00
#
2018-04-04 16:35:41 +03:00
# This work is licensed under the GNU GPLv2 or later.
2018-03-20 22:00:02 +03:00
# See the COPYING file in the top-level directory.
2013-03-18 01:06:52 +04:00
2018-09-02 01:11:58 +03:00
import logging
2013-03-18 01:06:52 +04:00
import os
2018-03-20 19:18:35 +03:00
from . device import Device
2018-03-20 19:27:37 +03:00
from . . xmlbuilder import XMLBuilder , XMLChildProperty , XMLProperty
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-03-18 01:06:52 +04:00
def _get_mode_prop ( channel_type ) :
xpath = " ./channel[@name= ' %s ' ]/@mode " % channel_type
2013-09-19 21:27:30 +04:00
return XMLProperty ( xpath )
2013-03-18 01:06:52 +04:00
2013-04-13 22:34:52 +04:00
2013-07-16 02:53:53 +04:00
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
2014-01-29 17:18:01 +04:00
class _GraphicsListen ( XMLBuilder ) :
2018-03-21 17:53:34 +03:00
XML_NAME = " listen "
2014-01-29 17:18:01 +04:00
type = XMLProperty ( " ./@type " )
address = XMLProperty ( " ./@address " )
network = XMLProperty ( " ./@network " )
2017-09-06 11:26:33 +03:00
socket = XMLProperty ( " ./@socket " )
2014-01-29 17:18:01 +04:00
2018-03-20 19:18:35 +03:00
class DeviceGraphics ( Device ) :
2018-03-21 17:53:34 +03:00
XML_NAME = " graphics "
2013-03-18 01:06:52 +04:00
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 "
KEYMAP_DEFAULT = " default "
_special_keymaps = [ KEYMAP_LOCAL , KEYMAP_DEFAULT ]
@staticmethod
def valid_keymaps ( ) :
"""
Return a list of valid keymap values .
"""
2018-03-20 19:27:37 +03:00
from . . import hostkeymap
2013-03-18 01:06:52 +04:00
2017-10-11 14:35:46 +03:00
orig_list = list ( hostkeymap . keytable . values ( ) )
2013-03-18 01:06:52 +04:00
sort_list = [ ]
orig_list . sort ( )
for k in orig_list :
if k not in sort_list :
sort_list . append ( k )
return sort_list
@staticmethod
def pretty_type_simple ( gtype ) :
2018-03-20 19:18:35 +03:00
if ( gtype in [ DeviceGraphics . TYPE_VNC ,
DeviceGraphics . TYPE_SDL ,
DeviceGraphics . TYPE_RDP ] ) :
2013-03-18 01:06:52 +04:00
return str ( gtype ) . upper ( )
return str ( gtype ) . capitalize ( )
2013-09-11 19:47:09 +04:00
def __init__ ( self , * args , * * kwargs ) :
2018-03-20 19:18:35 +03:00
Device . __init__ ( self , * args , * * kwargs )
2013-03-18 01:06:52 +04:00
2013-04-14 00:14:14 +04:00
self . _local_keymap = - 1
2013-03-18 01:06:52 +04:00
2013-07-16 02:53:53 +04:00
2018-09-04 00:03:02 +03:00
_XML_PROP_ORDER = [ " type " , " gl " , " _port " , " _tlsPort " , " autoport " ,
" _keymap " , " _listen " ,
2013-07-16 02:53:53 +04:00
" passwd " , " display " , " xauth " ]
2018-04-24 21:11:30 +03:00
def _get_local_keymap ( self ) :
2013-04-14 00:14:14 +04:00
if self . _local_keymap == - 1 :
2018-03-20 19:27:37 +03:00
from . . import hostkeymap
2013-04-14 00:31:13 +04:00
self . _local_keymap = hostkeymap . default_keymap ( )
2013-04-14 00:14:14 +04:00
return self . _local_keymap
2013-03-18 01:06:52 +04:00
2018-09-04 00:03:02 +03:00
def _set_keymap ( self , val ) :
2013-07-16 02:53:53 +04:00
if val == self . KEYMAP_DEFAULT :
2018-04-24 21:11:30 +03:00
# Leave it up to the hypervisor
2018-09-04 00:03:02 +03:00
val = None
elif 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 ) :
2014-03-23 02:25:53 +04:00
val = _validate_port ( " Port " , val )
self . autoport = self . _get_default_autoport ( )
2018-09-04 00:03:02 +03:00
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 ) :
2014-03-23 02:25:53 +04:00
val = _validate_port ( " TLS Port " , val )
self . autoport = self . _get_default_autoport ( )
2018-09-04 00:03:02 +03:00
self . _tlsPort = val
def _get_tlsport ( self ) :
return self . _tlsPort
_tlsPort = XMLProperty ( " ./@tlsPort " , is_int = True )
tlsPort = property ( _get_tlsport , _set_tlsport )
2018-09-02 01:11:58 +03:00
autoport = XMLProperty ( " ./@autoport " , is_yesno = True )
2013-03-18 01:06:52 +04:00
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 )
2018-09-02 01:11:58 +03:00
xauth = XMLProperty ( " ./@xauth " )
display = XMLProperty ( " ./@display " )
2013-07-16 02:53:53 +04:00
2014-01-29 17:18:01 +04:00
def _set_listen ( self , val ) :
2019-02-22 18:32:39 +03:00
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
2018-09-04 00:03:02 +03:00
def _get_listen ( self ) :
return self . _listen
_listen = XMLProperty ( " ./@listen " )
listen = property ( _get_listen , _set_listen )
2014-01-29 17:18:01 +04:00
2018-09-02 01:11:58 +03:00
type = XMLProperty ( " ./@type " )
2013-09-19 21:27:30 +04:00
passwd = XMLProperty ( " ./@passwd " )
passwdValidTo = XMLProperty ( " ./@passwdValidTo " )
socket = XMLProperty ( " ./@socket " )
2014-01-29 18:52:49 +04:00
connected = XMLProperty ( " ./@connected " )
2014-02-28 02:43:59 +04:00
defaultMode = XMLProperty ( " ./@defaultMode " )
2013-07-24 16:46:55 +04:00
2014-01-29 17:18:01 +04:00
listens = XMLChildProperty ( _GraphicsListen )
2019-02-22 18:32:39 +03:00
def _remove_all_listens ( self ) :
2016-06-11 23:44:54 +03:00
for listen in self . listens :
self . remove_child ( listen )
2017-02-21 16:00:59 +03:00
def get_first_listen_type ( self ) :
if len ( self . listens ) > 0 :
return self . listens [ 0 ] . type
return None
2019-02-22 18:32:39 +03:00
def _set_listen_none ( self ) :
self . _remove_all_listens ( )
2017-02-21 16:00:58 +03:00
self . listen = None
2016-06-11 23:44:54 +03:00
self . port = None
self . tlsPort = None
2017-02-21 16:00:57 +03:00
self . autoport = None
2016-06-11 23:44:54 +03:00
self . socket = None
if self . conn . check_support (
2017-09-20 10:36:27 +03:00
self . conn . SUPPORT_CONN_GRAPHICS_LISTEN_NONE ) :
2018-02-08 01:27:56 +03:00
obj = self . listens . add_new ( )
2016-06-11 23:44:54 +03:00
obj . type = " none "
2014-01-29 17:18:01 +04:00
2015-04-11 23:56:27 +03:00
# 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 )
2016-03-04 14:31:51 +03:00
gl = XMLProperty ( " ./gl/@enable " , is_yesno = True )
2017-02-21 16:01:00 +03:00
rendernode = XMLProperty ( " ./gl/@rendernode " )
2019-05-16 17:21:19 +03:00
zlib_compression = XMLProperty ( " ./zlib/@compression " )
2018-09-02 01:11:58 +03:00
##################
# 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
logging . debug ( " Using default_graphics= %s " , gtype )
if gtype == " spice " and not self . _spice_supported ( ) :
logging . 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 ( ) :
logging . debug ( " Local connection, disabling spice image "
" compression. " )
return " off "
return None
def _default_spice_gl ( self , _guest ) :
if not self . conn . check_support (
self . conn . SUPPORT_CONN_SPICE_GL ) :
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 . check_support (
self . conn . SUPPORT_CONN_SPICE_RENDERNODE ) :
for nodedev in self . conn . fetch_all_nodedevs ( ) :
if ( nodedev . device_type != ' drm ' or
nodedev . drm_type != ' 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 )