[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: 0.2.1.1-33-g01ea13f
X2Go dev team
git-admin at x2go.org
Wed Jan 8 15:31:29 CET 2014
The branch, build-baikal has been updated
via 01ea13f9b472bf7139c0640fbddb1cf4309c0861 (commit)
from 3133baf8a3c0e8dc6d80bad8d5aef6b0d0f34862 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
-----------------------------------------------------------------------
Summary of changes:
debian/changelog | 2 +
x2go/backends/control/_stdout.py | 54 ++++++++++++++++++---
x2go/backends/terminal/_stdout.py | 57 ++++++++++++++++++++++
x2go/client.py | 84 ++++++++++++++++++++++++++++++--
x2go/session.py | 95 ++++++++++++++++++++++++++++++-------
5 files changed, 263 insertions(+), 29 deletions(-)
The diff of changes is:
diff --git a/debian/changelog b/debian/changelog
index 87f6a60..b9c9ed2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -25,6 +25,8 @@ python-x2go (0.4.0.0-0~x2go1) UNRELEASED; urgency=low
- Fix auto-starting and auto-resuming of sessions.
- Avoid false-positive notifications of dead control session directly after
a disconnect request from the user.
+ - Improve desktop sharing code. Add code to obtain version information of
+ server-side X2Go components.
-- Mike Gabriel <mike.gabriel at das-netzwerkteam.de> Thu, 20 Dec 2012 08:58:44 +0100
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index b8c4c10..52eee5f 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -194,6 +194,7 @@ class X2GoControlSessionSTDOUT(paramiko.SSHClient):
self._remote_username = None
self._remote_peername = None
+ self._server_versions = None
self._server_features = None
if logger is None:
@@ -439,18 +440,51 @@ class X2GoControlSessionSTDOUT(paramiko.SSHClient):
return _retval
@property
+ def _x2go_server_versions(self):
+ """\
+ Render a dictionary of server-side X2Go components and their versions. Results get cached
+ once there has been one successful query.
+
+ """
+ if self._server_versions is None:
+ self._server_versions = {}
+ (stdin, stdout, stderr) = self._x2go_exec_command('which x2goversion >/dev/null && x2goversion')
+ _lines = stdout.read().split('\n')
+ for _line in _lines:
+ if ':' not in _line: continue
+ comp = _line.split(':')[0].strip()
+ version = _line.split(':')[1].strip()
+ self._server_versions.update({comp: version})
+ self.logger('server-side X2Go components and their versions are: %s' % self._server_versions, loglevel=log.loglevel_DEBUG)
+ return self._server_versions
+
+ def query_server_versions(self, force=False):
+ """\
+ Do a query for the server-side list of X2Go components and their versions.
+
+ @param force: do not use the cached component list, really ask the server (again)
+ @type force: C{bool}
+
+ @return: dictionary of X2Go components (as keys) and their versions (as values)
+ @rtype: C{list}
+
+ """
+ if force:
+ self._server_versions = None
+ return self._x2go_server_versions
+ get_server_versions = query_server_versions
+
+ @property
def _x2go_server_features(self):
"""\
- Render a list of server-side X2Go features. Results get cached once there has been one successfull query.
+ Render a list of server-side X2Go features. Results get cached once there has been one successful query.
"""
if self._server_features is None:
(stdin, stdout, stderr) = self._x2go_exec_command('which x2gofeaturelist >/dev/null && x2gofeaturelist')
self._server_features = stdout.read().split('\n')
self.logger('server-side X2Go features are: %s' % self._server_features, loglevel=log.loglevel_DEBUG)
- return self._server_features
- else:
- return self._server_features
+ return self._server_features
def query_server_features(self, force=False):
"""\
@@ -1333,7 +1367,7 @@ class X2GoControlSessionSTDOUT(paramiko.SSHClient):
user = desktop.split('@')[0]
display = desktop.split('@')[1]
if not (user and display):
- raise x2go_exceptions.X2GoDesktopSharingException('Need user name and display number of sharable desktop.')
+ raise x2go_exceptions.X2GoDesktopSharingException('Need user name and display number of shared desktop.')
cmd = '%sXSHAD%sXSHAD%s' % (share_mode, user, display)
@@ -1443,7 +1477,10 @@ class X2GoControlSessionSTDOUT(paramiko.SSHClient):
be interpreted as disconnected due to connection loss
"""
if raw:
- (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
+ if 'X2GO_LIST_SHADOWSESSIONS' in self._x2go_server_features:
+ (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && { x2golistsessions; x2golistshadowsessions; }")
+ else:
+ (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
return stdout.read(), stderr.read()
else:
@@ -1460,7 +1497,10 @@ class X2GoControlSessionSTDOUT(paramiko.SSHClient):
while not _success and _count < _maxwait:
_count += 1
try:
- (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
+ if 'X2GO_LIST_SHADOWSESSIONS' in self._x2go_server_features:
+ (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && { x2golistsessions; x2golistshadowsessions; }")
+ else:
+ (stdin, stdout, stderr) = self._x2go_exec_command("export HOSTNAME && x2golistsessions")
_stdout_read = stdout.read()
_listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
_success = True
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 0156700..4872832 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -983,6 +983,18 @@ class X2GoTerminalSessionSTDOUT(object):
# session title fallback... (like X2Go server does it...)
self.session_title = _generic_title
+ elif self.params.session_type == 'S':
+ if self.set_session_title:
+
+ shared_user = _generic_title.split('XSHAD')[1]
+ shared_display = _generic_title.split('XSHAD')[2].replace('PP', ':').split("_")[0]
+
+ self.session_title = 'Desktop %s@%s shared with %s@%s' % (shared_user, shared_display, self.control_session.remote_username(), self.control_session.get_hostname())
+
+ else:
+ # session title fallback... (like X2Go server does it...)
+ self.session_title = _generic_title
+
else:
# do nothing for rootless sessions
self.session_title = _generic_title
@@ -1616,3 +1628,48 @@ class X2GoTerminalSessionSTDOUT(object):
self._rm_desktop_dirtree()
self._cleaned_up = True
+
+ def is_desktop_session(self):
+ """\
+ Test if this terminal session is a desktop session.
+
+ @return: C{True} if this session is of session type desktop ('D').
+ @rtype: C{bool}
+
+ """
+ self.params.rewrite_session_type()
+ return self.params.session_type == 'D'
+
+ def is_rootless_session(self):
+ """\
+ Test if this terminal session is a rootless session.
+
+ @return: C{True} if this session is of session type rootless ('R').
+ @rtype: C{bool}
+
+ """
+ self.params.rewrite_session_type()
+ return self.params.session_type == 'R'
+
+ def is_shadow_session(self):
+ """\
+ Test if this terminal session is a desktop sharing (aka shadow) session.
+
+ @return: C{True} if this session is of session type shadow ('S').
+ @rtype: C{bool}
+
+ """
+ self.params.rewrite_session_type()
+ return self.params.session_type == 'S'
+
+ def is_pubapp_session(self):
+ """\
+ Test if this terminal session is a published applications session.
+
+ @return: C{True} if this session is of session type published applications ('P').
+ @rtype: C{bool}
+
+ """
+ self.params.rewrite_session_type()
+ return self.params.session_type == 'P'
+
diff --git a/x2go/client.py b/x2go/client.py
index 3a091f2..b7fd646 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -38,6 +38,7 @@ Supported Features
- enabling and mangaging X2Go printing (real printing, viewing as PDF, saving
to a local folder or executing a custom »print« command
- transparent tunneling of audio (Pulseaudio, ESD)
+ - sharing of other desktops
- LDAP support for X2Go server clusters (NOT IMPLEMENTED YET)
Non-Profile Sessions
@@ -384,6 +385,20 @@ class X2GoClient(object):
"""
self.logger('HOOK_session_startup_failed: session startup for session profile ,,%s'' failed.' % profile_name, loglevel=log.loglevel_WARN)
+ def HOOK_list_desktops_timeout(self, profile_name='UNKNOWN'):
+ """\
+ HOOK method: called if the x2golistdesktops command generates a timeout due to long execution time.
+
+ """
+ self.logger('HOOK_list_desktops_timeout: the server-side x2golistdesktops command for session profile %s took too long to return results. This can happen from time to time, please try again.' % profile_name, loglevel=log.loglevel_WARN)
+
+ def HOOK_no_such_desktop(self, profile_name='UNKNOWN', desktop='UNKNOWN'):
+ """\
+ HOOK method: called if it is tried to connect to a (seen before) sharable desktop that's not available (anymore).
+
+ """
+ self.logger('HOOK_no_such_desktop: the desktop %s (via session profile %s) is not available for sharing (anymore).' % (desktop, profile_name), loglevel=log.loglevel_WARN)
+
def HOOK_no_known_xserver_found(self):
"""\
HOOK method: called if the Python X2Go module could not find any usable XServer
@@ -477,7 +492,6 @@ class X2GoClient(object):
# this HOOK has to return either True (accept host connection) or False (deny host conection)
return True
-
def HOOK_on_control_session_death(self, profile_name):
"""\
HOOK method: called if a control session (server connection) has unexpectedly encountered a failure.
@@ -1465,7 +1479,7 @@ class X2GoClient(object):
return _retval
__start_session = start_session
- def share_desktop_session(self, session_uuid, desktop=None, user=None, display=None, share_mode=0, **sessionopts):
+ def share_desktop_session(self, session_uuid, desktop=None, user=None, display=None, share_mode=0, check_desktop_list=False, **sessionopts):
"""\
Share another already running desktop session. Desktop sharing can be run
in two different modes: view-only and full-access mode. Like new sessions
@@ -1503,10 +1517,8 @@ class X2GoClient(object):
if not _desktop in self._X2GoClient__list_desktops(session_uuid):
_orig_desktop = _desktop
_desktop = '%s.0' % _desktop
- if not _desktop in self._X2GoClient__list_desktops(session_uuid):
- raise x2go_exceptions.X2GoDesktopSharingException('No such desktop ID: %s' % _orig_desktop)
- return self.session_registry(session_uuid).share_desktop(desktop=_desktop, share_mode=share_mode, check_desktop_list=False, **sessionopts)
+ return self.session_registry(session_uuid).share_desktop(desktop=_desktop, share_mode=share_mode, check_desktop_list=check_desktop_list, **sessionopts)
__share_desktop_session = share_desktop_session
def resume_session(self, session_uuid=None, session_name=None, match_profile_name=None, **sessionopts):
@@ -2022,6 +2034,7 @@ class X2GoClient(object):
@type return_profile_ids: C{bool}
@param return_session_names: return as list of session names
@type return_session_names: C{bool}
+
@return: list of connected sessions
@rtype: C{list}
@@ -2050,6 +2063,7 @@ class X2GoClient(object):
@type return_profile_ids: C{bool}
@param return_session_names: return as list of session names
@type return_session_names: C{bool}
+
@return: list of associated sessions
@rtype: C{list}
@@ -2078,6 +2092,7 @@ class X2GoClient(object):
@type return_profile_ids: C{bool}
@param return_session_names: return as list of session names
@type return_session_names: C{bool}
+
@return: list of running sessions
@rtype: C{list}
@@ -2106,6 +2121,7 @@ class X2GoClient(object):
@type return_profile_ids: C{bool}
@param return_session_names: return as list of session names
@type return_session_names: C{bool}
+
@return: list of suspended sessions
@rtype: C{list}
@@ -2134,6 +2150,7 @@ class X2GoClient(object):
@type return_profile_ids: C{bool}
@param return_session_names: return as list of session names
@type return_session_names: C{bool}
+
@return: list of registered sessions
@rtype: C{list}
@@ -2164,6 +2181,63 @@ class X2GoClient(object):
return self.session_registry.control_session_of_profile_name(profile_name)
__client_control_session_of_profile_name = client_control_session_of_profile_name
+ def get_server_versions(self, profile_name, component=None):
+ """\
+ Query the server configured in session profile <profile_name> for the list of install X2Go components
+ and its versions.
+
+ @param profile_name: use the control session of this profile to query the X2Go server for its component list
+ @type profile_name: C{str}
+ @param component: only return the version of a specific component
+ @type component: C{str}
+
+ @return: dictionary of server components (as keys) and their versions (as values) or the version of the given <component>
+ @rtype: C{dict} or C{str}
+
+ @raise X2GoClientException: if component is not available on the X2Go Server.
+
+ """
+ control_session = self.client_control_session_of_profile_name(profile_name)
+ if component is None:
+ return control_session.get_server_versions()
+ else:
+ try:
+ return control_session.get_server_versions()[component]
+ except KeyError:
+ raise x2go_exceptions.X2GoClientException('No such component on X2Go Server')
+
+ def get_server_features(self, profile_name):
+ """\
+ Query the server configured in session profile <profile_name> for the list of server-side
+ X2Go features.
+
+ @param profile_name: use the control session of this profile to query the X2Go server for its feature list
+ @type profile_name: C{str}
+
+ @return: list of server feature names (as returned by server-side command ,,x2gofeaturelist''
+ @rtype: C{list}
+
+ """
+ control_session = self.client_control_session_of_profile_name(profile_name)
+ return control_session.get_server_features()
+
+ def has_server_feature(self, profile_name, feature):
+ """\
+ Query the server configured in session profile <profile_name> for the availability
+ of a certain server feature.
+
+ @param profile_name: use the control session of this profile to query the X2Go server for its feature
+ @type profile_name: C{str}
+ @param feature: test the availability of this feature on the X2Go server
+ @type feature: C{str}
+
+ @return: C{True} if the feature is available on the queried server
+ @rtype: C{bool}
+
+ """
+ control_session = self.client_control_session_of_profile_name(profile_name)
+ return feature in control_session.get_server_features()
+
def client_registered_session_of_name(self, session_name, return_object=False):
"""\
Retrieve X2Go session of a given session name.
diff --git a/x2go/session.py b/x2go/session.py
index 2284c09..fbe1bf3 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -467,6 +467,26 @@ class X2GoSession(object):
else:
self.logger('HOOK_session_startup_failed: session startup for session profile ,,%s\'\' failed.' % self.profile_name, loglevel=log.loglevel_WARN)
+ def HOOK_list_desktops_timeout(self):
+ """\
+ HOOK method: called if the x2golistdesktops command generates a timeout due to long execution time.
+
+ """
+ if self.client_instance:
+ self.client_instance.HOOK_list_desktops_timeout(profile_name=self.profile_name)
+ else:
+ self.logger('HOOK_list_desktops_timeout: the server-side x2golistdesktops command for session profile %s took too long to return results. This can happen from time to time, please try again.' % self.profile_name, loglevel=log.loglevel_WARN)
+
+ def HOOK_no_such_desktop(self, desktop='UNKNOWN'):
+ """\
+ HOOK method: called if it is tried to connect to a shared desktop that's not available (anymore).
+
+ """
+ if self.client_instance:
+ self.client_instance.HOOK_no_such_desktop(profile_name=self.profile_name, desktop=desktop)
+ else:
+ self.logger('HOOK_no_such_desktop: the desktop %s (via session profile %s) is not available for sharing (anymore).' % (desktop, self.profile_name), loglevel=log.loglevel_WARN)
+
def HOOK_rforward_request_denied(self, server_port=0):
"""\
HOOK method: called if a reverse port forwarding request has been denied.
@@ -1451,6 +1471,9 @@ class X2GoSession(object):
"""
try:
return self.control_session.list_desktops(raw=raw)
+ except x2go_exceptions.X2GoTimeoutException:
+ if self.is_alive(): self.HOOK_list_desktop_timeout()
+ return []
except x2go_exceptions.X2GoControlSessionException:
if self.connected: self.HOOK_on_control_session_death()
self._X2GoSession__disconnect()
@@ -1570,19 +1593,6 @@ class X2GoSession(object):
return False
__is_published_applications_provider = is_published_applications_provider
- def is_desktop_session(self):
- """\
- Returns true if this session is configured as desktop session.
-
- @return: returns C{True} if this session is a desktop session.
- @rtype: C{bool}
-
- """
- if self.has_terminal_session():
- return self.terminal_session.is_desktop_session()
- return False
- __is_desktop_session = is_desktop_session
-
def get_published_applications(self, lang=None, refresh=False, raw=False, very_raw=False, max_no_submenus=defaults.PUBAPP_MAX_NO_SUBMENUS):
"""\
Return a list of published menu items from the X2Go server
@@ -1928,7 +1938,6 @@ class X2GoSession(object):
self._X2GoSession__disconnect()
return False
-
__resume = resume
def start(self, cmd=None, progress_event=None):
@@ -2029,11 +2038,15 @@ class X2GoSession(object):
_desktop = desktop or '%s@%s' % (user, display)
if check_desktop_list:
- if not _desktop in self._X2GoSession__list_desktops():
+ desktop_list = self._X2GoSession__list_desktops()
+ if not _desktop in desktop_list:
_orig_desktop = _desktop
_desktop = '%s.0' % _desktop
- if not _desktop in self._X2GoSession__list_desktops():
- raise x2go_exceptions.X2GoDesktopSharingException('No such desktop ID: %s' % _orig_desktop)
+ if not _desktop in desktop_list:
+ self.HOOK_no_such_desktop(desktop=_orig_desktop)
+ self._progress_status = -1
+ progress_event.set()
+ return False
self._progress_status = 33
progress_event.set()
@@ -2101,6 +2114,54 @@ class X2GoSession(object):
return False
__share_desktop = share_desktop
+ def is_desktop_session(self):
+ """\
+ Test if this X2Go session is a desktop session.
+
+ @return: C{True} if this session is of session type desktop ('D').
+ @rtype: C{bool}
+
+ """
+ if self.has_terminal_session():
+ return self.terminal_session.is_desktop_session()
+ __is_desktop_session = is_desktop_session
+
+ def is_rootless_session(self):
+ """\
+ Test if this X2Go session is a rootless session.
+
+ @return: C{True} if this session is of session type rootless ('R').
+ @rtype: C{bool}
+
+ """
+ if self.has_terminal_session():
+ return self.terminal_session.is_rootless_session()
+ __is_rootless_session = is_rootless_session
+
+ def is_shadow_session(self):
+ """\
+ Test if this X2Go session is a desktop sharing (aka shadow) session.
+
+ @return: C{True} if this session is of session type shadow ('S').
+ @rtype: C{bool}
+
+ """
+ if self.has_terminal_session():
+ return self.terminal_session.is_shadow_session()
+ __is_shadow_session = is_shadow_session
+
+ def is_pubapp_session(self):
+ """\
+ Test if this X2Go session is a published applications session.
+
+ @return: C{True} if this session is of session type published applications ('P').
+ @rtype: C{bool}
+
+ """
+ if self.has_terminal_session():
+ return self.terminal_session.is_pubapp_session()
+ __is_pubapp_session = is_pubapp_session
+
def suspend(self):
"""\
Suspend this X2Go session.
hooks/post-receive
--
python-x2go.git (Python X2Go Client API)
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "python-x2go.git" (Python X2Go Client API).
More information about the x2go-commits
mailing list