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
import os
2018-03-20 19:18:35 +03:00
from . device import Device
2019-06-17 04:12:39 +03:00
from . . logger import log
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-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 "
2024-03-25 16:42:32 +03:00
_XML_PROP_ORDER = [ " _type " , " gl " , " _port " , " _tlsPort " , " autoport " , " websocket " ,
2020-01-25 00:03:17 +03:00
" keymap " , " _listen " ,
2013-07-16 02:53:53 +04:00
" passwd " , " display " , " xauth " ]
2020-01-25 00:03:17 +03:00
keymap = XMLProperty ( " ./@keymap " )
2018-09-04 00:03:02 +03:00
2024-03-25 16:42:32 +03:00
def _set_type ( self , val ) :
self . _type = val
# connected is valid for Spice and VNC, but VNC accepts only 'keep' and
# libvirt errors out if there is any other value
if val == " vnc " and self . connected != " keep " :
self . connected = None
def _get_type ( self ) :
return self . _type
_type = XMLProperty ( " ./@type " )
type = property ( _get_type , _set_type )
2018-09-04 00:03:02 +03:00
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 )
2020-07-16 15:55:17 +03:00
websocket = XMLProperty ( " ./@websocket " , is_int = True )
2013-03-18 01:06:52 +04:00
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
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
2019-06-07 23:06:52 +03:00
if 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 _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
2022-02-10 18:17:15 +03:00
log . debug ( " App is configured with default_graphics= %s " , gtype )
2022-02-10 18:13:44 +03:00
if self . conn . is_xen ( ) :
# Xen domcaps can advertise spice support, but we have historically
# not defaulted to it for xen, so force vnc.
log . debug ( " Not defaulting to spice for xen driver. Using vnc. " )
gtype = " vnc "
2021-06-08 17:30:30 +03:00
if ( gtype == " spice " and
not guest . lookup_domcaps ( ) . supports_graphics_spice ( ) ) :
2022-02-10 18:17:15 +03:00
log . debug ( " spice requested but HV doesn ' t support it. Using vnc. " )
2018-09-02 01:11:58 +03:00
gtype = " vnc "
return gtype
def _default_image_compression ( self , _guest ) :
if self . type != " spice " :
return None
if not self . conn . is_remote ( ) :
2019-06-17 04:12:39 +03:00
log . debug ( " Local connection, disabling spice image "
2018-09-02 01:11:58 +03:00
" compression. " )
return " off "
return None
def _default_spice_gl ( self , _guest ) :
# If spice GL but rendernode wasn't specified, hardcode
# the first one
2020-08-24 19:14:21 +03:00
if not self . rendernode :
2018-09-02 01:11:58 +03:00
for nodedev in self . conn . fetch_all_nodedevs ( ) :
2019-06-05 23:13:44 +03:00
if not nodedev . is_drm_render ( ) :
2018-09-02 01:11:58 +03:00
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 )