[X2Go-Commits] python-x2go.git - build-baikal (branch) updated: 35ec0740ece713767617c85c90c32c044dd23338
X2Go dev team
git-admin at x2go.org
Wed Jan 8 15:29:19 CET 2014
The branch, build-baikal has been updated
via 35ec0740ece713767617c85c90c32c044dd23338 (commit)
from e3fe57d1ad10f04c05565d3dbb712bc1d3f0caf5 (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:
x2go/backends/control/stdout.py | 80 ++++++----------
x2go/backends/profiles/sessions_file.py | 21 ----
x2go/backends/terminal/stdout.py | 20 ++--
x2go/cache.py | 95 ++++++++++---------
x2go/cleanup.py | 22 ++---
x2go/client.py | 158 +++++++++++++++++++++++--------
x2go/defaults.py | 3 +-
x2go/guardian.py | 23 ++---
x2go/registry.py | 66 ++++++++++++-
x2go/session.py | 33 ++++---
x2go/utils.py | 1 -
x2go/x2go_exceptions.py | 5 +-
12 files changed, 308 insertions(+), 219 deletions(-)
The diff of changes is:
diff --git a/x2go/backends/control/stdout.py b/x2go/backends/control/stdout.py
index 42ae7c9..088b48d 100644
--- a/x2go/backends/control/stdout.py
+++ b/x2go/backends/control/stdout.py
@@ -37,7 +37,6 @@ import x2go.log as log
import x2go.utils as utils
import x2go.x2go_exceptions as x2go_exceptions
import x2go.defaults as defaults
-import x2go.cache as cache
from x2go.backends.terminal import X2goTerminalSession as _X2goTerminalSession
from x2go.backends.info import X2goServerSessionInfo as _X2goServerSessionInfo
@@ -56,13 +55,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
@type loglevel: int
"""
+ associated_terminals = None
+
def __init__(self,
terminal_backend=_X2goTerminalSession,
info_backend=_X2goServerSessionInfo,
list_backend=_X2goServerSessionList,
proxy_backend=_X2goProxy,
- use_listsessions_cache=True,
- controlled_session=None,
logger=None, loglevel=log.loglevel_DEFAULT,
*args, **kwargs):
"""\
@@ -73,28 +72,21 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
"""
self.associated_terminals = {}
self.terminated_terminals = []
- self.controlled_sessions = {}
self._session_auth_rsakey = None
self._remote_home = None
self._remote_group = {}
- self.x2go_listsessions_cache = None
-
if logger is None:
self.logger = log.X2goLogger(loglevel=loglevel)
else:
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- if controlled_session is not None:
- self.controlled_sessions[controlled_session._X2goSession__get_uuid()] = controlled_session
-
self._terminal_backend = terminal_backend
self._info_backend = info_backend
self._list_backend = list_backend
self._proxy_backend = proxy_backend
- self.use_listsessions_cache = use_listsessions_cache
paramiko.SSHClient.__init__(self, *args, **kwargs)
def __del__(self):
@@ -131,10 +123,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
self.logger('executing command on X2go server: %s' % cmd, loglevel)
return self.exec_command(cmd, **kwargs)
except AttributeError:
- raise x2go_exceptions.X2goSessionException('a Paramiko/SSH control session has died')
+ raise x2go_exceptions.X2goControlSessionException('a Paramiko/SSH control session has died')
else:
- raise x2go_exceptions.X2goSessionException('the Paramiko/SSH client is not connected')
+ raise x2go_exceptions.X2goControlSessionException('the Paramiko/SSH client is not connected')
@property
def _x2go_remote_home(self):
@@ -276,10 +268,6 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
ssh_transport._x2go_session_marker = True
self._session_password = password
- if self.use_listsessions_cache:
- self.x2go_listsessions_cache = cache.X2goListSessionsCache(self, logger=self.logger)
- self.x2go_listsessions_cache.start()
-
return (self.get_transport() is not None)
def disconnect(self):
@@ -287,33 +275,34 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
STILL UNDOCUMENTED
"""
- if self.x2go_listsessions_cache is not None:
- self.x2go_listsessions_cache.stop_thread()
- del self.x2go_listsessions_cache
- self.x2go_listsessions_cache = None
-
- t_names = self.associated_terminals.keys()
- for t_obj in self.associated_terminals.values():
- try:
- t_obj.suspend()
- except x2go_exceptions.X2goSessionException:
- pass
- del t_obj
- for t_name in t_names:
- del self.associated_terminals[t_name]
+ if self.associated_terminals is not None:
+ t_names = self.associated_terminals.keys()
+ for t_obj in self.associated_terminals.values():
+ try:
+ t_obj.suspend()
+ except x2go_exceptions.X2goTerminalSessionException:
+ pass
+ del t_obj
+ for t_name in t_names:
+ del self.associated_terminals[t_name]
self._remote_home = None
self._remote_group = {}
self._session_auth_rsakey = None
- if self.get_transport() is not None:
- self.get_transport().close()
+
+ try:
+ if self.get_transport() is not None:
+ self.get_transport().close()
+ except AttributeError:
+ # if the Paramiko _transport object has not yet been initialized, ignore it
+ pass
def is_alive(self):
try:
self._x2go_exec_command('echo', loglevel=log.loglevel_DEBUG)
return True
- except x2go_exceptions.X2goSessionException:
+ except x2go_exceptions.X2goControlSessionException:
return False
def start(self, **kwargs):
@@ -342,7 +331,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group x2gousers' % self.get_transport().get_username())
if session_name is not None:
- session_info = self.list_sessions(refresh_cache=True)[session_name]
+ session_info = self.list_sessions()[session_name]
else:
session_info = None
@@ -379,7 +368,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
return _terminal or None
- def list_sessions(self, raw=False, no_cache=False, refresh_cache=False):
+ def list_sessions(self, raw=False):
"""\
List all sessions of current user on the connected server.
@@ -396,25 +385,18 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
if raw:
return stdout.read(), stderr.read()
- elif no_cache or refresh_cache or (self.use_listsessions_cache is False) or (self.x2go_listsessions_cache is None):
+ else:
try:
(stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
_stdout_read = stdout.read()
_listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
- if refresh_cache and self.x2go_listsessions_cache is not None:
- self.x2go_listsessions_cache.update_session_list(session_list=_listsessions)
return _listsessions
- except X2goSessionException, e:
- self.logger('encountered X2goSessionsException: %s' % str(e), loglevel=log.loglevel_ERROR)
- self._X2goSessions__disconnect()
-
- else:
-
- return self.x2go_listsessions_cache.list_sessions()
+ except X2goSessionControlException, e:
+ self.logger('encountered X2goSessionsControlException: %s' % str(e), loglevel=log.loglevel_ERROR)
def clean_sessions(self):
"""\
@@ -422,7 +404,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
connected user on the remote X2go server and terminate them.
"""
- session_infos = self.list_sessions(refresh_cache=True)
+ session_infos = self.list_sessions()
for session_info in session_infos.values():
self.terminate(session_name=session_info)
@@ -452,7 +434,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
@rtype: C{bool}
"""
- session_infos = self.list_sessions(refresh_cache=True)
+ session_infos = self.list_sessions()
if session_name in session_infos.keys():
return session_infos[session_name].is_running()
return False
@@ -466,7 +448,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
@rtype: C{bool}
"""
- session_infos = self.list_sessions(refresh_cache=True)
+ session_infos = self.list_sessions()
if session_name in session_infos.keys():
return session_infos[session_name].is_suspended()
return False
@@ -483,7 +465,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
@rtype: C{bool}
"""
- session_infos = self.list_sessions(refresh_cache=True)
+ session_infos = self.list_sessions()
if session_name not in session_infos.keys():
if session_name in self.terminated_terminals:
diff --git a/x2go/backends/profiles/sessions_file.py b/x2go/backends/profiles/sessions_file.py
index 4d1644b..fe2c457 100644
--- a/x2go/backends/profiles/sessions_file.py
+++ b/x2go/backends/profiles/sessions_file.py
@@ -180,27 +180,6 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
self.write_user_config = True
self.writeIniFile()
- def has_default_profiles(self):
- """\
- STILL UNDOCUMENTED
-
- """
- return self.get_default_profiles() and True or False
-
- def get_default_profiles(self):
- """\
- Find profiles marked as default profiles. If appropriate, default
- profiles may be started immediately on client startup.
-
- """
- _default_profiles = []
- for profile_name in self.profile_names:
- _profile_id = self.to_profile_id(profile_name)
- _profile_config = self.get_profile_config(profile_name)
- if _profile_config['default']:
- _default_profiles.append(_profile_id)
- return _default_profiles
-
def check_profile_id_or_name(self, profile_id_or_name):
"""\
STILL UNDOCUMENTED
diff --git a/x2go/backends/terminal/stdout.py b/x2go/backends/terminal/stdout.py
index 5e0d259..b992f0c 100644
--- a/x2go/backends/terminal/stdout.py
+++ b/x2go/backends/terminal/stdout.py
@@ -44,7 +44,6 @@ import x2go.log as log
import x2go.defaults as defaults
import x2go.utils as utils
import x2go.x2go_exceptions as x2go_exceptions
-import x2go.guardian as guardian
from x2go.cleanup import x2go_cleanup
@@ -212,7 +211,7 @@ class X2goTerminalSessionSTDOUT(object):
self.proxy = None
self.proxy_subprocess = None
- self.guardian_thread = None
+ self.active_threads = []
self.reverse_tunnels = {}
self.print_queue = None
@@ -253,15 +252,10 @@ class X2goTerminalSessionSTDOUT(object):
if self.session_info.name:
self.session_info.local_container = os.path.join(self.params.rootdir, 'S-%s' % self.session_info.name)
else:
- raise X2goSessionException('no valid session info availble')
+ raise X2goTerminalSessionException('no valid session info availble')
else:
self.session_info = info_backend()
- # each terminal session has its own guardian
- self.guardian_thread = guardian.X2goSessionGuardian(self, logger=self.logger)
- self.guardian_thread.start()
-
-
def __del__(self):
self._x2go_tidy_up()
@@ -361,7 +355,7 @@ class X2goTerminalSessionSTDOUT(object):
if _tunnel is not None:
self.reverse_tunnels[self.session_info.name]['snd'] = (self.session_info.snd_port, _tunnel)
_tunnel.start()
- self.guardian_thread.active_threads.append(_tunnel)
+ self.active_threads.append(_tunnel)
else:
# tunnel has already been started and might simply need a resume call
@@ -385,7 +379,7 @@ class X2goTerminalSessionSTDOUT(object):
if _tunnel is not None:
self.reverse_tunnels[self.session_info.name]['sshfs'] = (self.session_info.sshfs_port, _tunnel)
_tunnel.start()
- self.guardian_thread.active_threads.append(_tunnel)
+ self.active_threads.append(_tunnel)
else:
# tunnel has already been started and might simply need a resume call
@@ -430,7 +424,7 @@ class X2goTerminalSessionSTDOUT(object):
logger=self.logger,
)
self.print_queue.start()
- self.guardian_thread.active_threads.append(self.print_queue)
+ self.active_threads.append(self.print_queue)
def set_print_action(self, print_action, **kwargs):
"""\
@@ -464,7 +458,7 @@ class X2goTerminalSessionSTDOUT(object):
"""
if self.session_info.username not in self.control_session._x2go_remote_group('fuse'):
- raise x2go_exceptions.X2goSessionException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
+ raise x2go_exceptions.X2goUserException('remote user %s is not member of X2go server group fuse' % self.session_info.username)
if folder_name is None:
self.logger('no folder name given...', log.loglevel_WARN)
@@ -647,7 +641,7 @@ class X2goTerminalSessionSTDOUT(object):
# set up SSH tunnel for X11 graphical elements
self.proxy = self.proxy_class(session_info=self.session_info, ssh_transport=self.control_session.get_transport(), logger=self.logger)
self.proxy_subprocess = self.proxy.start_proxy()
- self.guardian_thread.active_threads.append(self.proxy)
+ self.active_threads.append(self.proxy)
return self.ok()
diff --git a/x2go/cache.py b/x2go/cache.py
index b1e8e89..647d000 100644
--- a/x2go/cache.py
+++ b/x2go/cache.py
@@ -24,35 +24,34 @@ X2goListSessionCache class - caching X2go session information.
__NAME__ = 'x2gocache-pylib'
# modules
-import gevent
-import threading
import copy
# Python X2go modules
import log
import x2go_exceptions
-class X2goListSessionsCache(threading.Thread):
+class X2goListSessionsCache(object):
"""\
STILL UNDOCUMENTED
"""
+ x2go_listsessions_cache = {}
- def __init__(self, control_session, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, client, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
- @param control: the L{X2goControlSession} that uses this L{X2goListSessionsCache}
- @type control: C{instance}
+ @param client: the L{X2goClient} instance that uses this L{X2goListSessionsCache}
+ @type client: C{instance}
@param refresh_interval: refresh interval of the list sessions cache in seconds
@type refresh_interval: C{int}
- @param logger: you can pass an L{X2goLogger} object to the L{X2goSessionGuardian} constructor
+ @param logger: you can pass an L{X2goLogger} object to the L{X2goListSessionsCache} constructor
@type logger: C{instance}
@param loglevel: if no L{X2goLogger} object has been supplied a new one will be
constructed with the given loglevel
@type loglevel: C{int}
"""
- self.x2go_listsessions_cache = None
- self.last_listsessions_cache = None
+ self.x2go_listsessions_cache = {}
+ self.last_listsessions_cache = {}
if logger is None:
self.logger = log.X2goLogger(loglevel=loglevel)
@@ -60,57 +59,65 @@ class X2goListSessionsCache(threading.Thread):
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- self.control_session = control_session
- self.last_sessionlist = None
+ self.client = client
self.refresh_interval = refresh_interval
- threading.Thread.__init__(self, target=self.refresh_cache)
- self.daemon = True
- def refresh_cache(self):
+ def check_cache(self, seconds=None):
+
+ if seconds and (seconds % self.refresh_interval != 0):
+ return
+
+ for profile_name in self.x2go_listsessions_cache.keys():
+ if profile_name not in [ self.client.to_profile_name(p_id) for p_id in self.client.connected_profiles ]:
+ del self.x2go_listsessions_cache[profile_name]
+
+ def update_all(self, seconds=None):
"""\
- The handler of this L{X2goListSessionsCache} thread.
+ Update L{X2goListSessionsCache} for all connected profiles.
+
+ @param profile_name: name of profile to update
+ @type profile_name: C{str}
"""
- seconds = 0
- self._keepalive = True
- while self._keepalive:
- gevent.sleep(1)
- seconds += 1
- if seconds % self.refresh_interval == 0:
- self.list_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
- self.update_session_list()
-
- def update_session_list(self, session_list=None):
+ if seconds and (seconds % self.refresh_interval != 0):
+ return
+
+ for profile_name in self.client.connected_profiles:
+ self.update(profile_name, seconds=seconds)
+
+ self.check_cache(seconds=seconds)
+
+ def update(self, profile_name, seconds=None):
"""\
- Retrieve a recent session list either from the control session's C{list_sessions()}
- method or as an argument.
+ Update the L{X2goListSessionsCache} for profile C{profile_name}.
- @param session_list: an L{X2goServerSessionList} backend instance
- @type session_list C{instance}
+ @param profile_name: name of profile to update
+ @type profile_name: C{str}
"""
- if session_list is None:
- try:
- self.x2go_listsessions_cache = self.control_session.list_sessions(no_cache=True)
- except x2go_exceptions.X2goSessionException:
- for s in self.control_session.controlled_sessions.values():
- s.__hook_session_has_died()
- s._X2goSession__disconnect()
+ if seconds and (seconds % self.refresh_interval != 0):
+ return
+
+ self.last_listsessions_cache = copy.deepcopy(self.x2go_listsessions_cache)
+ control_session = self.client.client_control_session_of_name(profile_name)
+ if control_session is not None:
+ self.x2go_listsessions_cache[profile_name] = control_session.list_sessions()
else:
- self.x2go_listsessions_cache = session_list
+ del self.x2go_listsessions_cache[profile_name]
- def list_sessions(self):
+ def list_sessions(self, session_uuid):
"""\
Retrieve the current cache content of L{X2goListSessionsCache}.
"""
- return self.x2go_listsessions_cache
+ profile_name = self.client.get_session_profile_name(session_uuid)
+ return self.x2go_listsessions_cache[profile_name]
- def stop_thread(self):
+ def is_cached(self, session_uuid=None, profile_name=None):
"""\
- Stop this L{X2goListSessionsCache} thread.
+ Retrieve the current cache content of L{X2goListSessionsCache}.
"""
- self._keepalive = False
-
-
+ if profile_name is None and session_uuid:
+ profile_name = self.client.get_session_profile_name(session_uuid)
+ return self.x2go_listsessions_cache.has_key(profile_name)
diff --git a/x2go/cleanup.py b/x2go/cleanup.py
index 04949df..a6f3219 100644
--- a/x2go/cleanup.py
+++ b/x2go/cleanup.py
@@ -27,7 +27,7 @@ import guardian
import rforward
-def x2go_cleanup(e=None, terminal_session=None, threads=[]):
+def x2go_cleanup(e=None, threads=None):
"""\
For every Python X2go application you write, please make sure to
capture the KeyboardInterrupt and the SystemExit exceptions and
@@ -49,33 +49,27 @@ def x2go_cleanup(e=None, terminal_session=None, threads=[]):
@param e: if L{x2go_cleanup} got called as we caught an exception this can be the C{Exception} that
we might process at the end of the clean-up (or if clean-up failed or was not appropriate)
@type e: C{exception}
- @param terminal_session: an L{X2goSession} object
- @type terminal_session: C{instance}
@param threads: a list of threads to clean up
@type threads: C{list}
"""
- if terminal_session is None:
- active_threads = threading.enumerate()
+ if threads is None:
+ threads = threading.enumerate()
else:
- terminal_session.logger('cleaning up threads of terminal session: %s' % terminal_session.session_info.name)
- active_threads = threads
+ threads = threads
# stop X2go reverse forwarding tunnels
- for t in active_threads:
+ for t in threads:
if type(t) == rforward.X2goRevFwTunnel:
t.stop_thread()
+ del t
# stop X2go paramiko transports used by X2goTerminalSession objects
- for t in active_threads:
+ for t in threads:
if type(t) == paramiko.Transport:
if hasattr(t, '_x2go_session_marker'):
t.stop_thread()
-
- # stop the X2goGuardian threads (one per X2goSession
- for t in active_threads:
- if type(t) == guardian.X2goSessionGuardian:
- t.stop_thread()
+ del t
if e is not None:
raise e
diff --git a/x2go/client.py b/x2go/client.py
index c1ea7b2..be1ae0e 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -126,6 +126,8 @@ from settings import X2goClientSettings
from printing import X2goClientPrinting
from registry import X2goSessionRegistry
from guardian import X2goSessionGuardian
+from cache import X2goListSessionsCache
+import x2go_exceptions
import log
import utils
@@ -146,7 +148,7 @@ class X2goClient(object):
session object etc.) and connected to it (authentication). For these two steps
use these methods: L{X2goClient.register_session()} and L{X2goClient.connect_session()}.
"""
- def __init__(self, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, use_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
@param logger: you can pass an L{X2goLogger} object to the
L{X2goClient} constructor
@@ -156,6 +158,8 @@ class X2goClient(object):
@type loglevel: C{int}
"""
+ self.listsessions_cache = None
+
if logger is None:
self.logger = log.X2goLogger(loglevel=loglevel)
else:
@@ -166,9 +170,22 @@ class X2goClient(object):
self.session_profiles = X2goSessionProfiles(logger=self.logger)
self.session_registry = X2goSessionRegistry(logger=self.logger)
+ self.session_guardian = X2goSessionGuardian(self, enable_cache=use_cache, logger=self.logger)
+ if use_cache:
+ self.listsessions_cache = X2goListSessionsCache(self, logger=self.logger)
self.client_settings = X2goClientSettings(logger=self.logger)
self.client_printing = X2goClientPrinting(logger=self.logger)
+ self.use_cache = use_cache
+
+ # user hooks for detecting/notifying what happened with this session
+ def HOOK_on_control_session_death(self, profile_name):
+ self.logger('the control session of profile %s has died unexpectedly' % profile_name)
+ def HOOK_on_session_got_suspended_from_within(self, session_uuid):
+ self.logger('session %s has been suspended from within the application' % self.session_registry(session_uuid).get_session_name())
+ def HOOK_on_session_got_terminated_from_within(self, session_uuid):
+ self.logger('session %s has been terminated from within the application' % self.session_registry(session_uuid).get_session_name())
+
def __get_client_username(self):
"""\
Query the local user's username (i.e. the user running the X2go client).
@@ -180,19 +197,6 @@ class X2goClient(object):
return _CURRENT_LOCAL_USER
get_client_username = __get_client_username
- def __is_valid_username(self):
- """\
- Check if user is allowed to start an X2go session on a remote server.
-
- @return User allowed to start a session?
- @rtype: C{str}
-
- """
- return _CURRENT_LOCAL_USER
- get_client_username = __get_client_username
-
-
-
def register_all_session_profiles(self, return_objects=False):
"""\
Register all session profiles found in the C{sessions} configuration file
@@ -328,7 +332,18 @@ class X2goClient(object):
__register_session = register_session
###
- ### WRAPPER METHODS FOR X2goRegisteredSession objects
+ ### WRAPPER METHODS FOR X2goSessionRegistry objects
+ ###
+
+ def get_session_summary(self, session_uuid):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.session_summary(session_uuid)
+
+ ###
+ ### WRAPPER METHODS FOR X2goSession objects
###
def get_session_username(self, session_uuid):
@@ -388,27 +403,6 @@ class X2goClient(object):
with_session = __get_session
"""Alias for L{get_session()}."""
- def get_registered_session(self, session_uuid):
- """\
- Retrieve the complete L{X2goRegisteredSession} object that has been
- registered under the given session registry hash.
-
- L{X2goRegisteredSession} is one of Python X2go's public API classes
- and may safely be used in user applications to operate on individual
- sessions.
-
- @param session_uuid: the X2go session's UUID registry hash
- @type session_uuid: C{str}
-
- @return: the L{X2goRegisteredSession} instance
- @rtype: obj
-
- """
- return self.session_registry(session_uuid)
- __get_registered_session = get_registered_session
- with_registered_session = __get_registered_session
- """Alias for L{get_registered_session()}."""
-
def get_session_name(self, session_uuid):
"""\
Retrieve the server-side X2go session name for the session that has
@@ -853,6 +847,23 @@ class X2goClient(object):
return self.session_registry.registered_sessions
__client_registered_sessions = client_registered_sessions
+ @property
+ def client_control_sessions(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.control_sessions
+ __client_control_sessions = client_control_sessions
+
+ def client_control_session_of_name(self, profile_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.control_session_of_name(profile_name)
+ __client_control_session_of_name = client_control_session_of_name
+
def client_registered_sessions_of_name(self, profile_name):
"""\
STILL UNDOCUMENTED
@@ -890,7 +901,7 @@ class X2goClient(object):
"""
if self._X2goClient__is_session_connected(session_uuid):
- session_list = self._X2goClient__list_sessions(session_uuid, refresh_cache=True)
+ session_list = self._X2goClient__list_sessions(session_uuid)
return [ key for key in session_list.keys() if session_list[key].status == 'R' ]
else:
raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
@@ -919,7 +930,7 @@ class X2goClient(object):
"""
if self._X2goClient__is_session_connected(session_uuid):
- session_list = self._X2goClient__list_sessions(session_uuid, refresh_cache=True)
+ session_list = self._X2goClient__list_sessions(session_uuid)
return [ key for key in session_list.keys() if session_list[key].status == 'S' ]
else:
raise X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
@@ -979,7 +990,18 @@ class X2goClient(object):
"""
session = self.session_registry(session_uuid)
- return session.list_sessions(no_cache=no_cache, refresh_cache=refresh_cache)
+
+ if not self.use_cache or no_cache:
+ return session.list_sessions()
+ elif refresh_cache:
+ self.update_cache_by_session_uuid(session_uuid)
+ return self.listsessions_cache.list_sessions(session_uuid)
+ else:
+ # if there is no cache for this session_uuid available, make sure the cache gets updated
+ # before reading from it...
+ if self.use_cache and (not self.listsessions_cache.is_cached(session_uuid=session_uuid)):
+ self.update_cache_by_session_uuid(session_uuid)
+ return self.listsessions_cache.list_sessions(session_uuid)
__list_sessions = list_sessions
###
@@ -1066,7 +1088,7 @@ class X2goClient(object):
@rtype: C{str}
"""
- return self.session_profiles.get_profile_id(profile_name)
+ return self.session_profiles.to_profile_id(profile_name)
__to_profile_id = to_profile_id
def to_profile_name(self, profile_id):
@@ -1081,7 +1103,61 @@ class X2goClient(object):
@rtype: C{str}
"""
- return self.session_profiles.get_profile_name(profile_id)
+ return self.session_profiles.to_profile_name(profile_id)
__to_profile_name = to_profile_name
+ @property
+ def connected_profiles(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.connected_profiles
+ __connected_profiles = connected_profiles
+
+ def disconnect_profile(self, profile_name):
+ """\
+ Disconnect all L{X2goSession} instances that relate to C{profile_name} by closing down their
+ Paramiko/SSH Transport thread.
+
+ @param profile_name: the X2go session profile name
+ @type session_uuid: C{str}
+ """
+ for s in self.session_registry.registered_sessions_of_name(profile_name):
+ s.disconnect()
+ __disconnect_profile = disconnect_profile
+
+ def update_cache_by_profile(self, profile_name, seconds=None):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ if self.listsessions_cache is not None:
+ try:
+ self.listsessions_cache.update(profile_name, seconds=seconds)
+ except x2go_exceptions.X2goControlSessionException:
+ self.HOOK_on_control_session_death(profile_name)
+ self.disconnect_profile(profile_name, seconds=seconds)
+ __update_cache_by_profile = update_cache_by_profile
+
+ def update_cache_by_session_uuid(self, session_uuid, seconds=None):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ profile_name = self.get_session_profile_name(session_uuid)
+ self.__update_cache_by_profile(profile_name, seconds=seconds)
+ __update_cache_by_session_uuid = update_cache_by_session_uuid
+
+ def update_cache_all_profiles(self, seconds=None):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ if self.listsessions_cache is not None:
+ for profile_id in self.connected_profiles:
+ profile_name = self.to_profile_name(profile_id)
+ self.__update_cache_by_profile(profile_name, seconds=seconds)
+ self.listsessions_cache.check_cache(seconds=seconds)
+ __update_cache_all_profiles = update_cache_all_profiles
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 1a04b5f..5f61493 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -46,7 +46,7 @@ if X2GOCLIENT_OS == "Windows":
SUPPORTED_SOUND = False
SUPPORTED_PRINTING = True
SUPPORTED_FOLDERSHARING = True
- DISPLAY='localhost:0.0'
+ DISPLAY='127.0.0.1:0.0'
os.environ['DISPLAY'] = DISPLAY
elif X2GOCLIENT_OS == "Linux":
@@ -182,7 +182,6 @@ X2GO_SESSIONPROFILE_DEFAULTS = {
'host': None, 'user': None, 'key': None, 'sshport': 22, 'add_to_known_hosts': True,
'rootless': True, 'applications': 'WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL', 'command':'TERMINAL', 'session_type': 'application',
'rdpoptions':None, 'rdpserver':None,
- 'default':False,
'print': True,
'xdmcpserver': 'localhost',
}
diff --git a/x2go/guardian.py b/x2go/guardian.py
index 176c274..0195c73 100644
--- a/x2go/guardian.py
+++ b/x2go/guardian.py
@@ -49,14 +49,7 @@ class X2goSessionGuardian(threading.Thread):
"""
- active_threads = []
- """\
- List of active threads that this L{X2goSessionGuardian} instance will monitor. Whenever
- an L{X2goSession} starts a new sub-thread, it will be appended to this list.
-
- """
-
- def __init__(self, terminal_session, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, client, enable_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
@param terminal_session: the L{X2goTerminalSession} that is controlled by this L{X2goSessionGuardian}
@type terminal_session: C{instance}
@@ -67,17 +60,17 @@ class X2goSessionGuardian(threading.Thread):
@type loglevel: C{int}
"""
- self.active_threads = []
-
if logger is None:
self.logger = log.X2goLogger(loglevel=loglevel)
else:
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- self.terminal_session = terminal_session
+ self.client = client
+ self.enable_cache = enable_cache
threading.Thread.__init__(self, target=self.guardian)
self.daemon = True
+ self.start()
def guardian(self):
"""\
@@ -91,11 +84,15 @@ class X2goSessionGuardian(threading.Thread):
while not _sigterm_received and self._keepalive:
gevent.sleep(1)
seconds += 1
+ if self.enable_cache:
+ self.client.update_cache_all_profiles(seconds)
self.logger('X2go session guardian thread waking up after %s seconds' % seconds, loglevel=log.loglevel_DEBUG)
- self.logger('calling terminal session cleanup for terminal session: %s' % self.terminal_session.session_info.name, loglevel=log.loglevel_DEBUG)
- x2go_cleanup(terminal_session=self.terminal_session, threads=self.active_threads)
+ for session_uuid in self.client.session_registry.keys():
+ session_summary = self.client.get_session_summary(session_uuid)
+ self.logger('calling session cleanup on profile %s for terminal session: %s' % (session_summary['profile_name'], session_summary['session_name']), loglevel=log.loglevel_DEBUG)
+ x2go_cleanup(threads=session_summary['active_threads'])
def stop_thread(self):
"""\
diff --git a/x2go/registry.py b/x2go/registry.py
index ec6587c..95f25e3 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -46,7 +46,7 @@ class X2goSessionRegistry(object):
STILL UNDOCUMENTED
"""
- def __init__(self, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, use_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
STILL UNDOCUMENTED
@@ -88,6 +88,34 @@ class X2goSessionRegistry(object):
"""
return self(session_uuid).profile.profile_name
+ def session_summary(self, session_uuid):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ _session_summary = {}
+ _session_summary['uuid'] = session_uuid
+ _session_summary['profile_id'] = self.get_profile_id(session_uuid)
+ _session_summary['profile_name'] = self.get_profile_name(session_uuid)
+ _session_summary['session_name'] = self(session_uuid).get_session_name()
+ _session_summary['control_session'] = self(session_uuid).get_control_session()
+ _session_summary['control_params'] = self(session_uuid).control_params
+ _session_summary['terminal_session'] = self(session_uuid).get_terminal_session()
+ _session_summary['terminal_params'] = self(session_uuid).terminal_params
+ _session_summary['active_threads'] = self(session_uuid).get_terminal_session().active_threads
+ _session_summary['connected'] = self(session_uuid).connected
+ _session_summary['running'] = self(session_uuid).running
+ _session_summary['suspended'] = self(session_uuid).suspended
+ _session_summary['terminated'] = self(session_uuid).terminated
+ _session_summary['backends'] = {
+ 'control': self(session_uuid)._control_backend,
+ 'terminal': self(session_uuid)._terminal_backend,
+ 'info': self(session_uuid)._info_backend,
+ 'list': self(session_uuid)._list_backend,
+ 'proxy': self(session_uuid)._proxy_backend,
+ }
+ return _session_summary
+
def register(self, server, profile_id, profile_name,
control_backend=X2goControlSession,
terminal_backend=X2goTerminalSession,
@@ -101,7 +129,7 @@ class X2goSessionRegistry(object):
control_session = self.control_sessions[profile_id]
s = session.X2goSession(server=server, control_session=control_session,
- profile_id=profile_id, profile_name=profile_name,
+ profile_id=profile_id, profile_name=profile_name,
control_backend=control_backend,
terminal_backend=terminal_backend,
info_backend=info_backend,
@@ -131,6 +159,14 @@ class X2goSessionRegistry(object):
return self._sessionsWithState('connected')
@property
+ def connected_sessions(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self._sessionsWithState('connected')
+
+ @property
def running_sessions(self):
"""\
STILL UNDOCUMENTED
@@ -206,3 +242,29 @@ class X2goSessionRegistry(object):
"""
return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+
+ def control_session_of_name(self, profile_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ if self.registered_sessions_of_name(profile_name):
+ session = self.registered_sessions_of_name(profile_name)[0]
+ return session.control_session
+ return None
+
+ @property
+ def connected_control_sessions(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return [ c for c in self.control_sessions.values() if c.is_connected() ]
+
+ @property
+ def connected_profiles(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return [ p for p in self.control_sessions.keys() if self.control_sessions[p].is_connected() ]
diff --git a/x2go/session.py b/x2go/session.py
index 2c6129f..42018fc 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -54,15 +54,7 @@ _X2GO_SESSION_PARAMS = ('geometry', 'depth', 'link', 'pack',
class X2goSession(object):
- # user hooks for detecting/notifying what happened with this session
- def __hook_session_has_died(self):
- self.logger('the control session of session %s has unexpectedly died' % self.get_session_name())
- def __hook_session_suspended(self):
- self.logger('session %s has been suspended from within the application' % self.get_session_name())
- def __hook_session_terminated(self):
- self.logger('session %s has been terminated from within the application' % self.get_session_name())
-
- def __init__(self, server, control_session=None,
+ def __init__(self, server=None, control_session=None,
profile_id=None, profile_name=None,
printing=None, share_local_folders=[],
control_backend=X2goControlSession,
@@ -123,29 +115,36 @@ class X2goSession(object):
info_backend=info_backend,
list_backend=list_backend,
proxy_backend=proxy_backend,
- controlled_session=self,
logger=logger)
else:
self.control_session = control_session
- self.control_session.controlled_sessions[self.get_uuid()] = self
self.terminal_session = None
- self.guardian_thread = None
self.logger('starting X2goSession', loglevel=log.loglevel_DEBUG)
if known_hosts:
self.control_session.load_host_keys(known_hosts)
def __str__(self):
return self.__get_uuid()
+
def __repr__(self):
result = 'X2goSession('
for p in dir(self):
if '__' in p or not p in self.__dict__ or type(p) is types.InstanceType: continue
result += p + '=' + str(self.__dict__[p]) + ', '
return result + ')'
+
def __call__(self):
return self.__get_uuid()
+ # user hooks for detecting/notifying what happened with this session
+ def HOOK_session_has_died(self):
+ self.logger('the control session of session %s has unexpectedly died' % self.get_session_name())
+ def HOOK_session_suspended(self):
+ self.logger('session %s has been suspended from within the application' % self.get_session_name())
+ def HOOK_session_terminated(self):
+ self.logger('session %s has been terminated from within the application' % self.get_session_name())
+
def get_uuid(self):
"""\
STILL UNDOCUMENTED
@@ -320,10 +319,10 @@ class X2goSession(object):
self._X2goSession__disconnect()
__clean_sessions = clean_sessions
- def list_sessions(self, no_cache=False, refresh_cache=False):
- if (no_cache or refresh_cache) and not self.is_alive():
+ def list_sessions(self):
+ if not self.is_alive():
self._X2goSession__disconnect()
- return self.control_session.list_sessions(no_cache=no_cache, refresh_cache=refresh_cache)
+ return self.control_session.list_sessions()
__list_sessions = list_sessions
def resume(self, session_name=None):
@@ -337,8 +336,8 @@ class X2goSession(object):
"""
if self.is_alive():
_control = self.control_session
- _terminal = _control.resume(session_name=session_name, logger=self.logger, **self.terminal_params)
- self.guardian_thread = _terminal.guardian_thread
+ _terminal = _control.resume(session_name=session_name,
+ logger=self.logger, **self.terminal_params)
self.terminal_session = _terminal
if _terminal is not None:
diff --git a/x2go/utils.py b/x2go/utils.py
index bee7149..58c4c7a 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -203,7 +203,6 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
'rdpoptions',
'rdpserver',
'xdmcpserver',
- 'default',
]
for i in _ignored_options:
del _params[i]
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index 950a0c7..3b4e396 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -39,8 +39,9 @@ SSHException = paramiko.SSHException
class _X2goException(exceptions.BaseException): pass
class X2goClientException(_X2goException): pass
-class X2goSessionException(_X2goException): pass
-class X2goSessionException(_X2goException): pass
+class X2goControlSessionException(_X2goException): pass
+class X2goTerminalSessionException(_X2goException): pass
+class X2goSessionCacheException(_X2goException): pass
class X2goUserException(_X2goException): pass
class X2goProfileException(_X2goException): pass
class X2goSettingsException(_X2goException): pass
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