[X2Go-Commits] python-x2go.git - release/0.4.0.x (branch) updated: c4b70151df3b4f2572f1d9dc1699f29b072016b7
X2Go dev team
git-admin at x2go.org
Tue Jan 7 16:16:07 CET 2014
The branch, release/0.4.0.x has been updated
via c4b70151df3b4f2572f1d9dc1699f29b072016b7 (commit)
from f630352d855595d4aae0c03842ef7a5bd418209d (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 | 97 ++++++++---
x2go/backends/info/_stdout.py | 13 ++
x2go/backends/profiles/_file.py | 14 +-
x2go/backends/terminal/_stdout.py | 35 ++--
x2go/cache.py | 41 ++---
x2go/client.py | 292 ++++++++++++++++++++++-----------
x2go/defaults.py | 13 +-
x2go/guardian.py | 35 ++--
x2go/inifiles.py | 2 +-
x2go/registry.py | 323 ++++++++++++++++++++++++++++++-------
x2go/session.py | 270 +++++++++++++++++++++++++++----
x2go/utils.py | 12 +-
x2go/x2go_exceptions.py | 2 +
13 files changed, 880 insertions(+), 269 deletions(-)
The diff of changes is:
diff --git a/x2go/backends/control/_stdout.py b/x2go/backends/control/_stdout.py
index 3377ff6..4e67d88 100644
--- a/x2go/backends/control/_stdout.py
+++ b/x2go/backends/control/_stdout.py
@@ -50,8 +50,12 @@ def _rerewrite_blanks(cmd):
cmd = cmd.replace("X2GO_SPACE_CHAR", " ")
return cmd
-def _rewrite_password(cmd, password):
+def _rewrite_password(cmd, user=None, password=None):
+ # if there is a ,,-u X2GO_USER'' parameter in RDP options then we will replace
+ # it by our X2go session password
+ if cmd and user:
+ cmd = cmd.replace('X2GO_USER', user)
# if there is a ,,-p X2GO_PASSWORD'' parameter in RDP options then we will replace
# it by our X2go session password
if cmd and password:
@@ -94,11 +98,15 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
self.terminated_terminals = []
self.profile_name = profile_name
+ self.hostname = None
+ self.port = None
self._session_auth_rsakey = None
self._remote_home = None
self._remote_group = {}
+ self.locked = False
+
if logger is None:
self.logger = log.X2goLogger(loglevel=loglevel)
else:
@@ -140,6 +148,12 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
def _x2go_exec_command(self, cmd_line, loglevel=log.loglevel_INFO, **kwargs):
+ while self.locked:
+ gevent.sleep(.1)
+
+ self.locked = True
+ _retval = None
+
if type(cmd_line) == types.ListType:
cmd = " ".join(cmd_line)
else:
@@ -150,7 +164,8 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
timeout.start()
try:
self.logger('executing command on X2go server: %s' % _rerewrite_blanks(cmd), loglevel)
- return self.exec_command(_rewrite_password(cmd, self._session_password), **kwargs)
+ _retval = self.exec_command(_rewrite_password(cmd, user=self.get_transport().get_username(), password=self._session_password), **kwargs)
+ self.locked = False
except AttributeError:
raise x2go_exceptions.X2goControlSessionException('the X2go control session has died unexpectedly')
except EOFError:
@@ -158,11 +173,13 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
except gevent.timeout.Timeout:
raise x2go_exceptions.X2goControlSessionException('the X2go control session command timed out')
finally:
+ self.locked = False
timeout.cancel()
else:
+ self.locked = False
raise x2go_exceptions.X2goControlSessionException('the X2go control session is not connected')
- return None
+ return _retval
@property
def _x2go_remote_home(self):
@@ -293,6 +310,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
else:
raise paramiko.AuthenticationException()
+ self.hostname = hostname
+ self.port = port
+
# if we succeed, we immediately grab us an sFTP client session
self.sftp_client = self.open_sftp()
@@ -306,12 +326,23 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
return (self.get_transport() is not None)
+ def dissociate(self, terminal_session):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ for t_name in self.associated_terminals.keys():
+ if self.associated_terminals[t_name] == terminal_session:
+ del self.associated_terminals[t_name]
+ if self.terminated_terminals.has_key(t_name):
+ del self.terminated_terminals[t_name]
+
def disconnect(self):
"""\
STILL UNDOCUMENTED
"""
- if self.associated_terminals is not None:
+ if self.associated_terminals:
t_names = self.associated_terminals.keys()
for t_obj in self.associated_terminals.values():
try:
@@ -320,9 +351,12 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
pass
except x2go_exceptions.X2goControlSessionException:
pass
- del t_obj
+ t_obj.__del__()
for t_name in t_names:
- del self.associated_terminals[t_name]
+ try:
+ del self.associated_terminals[t_name]
+ except KeyError:
+ pass
self._remote_home = None
self._remote_group = {}
@@ -426,10 +460,28 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
else:
- (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
+ # this _success loop will catch errors in case the x2golistsessions output is corrupt
+ # this should not be needed and is a workaround for the current X2go server implementation
+ _success = False
+ while not _success:
- _stdout_read = stdout.read()
- _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
+ (stdin, stdout, stderr) = self._x2go_exec_command("x2golistsessions")
+
+ _stdout_read = stdout.read()
+
+ try:
+ _listsessions = self._list_backend(_stdout_read, info_backend=self._info_backend).sessions
+ _success = True
+ except:
+ gevent.sleep(1)
+
+ # update internal variables when list_sessions() is called
+ for _session_name, _session_info in self.associated_terminals.items():
+ if _session_name not in _listsessions.keys():
+ del self.associated_terminals[_session_name]
+ self.terminated_terminals.append(_session_name)
+ elif _session_info.is_suspended():
+ del self.associated_terminals[_session_name]
return _listsessions
@@ -439,9 +491,9 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
connected user on the remote X2go server and terminate them.
"""
- session_infos = self.list_sessions()
- for session_info in session_infos.values():
- self.terminate(session_name=session_info)
+ session_list = self.list_sessions()
+ for session_name in session_list.keys():
+ self.terminate(session_name=session_name)
def is_connected(self):
"""\
@@ -469,7 +521,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
session_infos = self.list_sessions()
if session_name in session_infos.keys():
return session_infos[session_name].is_running()
- return False
+ return None
def is_suspended(self, session_name):
"""\
@@ -483,7 +535,7 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
session_infos = self.list_sessions()
if session_name in session_infos.keys():
return session_infos[session_name].is_suspended()
- return False
+ return None
def has_terminated(self, session_name):
"""\
@@ -533,8 +585,10 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
(stdin, stdout, stderr) = self._x2go_exec_command("x2gosuspend-session %s" % session_name, loglevel=log.loglevel_DEBUG)
dummy_stdout = stdout.read()
dummy_stderr = stderr.read()
- self.associated_terminals[session_name].__del__()
- del self.associated_terminals[session_name]
+ if self.associated_terminals.has_key(session_name):
+ if self.associated_terminals[session_name] is not None:
+ self.associated_terminals[session_name].__del__()
+ del self.associated_terminals[session_name]
_ret = True
else:
@@ -567,19 +621,20 @@ class X2goControlSessionSTDOUT(paramiko.SSHClient):
_session_names = [ t.get_session_name() for t in self.associated_terminals.values() ]
if session_name in _session_names:
- self.logger('suspending associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
+ self.logger('terminating associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
(stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
dummy_stdout = stdout.read()
dummy_stderr = stderr.read()
- if self.associated_terminals[session_name] is not None:
- self.associated_terminals[session_name].__del__()
- del self.associated_terminals[session_name]
+ if self.associated_terminals.has_key(session_name):
+ if self.associated_terminals[session_name] is not None:
+ self.associated_terminals[session_name].__del__()
+ del self.associated_terminals[session_name]
self.terminated_terminals.append(session_name)
_ret = True
else:
- self.logger('suspending non-associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
+ self.logger('terminating non-associated session: %s' % session_name, loglevel=log.loglevel_DEBUG)
(stdin, stdout, stderr) = self._x2go_exec_command("x2goterminate-session %s" % session_name, loglevel=log.loglevel_DEBUG)
dummy_stdout = stdout.read()
dummy_stderr = stderr.read()
diff --git a/x2go/backends/info/_stdout.py b/x2go/backends/info/_stdout.py
index a35f9b0..9abbdd1 100644
--- a/x2go/backends/info/_stdout.py
+++ b/x2go/backends/info/_stdout.py
@@ -66,11 +66,13 @@ class X2goServerSessionInfoSTDOUT(object):
print 'Encountered IndexError: %s' % str(e)
print 'THIS SHOULD NOT HAPPEN... HERE IS THE x2golistsessions OUTPUT THAT CAUSED THE ERROR...'
print x2go_output
+ raise e
except ValueError, e:
# DEBUGGING CODE
print 'Encountered IndexError: %s' % str(e)
print 'THIS SHOULD NOT HAPPEN... HERE IS THE x2golistsessions OUTPUT THAT CAUSED THE ERROR...'
print x2go_output
+ raise e
def is_running(self):
@@ -173,4 +175,15 @@ class X2goServerSessionListSTDOUT(object):
s_info._parse_x2golistsessions_line(line)
self.sessions[s_info.name] = s_info
+ def __call__(self):
+ return self.sessions
+ def get_session_info(self, session_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ try:
+ return self.sessions[session_name]
+ except KeyError:
+ return None
diff --git a/x2go/backends/profiles/_file.py b/x2go/backends/profiles/_file.py
index c9a1888..0c109af 100644
--- a/x2go/backends/profiles/_file.py
+++ b/x2go/backends/profiles/_file.py
@@ -125,6 +125,13 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
_profile_config[option] = self.get(_profile_id, option, key_type=self.get_profile_option_type(option))
return _profile_config
+ def default_profile_config(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return copy.deepcopy(self.defaultSessionProfile)
+
def has_profile(self, profile_id_or_name):
try:
_profile_id = self.check_profile_id_or_name(profile_id_or_name)
@@ -201,14 +208,15 @@ class X2goSessionProfilesFILE(inifiles.X2goIniFile):
return profile_id
- def delete_profile(self, profile_id):
+ def delete_profile(self, profile_id_or_name):
"""\
STILL UNDOCUMENTED
"""
- self.iniConfig.remove_section(profile_id)
+ _profile_id = self.check_profile_id_or_name(profile_id_or_name)
+ self.iniConfig.remove_section(_profile_id)
self.write_user_config = True
- self.writeIniFile()
+ self.write()
def check_profile_id_or_name(self, profile_id_or_name):
"""\
diff --git a/x2go/backends/terminal/_stdout.py b/x2go/backends/terminal/_stdout.py
index 91821d2..ce2e9e3 100644
--- a/x2go/backends/terminal/_stdout.py
+++ b/x2go/backends/terminal/_stdout.py
@@ -299,13 +299,16 @@ class X2goTerminalSessionSTDOUT(object):
def _x2go_tidy_up(self):
if self.proxy is not None:
- self.proxy.__del__()
+ self.release_proxy()
try:
if self.control_session.get_transport() is not None:
- for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
- if _tunnel is not None:
- _tunnel.__del__()
+ try:
+ for _tunnel in [ _tun[1] for _tun in self.reverse_tunnels[self.session_info.name].values() ]:
+ if _tunnel is not None:
+ _tunnel.__del__()
+ except KeyError:
+ pass
if self.print_queue is not None:
self.print_queue.__del__()
@@ -737,11 +740,8 @@ class X2goTerminalSessionSTDOUT(object):
@rtype: bool
"""
- self.logger('suspending terminal session: %s' % self.session_info, log.loglevel_DEBUG)
- (stdin, stdout, stderr) = self.control_session._x2go_exec_command("x2gosuspend-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
- dummy_stdout = stdout.read()
- dummy_stderr = stderr.read()
- self.proxy.__del__()
+ self.control_session.suspend(session_name=self.session_info.name)
+ self.release_proxy()
# TODO: check if session has really suspended
_ret = True
@@ -756,13 +756,20 @@ class X2goTerminalSessionSTDOUT(object):
@rtype: bool
"""
- self.logger('terminating terminal session: %s' % self.session_info, log.loglevel_INFO)
- (stdin, stdout, stderr) = self.control_session._x2go_exec_command("x2goterminate-session %s" % self.session_info, loglevel=log.loglevel_DEBUG)
- dummy_stdout = stdout.read()
- dummy_stderr = stderr.read()
- self.proxy.__del__()
+ self.control_session.terminate(session_name=self.session_info.name)
+ self.release_proxy()
# TODO: check if session has really suspended
_ret = True
return _ret
+
+ def release_proxy(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ try:
+ self.proxy.__del__()
+ except:
+ pass
diff --git a/x2go/cache.py b/x2go/cache.py
index 2dc78cc..e0b4dfd 100644
--- a/x2go/cache.py
+++ b/x2go/cache.py
@@ -38,12 +38,10 @@ class X2goListSessionsCache(object):
"""
x2go_listsessions_cache = {}
- def __init__(self, client, refresh_interval=5, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, client_instance, logger=None, loglevel=log.loglevel_DEFAULT):
"""\
@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{X2goListSessionsCache} constructor
@type logger: C{instance}
@param loglevel: if no L{X2goLogger} object has been supplied a new one will be
@@ -60,49 +58,34 @@ class X2goListSessionsCache(object):
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- self.client = client
- self.refresh_interval = refresh_interval
+ self.client_instance = client_instance
- def check_cache(self, seconds=None):
-
- if seconds and (seconds % self.refresh_interval != 0):
- return
+ def check_cache(self):
for profile_name in self.x2go_listsessions_cache.keys():
- if profile_name not in self.client.connected_profiles(return_profile_names=True):
+ if profile_name not in self.client_instance.connected_profiles(return_profile_names=True):
del self.x2go_listsessions_cache[profile_name]
- def update_all(self, seconds=None):
+ def update_all(self):
"""\
Update L{X2goListSessionsCache} for all connected profiles.
- @param seconds: time since control session is up
- @type seconds: C{int}
-
"""
- if seconds and (seconds % self.refresh_interval != 0):
- return
+ for profile_name in self.client_instance.connected_profiles(return_profile_names=True):
+ self.update(profile_name)
- for profile_name in self.client.connected_profiles(return_profile_names=True):
- self.update(profile_name, seconds=seconds)
+ self.check_cache()
- self.check_cache(seconds=seconds)
-
- def update(self, profile_name, seconds=None):
+ def update(self, profile_name):
"""\
Update the L{X2goListSessionsCache} for profile C{profile_name}.
@param profile_name: name of profile to update
@type profile_name: C{str}
- @param seconds: time since control session is up
- @type seconds: C{int}
"""
- 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)
+ control_session = self.client_instance.client_control_session_of_profile_name(profile_name)
try:
self.x2go_listsessions_cache[profile_name] = control_session.list_sessions()
except x2go_exceptions.X2goControlSessionException, e:
@@ -117,7 +100,7 @@ class X2goListSessionsCache(object):
Retrieve the current cache content of L{X2goListSessionsCache}.
"""
- profile_name = self.client.get_session_profile_name(session_uuid)
+ profile_name = self.client_instance.get_session_profile_name(session_uuid)
if self.is_cached(session_uuid=session_uuid):
return self.x2go_listsessions_cache[profile_name]
else:
@@ -129,5 +112,5 @@ class X2goListSessionsCache(object):
"""
if profile_name is None and session_uuid:
- profile_name = self.client.get_session_profile_name(session_uuid)
+ profile_name = self.client_instance.get_session_profile_name(session_uuid)
return self.x2go_listsessions_cache.has_key(profile_name)
diff --git a/x2go/client.py b/x2go/client.py
index bacd3ab..56c909f 100644
--- a/x2go/client.py
+++ b/x2go/client.py
@@ -174,7 +174,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, use_cache=True, start_xserver=False,
+ def __init__(self,
control_backend=control.X2goControlSession,
terminal_backend=terminal.X2goTerminalSession,
info_backend=info.X2goServerSessionInfo,
@@ -186,6 +186,12 @@ class X2goClient(object):
client_rootdir=None,
sessions_rootdir=None,
ssh_rootdir=None,
+ start_xserver=False,
+ use_listsessions_cache=False,
+ auto_update_listsessions_cache=False,
+ auto_update_sessionregistry=False,
+ auto_register_sessions=False,
+ refresh_interval=5,
logger=None, loglevel=log.loglevel_DEFAULT):
"""\
@param logger: you can pass an L{X2goLogger} object to the
@@ -253,28 +259,40 @@ class X2goClient(object):
# presume the running XServer listens on :0
os.environ.update({'DISPLAY': 'localhost:0'})
- self.session_registry = X2goSessionRegistry(logger=self.logger)
- self.session_guardian = X2goSessionGuardian(self, enable_cache=use_cache, logger=self.logger)
- if use_cache:
+ self.session_registry = X2goSessionRegistry(self, logger=self.logger)
+ self.session_guardian = X2goSessionGuardian(self, auto_update_listsessions_cache=auto_update_listsessions_cache & use_listsessions_cache,
+ auto_update_sessionregistry=auto_update_sessionregistry,
+ auto_register_sessions=auto_register_sessions,
+ refresh_interval=refresh_interval,
+ logger=self.logger
+ )
+ if use_listsessions_cache:
self.listsessions_cache = X2goListSessionsCache(self, logger=self.logger)
- self.use_cache = use_cache
+ self.use_listsessions_cache = use_listsessions_cache
# user hooks for detecting/notifying what happened during application runtime
def HOOK_no_known_xserver_found(self):
self.logger('the Python X2go module could not find any usable XServer application, you will not be able to start X2go sessions without XServer', loglevel=log.loglevel_WARN)
def HOOK_open_print_dialog(self, filename, profile_name='UNKNOWN', session_name='UNKNOWN'):
- self.logger('incoming print job,, %s'' detected by X2goClient hook method' % filename, loglevel=log.loglevel_WARN)
+ self.logger('HOOK_open_print_dialog: incoming print job,, %s'' detected by X2goClient hook method' % filename, loglevel=log.loglevel_WARN)
def HOOK_on_control_session_death(self, profile_name):
- self.logger('the control session of profile %s has died unexpectedly' % profile_name, loglevel=log.loglevel_WARN)
- 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(), loglevel=log.loglevel_WARN)
- 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(), loglevel=log.loglevel_WARN)
+ self.logger('HOOK_on_control_session_death: the control session of profile %s has died unexpectedly' % profile_name, loglevel=log.loglevel_WARN)
+
+ def HOOK_on_session_has_started_by_me(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_started_by_me (session_uuid: %s, profile_name: %s): a new session %s has been started by this application' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+ def HOOK_on_session_has_started_by_other(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_started (session_uuid: %s, profile_name: %s): a new session %s has started been started by other application' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+ def HOOK_on_session_has_resumed_by_me(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_resumed_by_me (session_uuid: %s, profile_name: %s): suspended session %s has been resumed by this application' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+ def HOOK_on_session_has_resumed_by_other(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_resumed_by_other (session_uuid: %s, profile_name: %s): suspended session %s has been resumed by other application' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+ def HOOK_on_session_has_been_suspended(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_been_suspended (session_uuid: %s, profile_name: %s): session %s has been suspended' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
+ def HOOK_on_session_has_terminated(self, session_uuid='UNKNOWN', profile_name='UNKNOWN', session_name='UNKNOWN'):
+ self.logger('HOOK_on_session_has_terminated (session_uuid: %s, profile_name: %s): session %s has terminated' % (session_uuid, profile_name, session_name), loglevel=log.loglevel_NOTICE)
def _detect_backend_classes(self):
-
-
# CONTROL session backend
if type(self.control_backend) is types.StringType:
try:
@@ -413,7 +431,7 @@ class X2goClient(object):
sessions[_obj.get_profile_name()] = _obj
return sessions
- def register_session(self, server=None, profile_id=None, profile_name=None,
+ def register_session(self, server=None, profile_id=None, profile_name=None, session_name=None,
printing=False, share_local_folders=[], return_object=False,
force=False, **kwargs):
"""\
@@ -479,20 +497,6 @@ class X2goClient(object):
_profile_id = self.session_profiles.check_profile_id_or_name(_p)
_profile_name = self.session_profiles.to_profile_name(_profile_id)
-
- # detect if we are re-registering a session profile that is already been initialized
- # by register_all_session_profiles
- _profile_siblings = self.session_registry.registered_sessions_of_name(_profile_name)
- if (not force) and (len(_profile_siblings) == 1) and not _profile_siblings[0].has_terminal_session():
-
- session_uuid = _profile_siblings[0].get_uuid()
- self.logger('using already initially-registered-by-profile session %s' % session_uuid, log.loglevel_NOTICE, tag=self._logger_tag)
-
- if return_object:
- return self.session_registry(session_uuid)
- else:
- return session_uuid
-
_params = self.session_profiles.to_session_params(_profile_id)
del _params['profile_name']
@@ -517,6 +521,7 @@ class X2goClient(object):
session_uuid = self.session_registry.register(server=server,
profile_id=_profile_id, profile_name=_profile_name,
+ session_name=session_name,
control_backend=self.control_backend,
terminal_backend=self.terminal_backend,
info_backend=self.info_backend,
@@ -527,6 +532,7 @@ class X2goClient(object):
client_rootdir=self.client_rootdir,
sessions_rootdir=self.sessions_rootdir,
ssh_rootdir=self.ssh_rootdir,
+ keep_controlsession_alive=True,
**_params)
self.logger('initializing X2go session...', log.loglevel_NOTICE, tag=self._logger_tag)
@@ -566,7 +572,7 @@ class X2goClient(object):
return self.session_registry(session_uuid).get_username()
__get_session_username = get_session_username
- def get_session_server(self, session_uuid):
+ def get_session_server_peername(self, session_uuid):
"""\
After a session has been set up you can query the
hostname of the host the session is connected to (or
@@ -580,8 +586,8 @@ class X2goClient(object):
@rtype: tuple
"""
- return self.session_registry(session_uuid).get_server()
- __get_session_server = get_session_server
+ return self.session_registry(session_uuid).get_server_peername()
+ __get_session_server_peername = get_session_server_peername
def get_session(self, session_uuid):
"""\
@@ -653,8 +659,8 @@ class X2goClient(object):
@rtype: C{bool}
"""
- return self.session_registry(session_uuid).connect(username=username, password=password,
- add_to_known_hosts=add_to_known_hosts,
+ return self.session_registry(session_uuid).connect(username=username, password=password,
+ add_to_known_hosts=add_to_known_hosts,
force_password_auth=force_password_auth,
)
__connect_session = connect_session
@@ -667,7 +673,7 @@ class X2goClient(object):
@type session_uuid: C{str}
"""
self.session_registry(session_uuid).disconnect()
- if self.use_cache:
+ if self.use_listsessions_cache:
self.__update_cache_all_profiles()
__disconnect_session = disconnect_session
@@ -727,7 +733,7 @@ class X2goClient(object):
return self.session_registry(session_uuid).start()
__start_session = start_session
- def resume_session(self, session_uuid, session_name):
+ def resume_session(self, session_uuid=None, session_name=None):
"""\
Resume or continue a suspended / running X2go session on a
remote X2go server (as specified when L{register_session} was
@@ -742,7 +748,15 @@ class X2goClient(object):
@rtype: C{bool}
"""
- return self.session_registry(session_uuid).resume(session_name)
+ if session_uuid is None and session_name is None:
+ raise x2go_exceptions.X2goClientException('can\'t resume a session without either session_uuid or session_name')
+ if session_name is None and self.session_registry(session_uuid).session_name is None:
+ raise x2go_exceptions.X2goClientException('don\'t know which session to resume')
+ if session_uuid is None:
+ session_uuid = self.session_registry.get_session_of_session_name(session_name=session_name, return_object=False)
+ return self.session_registry(session_uuid).resume()
+ else:
+ return self.session_registry(session_uuid).resume(session_name=session_name)
__resume_session = resume_session
def suspend_session(self, session_uuid, session_name=None):
@@ -775,7 +789,7 @@ class X2goClient(object):
if session_name is None:
return self.session_registry(session_uuid).suspend()
else:
- for session in self.session_registry.running_sessions:
+ for session in self.session_registry.running_sessions():
if session_name == session.get_session_name():
return session.suspend()
return self.session_registry(session_uuid).control_session.suspend(session_name=session_name)
@@ -814,7 +828,7 @@ class X2goClient(object):
if session_name is None:
return self.session_registry(session_uuid).terminate()
else:
- for session in self.session_registry.running_sessions + self.session_registry.suspended_sessions:
+ for session in self.session_registry.running_sessions() + self.session_registry.suspended_sessions():
if session_name == session.get_session_name():
return session.terminate()
return self.session_registry(session_uuid).control_session.terminate(session_name=session_name)
@@ -979,21 +993,7 @@ class X2goClient(object):
STILL UNDOCUMENTED
"""
- if return_objects:
- return [ obj for obj in self.session_registry.connected_sessions ]
- if return_profile_names:
- return [ obj.get_profile_name() for obj in self.session_registry.connected_sessions ]
- return [ obj() for obj in self.session_registry.connected_sessions ]
- __client_connected_sessions = client_connected_sessions
-
- def client_connected_sessions_of_name(self, profile_name, return_objects=False):
- """\
- STILL UNDOCUMENTED
-
- """
- if return_objects:
- return [ s for s in self.session_registry.connected_sessions if s.get_profile_name() == profile_name ]
- return [ s.get_uuid() for s in self.session_registry.connected_sessions if s.get_profile_name() == profile_name ]
+ return self.session_registry.connected_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
__client_connected_sessions = client_connected_sessions
@property
@@ -1010,11 +1010,7 @@ class X2goClient(object):
STILL UNDOCUMENTED
"""
- if return_objects:
- return [ obj for obj in self.session_registry.running_sessions ]
- if return_profile_names:
- return [ obj.get_profile_name() for obj in self.session_registry.running_sessions ]
- return [ obj.get_uuid() for obj in self.session_registry.running_sessions ]
+ return self.session_registry.running_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
__client_running_sessions = client_running_sessions
@property
@@ -1031,11 +1027,7 @@ class X2goClient(object):
STILL UNDOCUMENTED
"""
- if return_objects:
- return [ obj for obj in self.session_registry.suspended_sessions ]
- if return_profile_names:
- return [ obj.get_profile_name() for obj in self.session_registry.suspended_sessions ]
- return [ obj.get_uuid() for obj in self.session_registry.suspended_sessions ]
+ return self.session_registry.running_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
__client_suspended_sessions = client_suspended_sessions
@property
@@ -1048,12 +1040,12 @@ class X2goClient(object):
__client_has_suspended_sessions = client_has_suspended_sessions
@property
- def client_registered_sessions(self):
+ def client_registered_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self.session_registry.registered_sessions
+ return self.session_registry.registered_sessions(return_objects=return_objects, return_profile_names=return_profile_names)
__client_registered_sessions = client_registered_sessions
@property
@@ -1065,21 +1057,45 @@ class X2goClient(object):
return self.session_registry.control_sessions
__client_control_sessions = client_control_sessions
- def client_control_session_of_name(self, profile_name):
+ def client_control_session_of_profile_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
+ return self.session_registry.control_session_of_profile_name(profile_name)
+ __client_control_session_of_profile_name = client_control_session_of_profile_name
- def client_registered_sessions_of_name(self, profile_name):
+ def client_registered_session_of_name(self, session_name, return_object=False):
"""\
STILL UNDOCUMENTED
"""
- return self.session_registry.registered_sessions_of_name(profile_name)
- __client_registered_sessions_of_name = client_registered_sessions_of_name
+ return self.session_registry.get_session_of_session_name(session_name, return_object=return_object)
+ __client_registered_session_of_name = client_registered_session_of_name
+
+ def client_has_registered_session_of_name(self, session_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.client_registered_session_of_name(session_name) is not None
+ __client_has_registered_session_of_name = client_registered_session_of_name
+
+ def client_registered_sessions_of_profile_name(self, profile_name, return_objects=False):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.registered_sessions_of_profile_name(profile_name, return_objects=return_objects)
+ __client_registered_sessions_of_profile_name = client_registered_sessions_of_profile_name
+
+ def client_connected_sessions_of_profile_name(self, profile_name, return_objects=False):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.session_registry.connected_sessions_of_profile_name(profile_name, return_objects=return_objects)
+ __client_connected_sessions = client_connected_sessions
###
### Provide access to the X2go server's sessions DB
@@ -1129,7 +1145,7 @@ class X2goClient(object):
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)
+ raise x2go_exceptions.X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
__server_running_sessions = server_running_sessions
@property
@@ -1158,7 +1174,7 @@ class X2goClient(object):
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)
+ raise x2go_exceptions.X2goClientException('X2go session with UUID %s is not connected' % session_uuid)
__server_suspended_sessions = server_suspended_sessions
@property
@@ -1199,7 +1215,11 @@ class X2goClient(object):
session.clean_sessions()
__clean_sessions = clean_sessions
- def list_sessions(self, session_uuid, no_cache=False, refresh_cache=False):
+ def list_sessions(self, session_uuid=None,
+ profile_name=None, profile_id=None,
+ no_cache=False, refresh_cache=False,
+ update_sessionregistry=True,
+ register_sessions=False):
"""\
Use the X2go session registered under C{session_uuid} to
retrieve a list of running or suspended X2go sessions on the
@@ -1214,19 +1234,45 @@ class X2goClient(object):
@type session_uuid: C{str}
"""
- session = self.session_registry(session_uuid)
+ if profile_id is not None:
+ profile_name = self.to_profile_name(profile_id)
+
+ if profile_name is not None:
+
+ _connected_sessions = self.client_connected_sessions_of_profile_name(profile_name, return_objects=True)
+ if _connected_sessions:
+ # it does not really matter which session to use for getting a server-side session list
+ # thus, we simply grab the first that comes in...
+ session_uuid = _connected_sessions[0].get_uuid()
+ else:
+ raise x2go_exceptions.X2goClientException('profile ,,%s\'\' is not connected' % profile_name)
- if not self.use_cache or no_cache:
- return session.list_sessions()
+ elif session_uuid is not None:
+ pass
+ else:
+ raise x2go_exceptions.X2goClientException('must either specify session UUID or profile name')
+
+ if not self.use_listsessions_cache or no_cache:
+ _session_list = self.session_registry(session_uuid).list_sessions()
elif refresh_cache:
self.update_cache_by_session_uuid(session_uuid)
- return self.listsessions_cache.list_sessions(session_uuid)
+ _session_list = 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)):
+ if self.use_listsessions_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)
+ _session_list = self.listsessions_cache.list_sessions(session_uuid)
+
+ if update_sessionregistry:
+ self.session_registry.update_status(profile_name=self.get_session_profile_name(session_uuid), session_list=_session_list)
+
+ if register_sessions:
+ self.session_registry.register_available_server_sessions(profile_name=self.get_session_profile_name(session_uuid),
+ session_list=_session_list,
+ update_sessionregistry=False)
+
+ return _session_list
__list_sessions = list_sessions
###
@@ -1363,43 +1409,109 @@ class X2goClient(object):
@param profile_name: the X2go session profile name
@type profile_name: C{str}
"""
- for s in self.session_registry.registered_sessions_of_name(profile_name):
+ for s in self.session_registry.registered_sessions_of_profile_name(profile_name, return_objects=True):
s.disconnect()
- if self.use_cache:
+ if self.use_listsessions_cache:
self.__update_cache_all_profiles()
__disconnect_profile = disconnect_profile
- def update_cache_by_profile(self, profile_name, seconds=None):
+ def update_sessionregistry_status_by_profile_name(self, profile_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ session_uuids = self.client_registered_sessions_of_profile_name(profile_name)
+ if session_uuids:
+ session_list = self.list_sessions(session_uuids[0],
+ update_sessionregistry=False,
+ register_sessions=False,
+ )
+ self.session_registry.update_status(profile_name=profile_name, session_list=session_list)
+ __update_sessionregistry_status_by_profile_name = update_sessionregistry_status_by_profile_name
+
+
+ def update_sessionregistry_status_by_session_uuid(self, session_uuid):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ session_list = self.list_sessions(session_uuid, update_sessionregistry=False, register_sessions=False)
+ if session_list:
+ self.session_registry.update_status(session_uuid=session_uuid, session_list=session_list)
+ __update_sessionregistry_status_by_session_uuid = update_sessionregistry_status_by_session_uuid
+
+ def update_sessionregistry_status_all_profiles(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ for profile_name in self.connected_profiles(return_profile_names=True):
+ self.__update_sessionregistry_status_by_profile_name(profile_name)
+ __update_sessionregistry_status_all_profiles = update_sessionregistry_status_all_profiles
+
+
+ def update_cache_by_profile_name(self, profile_name):
"""\
STILL UNDOCUMENTED
"""
if self.listsessions_cache is not None:
try:
- self.listsessions_cache.update(profile_name, seconds=seconds)
+ self.listsessions_cache.update(profile_name)
except x2go_exceptions.X2goControlSessionException:
self.HOOK_on_control_session_death(profile_name)
self.disconnect_profile(profile_name)
return False
- __update_cache_by_profile = update_cache_by_profile
+ __update_cache_by_profile_name = update_cache_by_profile_name
- def update_cache_by_session_uuid(self, session_uuid, seconds=None):
+ def update_cache_by_session_uuid(self, session_uuid):
"""\
STILL UNDOCUMENTED
"""
profile_name = self.get_session_profile_name(session_uuid)
- self.__update_cache_by_profile(profile_name, seconds=seconds)
+ self.__update_cache_by_profile_name(profile_name)
__update_cache_by_session_uuid = update_cache_by_session_uuid
- def update_cache_all_profiles(self, seconds=None):
+ def update_cache_all_profiles(self):
"""\
STILL UNDOCUMENTED
"""
if self.listsessions_cache is not None:
for profile_name in self.connected_profiles(return_profile_names=True):
- self.__update_cache_by_profile(profile_name, seconds=seconds)
+ self.__update_cache_by_profile_name(profile_name)
- self.listsessions_cache.check_cache(seconds=seconds)
+ self.listsessions_cache.check_cache()
__update_cache_all_profiles = update_cache_all_profiles
+
+ def register_available_server_sessions_by_profile_name(self, profile_name):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ for profile_name in self.connected_profiles(return_profile_names=True):
+ session_list = self.list_sessions(profile_name=profile_name,
+ update_sessionregistry=False,
+ register_sessions=False,
+ )
+ self.session_registry.register_available_server_sessions(profile_name, session_list=session_list)
+ __register_available_server_sessions_by_profile_name = register_available_server_sessions_by_profile_name
+
+ def register_available_server_sessions_by_session_uuid(self, session_uuid):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ profile_name = self.get_session_profile_name(session_uuid)
+ self.__register_available_server_sessions_by_profile_name(profile_name)
+ __register_available_server_sessions_by_session_uuid = register_available_server_sessions_by_session_uuid
+
+ def register_available_server_sessions_all_profiles(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ for profile_name in self.connected_profiles(return_profile_names=True):
+ self.__register_available_server_sessions_by_profile_name(profile_name)
+ __register_available_server_sessions_all_profiles = register_available_server_sessions_all_profiles
diff --git a/x2go/defaults.py b/x2go/defaults.py
index 69cbbbc..dd90ee2 100644
--- a/x2go/defaults.py
+++ b/x2go/defaults.py
@@ -234,17 +234,18 @@ else:
X2GO_SESSIONPROFILE_DEFAULTS = {
'speed': 2, 'pack': '16m-jpeg', 'quality': 9, 'link':'ADSL',
'iconvto': 'UTF-8', 'iconvfrom': 'ISO-8859-15', 'useiconv': False,
+ 'usesshproxy': False, 'sshproxy': '',
'fstunnel': True,
'export': '',
'fullscreen': False,
'width': 800,'height': 600,'dpi': 96,'setdpi': False,
'usekbd':True, 'layout': 'us', 'type': 'pc105/us',
- 'sound':False, 'soundsystem': 'pulse', 'startsoundsystem': True, 'soundtunnel':True, 'defsndport':True, 'sndport':4713,
- 'name': None, 'icon': ':icons/128x128/x2gosession.png',
- '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,
- 'print': True,
+ 'sound':False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713,
+ 'name': '', 'icon': ':icons/128x128/x2gosession.png',
+ 'host': '', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22,
+ 'rootless': True, 'applications': 'WWWBROWSER, MAILCLIENT, OFFICE, TERMINAL', 'command':'TERMINAL',
+ 'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '',
+ 'print': False,
'xdmcpserver': 'localhost',
}
"""L{X2goSessionProfiles} default values to fill a new session profile with."""
diff --git a/x2go/guardian.py b/x2go/guardian.py
index 27b11f4..f55dd4f 100644
--- a/x2go/guardian.py
+++ b/x2go/guardian.py
@@ -50,7 +50,12 @@ class X2goSessionGuardian(threading.Thread):
"""
- def __init__(self, client, enable_cache=True, logger=None, loglevel=log.loglevel_DEFAULT):
+ def __init__(self, client_instance,
+ auto_update_listsessions_cache=False,
+ auto_update_sessionregistry=False,
+ auto_register_sessions=False,
+ refresh_interval=5,
+ logger=None, loglevel=log.loglevel_DEFAULT):
"""\
@param enable_cache: let L{X2goSessionGuardian} refresh the session list cache for all L{X2goSession} objects
@type enable_cache: C{bool}
@@ -67,8 +72,12 @@ class X2goSessionGuardian(threading.Thread):
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- self.client = client
- self.enable_cache = enable_cache
+ self.client_instance = client_instance
+ self.auto_update_listsessions_cache = auto_update_listsessions_cache
+ self.auto_update_sessionregistry = auto_update_sessionregistry
+ self.auto_register_sessions = auto_register_sessions
+ self.refresh_interval = refresh_interval
+
threading.Thread.__init__(self, target=self.guardian)
self.daemon = True
self.start()
@@ -86,19 +95,21 @@ class X2goSessionGuardian(threading.Thread):
gevent.sleep(1)
seconds += 1
- if seconds % 5 == 0:
- # if no cache is used the next command acts like a ping a each session
- # if any of the connected servers is dead an X2goClient.disconnect_profile()
- # call will be executed on the respective session profile.
- self.client.all_servers_are_alive()
+ if seconds % self.refresh_interval == 0:
+
+ if self.auto_update_listsessions_cache:
+ self.client_instance.update_cache_all_profiles()
+
+ if self.auto_update_sessionregistry:
+ self.client_instance.update_sessionregistry_status_all_profiles()
- if self.enable_cache:
- self.client.update_cache_all_profiles(seconds=seconds)
+ if self.auto_register_sessions:
+ self.client_instance.register_available_server_sessions_all_profiles()
self.logger('X2go session guardian thread waking up after %s seconds' % seconds, loglevel=log.loglevel_DEBUG)
- for session_uuid in self.client.session_registry.keys():
- session_summary = self.client.get_session_summary(session_uuid)
+ for session_uuid in self.client_instance.session_registry.keys():
+ session_summary = self.client_instance.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'])
diff --git a/x2go/inifiles.py b/x2go/inifiles.py
index 7762005..88ca068 100644
--- a/x2go/inifiles.py
+++ b/x2go/inifiles.py
@@ -183,7 +183,7 @@ class X2goIniFile(object):
fd = open(self.user_config_file, 'wb')
self.iniConfig.write(fd)
fd.close()
- self.write_config = False
+ self.write_user_config = False
def get_type(self, section, key):
"""\
diff --git a/x2go/registry.py b/x2go/registry.py
index 66f6af3..53f934f 100644
--- a/x2go/registry.py
+++ b/x2go/registry.py
@@ -54,7 +54,7 @@ class X2goSessionRegistry(object):
STILL UNDOCUMENTED
"""
- def __init__(self, use_cache=True,
+ def __init__(self, client_instance,
logger=None, loglevel=log.loglevel_DEFAULT):
"""\
STILL UNDOCUMENTED
@@ -66,6 +66,8 @@ class X2goSessionRegistry(object):
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
+ self.client_instance = client_instance
+
self.registry = {}
self.control_sessions = {}
@@ -88,44 +90,158 @@ class X2goSessionRegistry(object):
STILL UNDOCUMENTED
"""
- return self(session_uid).profile.profile_id
+ return self(session_uuid).get_profile_id()
def get_profile_name(self, session_uuid):
"""\
STILL UNDOCUMENTED
"""
- return self(session_uuid).profile.profile_name
+ return self(session_uuid).get_profile_name()
- def session_summary(self, session_uuid):
+ def session_summary(self, session_uuid, status_only=False):
"""\
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,
- }
+ _r = False
+ if session_uuid in [ s() for s in self.registered_sessions() ]:
+ _r = True
+
+ if not status_only:
+ _session_summary['uuid'] = _r and session_uuid or None
+ _session_summary['profile_id'] = _r and self.get_profile_id(session_uuid) or ''
+ _session_summary['profile_name'] = _r and self.get_profile_name(session_uuid) or ''
+ _session_summary['session_name'] = _r and self(session_uuid).get_session_name() or ''
+ _session_summary['control_session'] = _r and self(session_uuid).get_control_session() or None
+ _session_summary['control_params'] = _r and self(session_uuid).control_params or {}
+ _session_summary['terminal_session'] = _r and self(session_uuid).get_terminal_session() or None
+ _session_summary['terminal_params'] = _r and self(session_uuid).terminal_params or {}
+ _session_summary['active_threads'] = _r and self(session_uuid).get_terminal_session().active_threads or []
+ _session_summary['backends'] = {
+ 'control': _r and self(session_uuid)._control_backend or None,
+ 'terminal': _r and self(session_uuid)._terminal_backend or None,
+ 'info': _r and self(session_uuid)._info_backend or None,
+ 'list': _r and self(session_uuid)._list_backend or None,
+ 'proxy': _r and self(session_uuid)._proxy_backend or None,
+ }
+
+ if _r:
+ _session_summary['virgin'] = self(session_uuid).virgin
+ _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
+ else:
+ _session_summary['virgin'] = None
+ _session_summary['connected'] = None
+ _session_summary['running'] = None
+ _session_summary['suspended'] = None
+ _session_summary['terminated'] = None
return _session_summary
- def register(self, server, profile_id, profile_name,
+ def update_status(self, session_uuid=None, profile_name=None, profile_id=None, session_list=None):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ if session_uuid and profile_name or session_uuid and profile_id or profile_name and profile_id:
+ raise X2goSessionRegistryException('only one of the possible method parameters is allowed (session_uuid, profile_name or profile_id)')
+ elif session_uuid is None and profile_name is None and profile_id is None:
+ raise X2goSessionRegistryException('at least one of the method parameters session_uuid, profile_name or profile_id must be given')
+
+ if session_uuid:
+ session_uuids = [ session_uuid ]
+ elif profile_name:
+ session_uuids = [ s() for s in self.registered_sessions_of_profile_name(profile_name, return_objects=True) ]
+ elif profile_id:
+ session_uuids = [ s() for s in self.registered_sessions_of_profile_name(self.client_instance.to_profile_name(profile_id), return_objects=True) ]
+
+ for _session_uuid in session_uuids:
+ self(_session_uuid).update_status(session_list=session_list)
+ _last_status = copy.deepcopy(self(_session_uuid)._last_status)
+ _current_status = copy.deepcopy(self(_session_uuid)._current_status)
+
+ # at this point we hook into the X2goClient instance and call notification methods
+ # that can be used to inform an application that something has happened
+
+ _profile_name = self(_session_uuid).get_profile_name()
+ _session_name = self(_session_uuid).get_session_name()
+
+ if _last_status['running'] == False and _current_status['running'] == True:
+ # session has started
+ if self(_session_uuid).has_terminal_session():
+ if _last_status['suspended']:
+ # from a suspended state
+ self.client_instance.HOOK_on_session_has_resumed_by_me(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ else:
+ # as a new session
+ self.client_instance.HOOK_on_session_has_started_by_me(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ else:
+ if _last_status['suspended']:
+ # from a suspended state
+ self.client_instance.HOOK_on_session_has_resumed_by_other(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ else:
+ # as a new session
+ self.client_instance.HOOK_on_session_has_started_by_other(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ elif _last_status['suspended'] == False and _current_status['suspended'] == True:
+ # session has been suspended
+ self(_session_uuid).session_cleanup()
+ self.client_instance.HOOK_on_session_has_been_suspended(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ elif _last_status['terminated'] == False and _current_status['terminated'] == True:
+ # session has terminated
+ self.client_instance.HOOK_on_session_has_terminated(session_uuid=_session_uuid, profile_name=_profile_name, session_name=_session_name)
+ self(_session_uuid).session_cleanup()
+ self(_session_uuid).__del__()
+ if len(self.virgin_sessions_of_profile_name(profile_name)) > 1:
+ del self.registry[_session_uuid]
+
+ def register_available_server_sessions(self, profile_name, session_list=None):
+
+ _connected_sessions = self.connected_sessions_of_profile_name(profile_name=profile_name, return_objects=False)
+ _registered_sessions = self.registered_sessions_of_profile_name(profile_name=profile_name, return_objects=False)
+ _session_names = [ self(s_uuid).session_name for s_uuid in _registered_sessions if self(s_uuid).session_name is not None ]
+
+ if _connected_sessions:
+ # any of the connected sessions is valuable for accessing the profile's control
+ # session commands, so we simply take the first that comes in...
+ _ctrl_session = self(_connected_sessions[0])
+ if session_list is None:
+ session_list = _ctrl_session.list_sessions()
+ for session_name in session_list.keys():
+ if session_name not in _session_names:
+ server = _ctrl_session.get_server_hostname()
+ profile_id = _ctrl_session.get_profile_id()
+
+ # reconstruct all session options of _ctrl_session to auto-register a suspended session
+ # found on the _ctrl_session's connected server
+ _pre_kwargs = _ctrl_session.__dict__
+ kwargs = {}
+ kwargs.update(_pre_kwargs['terminal_params'])
+ kwargs.update(_pre_kwargs['control_params'])
+ kwargs['control_backend'] = _pre_kwargs['_control_backend']
+ kwargs['terminal_backend'] = _pre_kwargs['_terminal_backend']
+ kwargs['proxy_backend'] = _pre_kwargs['_proxy_backend']
+ kwargs['info_backend'] = _pre_kwargs['_info_backend']
+ kwargs['list_backend'] = _pre_kwargs['_list_backend']
+ kwargs['settings_backend'] = _pre_kwargs['_settings_backend']
+ kwargs['printing_backend'] = _pre_kwargs['_printing_backend']
+ kwargs['keep_controlsession_alive'] = _pre_kwargs['keep_controlsession_alive']
+ kwargs['client_rootdir'] = _pre_kwargs['client_rootdir']
+ kwargs['sessions_rootdir'] = _pre_kwargs['sessions_rootdir']
+
+ # this if clause catches problems when x2golistsessions commands give weird results
+ if not self.has_session_of_session_name(session_name):
+ self.register(server, profile_id, profile_name,
+ session_name=session_name,
+ virgin=False, running=False, suspended=True, terminated=None,
+ **kwargs
+ )
+ self.update_status(profile_name=profile_name, session_list=session_list)
+
+ def register(self, server, profile_id, profile_name,
+ session_name=None,
control_backend=_X2goControlSession,
terminal_backend=_X2goTerminalSession,
info_backend=_X2goServerSessionInfo,
@@ -136,14 +252,36 @@ class X2goSessionRegistry(object):
client_rootdir=os.path.join(_LOCAL_HOME,_X2GO_CLIENT_ROOTDIR),
sessions_rootdir=os.path.join(_LOCAL_HOME,_X2GO_SESSIONS_ROOTDIR),
ssh_rootdir=os.path.join(_LOCAL_HOME,_X2GO_SSH_ROOTDIR),
+ keep_controlsession_alive=True,
**kwargs):
+ """\
+ STILL UNDOCUMENTED
+ """
control_session = None
if profile_id in self.control_sessions.keys():
control_session = self.control_sessions[profile_id]
+ # when starting a new session, we will try to use unused registered virgin sessions
+ # depending on your application layout, there shoul either be one or no such virgin session at all
+ _virgin_sessions = self.virgin_sessions_of_profile_name(profile_name, return_objects=True)
+ if _virgin_sessions and not session_name:
+
+ session_uuid = _virgin_sessions[0].get_uuid()
+ self.logger('using already initially-registered yet-unused session %s' % session_uuid, log.loglevel_NOTICE)
+ return session_uuid
+
+ try:
+ _retval = self.get_session_of_session_name(session_name)
+ self.logger('using already registered-by-session-name session %s' % session_uuid, log.loglevel_NOTICE)
+ return _retval
+ except X2goSessionException:
+ # no registered session for session_name found... FINE, go ahead!
+ pass
+
s = session.X2goSession(server=server, control_session=control_session,
profile_id=profile_id, profile_name=profile_name,
+ session_name=session_name,
control_backend=control_backend,
terminal_backend=terminal_backend,
info_backend=info_backend,
@@ -154,6 +292,7 @@ class X2goSessionRegistry(object):
client_rootdir=client_rootdir,
sessions_rootdir=sessions_rootdir,
ssh_rootdir=ssh_rootdir,
+ keep_controlsession_alive=keep_controlsession_alive,
logger=self.logger, **kwargs)
session_uuid = s._X2goSession__get_uuid()
@@ -166,48 +305,81 @@ class X2goSessionRegistry(object):
return session_uuid
- def _sessionsWithState(self, state):
- return [ ts for ts in self.registry.values() if eval('ts.%s' % state) ]
+ def has_session_of_session_name(self, session_name):
+ """\
+ STILL UNDOCUMENTED
- @property
- def connected_sessions(self):
+ """
+ try:
+ _dummy = self.get_session_of_session_name(session_name)
+ return True
+ except X2goSessionException:
+ return False
+
+ def get_session_of_session_name(self, session_name, return_object=False):
"""\
STILL UNDOCUMENTED
"""
- return self._sessionsWithState('connected')
+ found_sessions = [ s for s in self.registered_sessions() if s.session_name == session_name and s.session_name is not None ]
+ if len(found_sessions) == 1:
+ session = found_sessions[0]
+ if return_object:
+ return session
+ else:
+ return session.get_uuid()
+ elif len(found_sessions) > 1:
+ raise X2goSessionRegistryException('there should only be one registered session of name ,,%s\'\'' % session_name)
+ else:
+ raise X2goSessionException('no session of name ,,%s\'\' registered' % session_name)
+
+ def _sessionsWithState(self, state, return_objects=True, return_profile_names=False):
+ sessions = [ ts for ts in self.registry.values() if eval('ts.%s' % state) ]
+ if return_objects:
+ return sessions
+ elif return_profile_names:
+ profile_names = []
+ for session in sessions:
+ if session.profile_name not in profile_names:
+ profile_names.append(session.profile_name)
+ return profile_names
+ else:
+ return [s.get_uuid() for s in sessions ]
- @property
- def connected_sessions(self):
+ def connected_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self._sessionsWithState('connected')
+ return self._sessionsWithState('connected', return_objects=return_objects, return_profile_names=return_profile_names)
- @property
- def running_sessions(self):
+ def virgin_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self._sessionsWithState('running')
+ return self._sessionsWithState('virgin', return_objects=return_objects, return_profile_names=return_profile_names)
- @property
- def suspended_sessions(self):
+ def running_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self._sessionsWithState('suspended')
+ return self._sessionsWithState('running', return_objects=return_objects, return_profile_names=return_profile_names)
- @property
- def terminated_sessions(self):
+ def suspended_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self._sessionsWithState('terminated')
+ return self._sessionsWithState('suspended', return_objects=return_objects, return_profile_names=return_profile_names)
+
+ def terminated_sessions(self, return_objects=True, return_profile_names=False):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self._sessionsWithState('terminated', return_objects=return_objects, return_profile_names=return_profile_names)
@property
def has_running_sessions(self):
@@ -215,7 +387,7 @@ class X2goSessionRegistry(object):
STILL UNDOCUMENTED
"""
- return self.running_sessions and len(self.running_sessions) > 0
+ return self.running_sessions() and len(self.running_sessions()) > 0
@property
def has_suspended_sessions(self):
@@ -225,13 +397,21 @@ class X2goSessionRegistry(object):
"""
return self.suspended_sessions and len(self.suspended_sessions) > 0
- @property
- def registered_sessions(self):
+ def registered_sessions(self, return_objects=True, return_profile_names=False):
"""\
STILL UNDOCUMENTED
"""
- return self.registry.values()
+ if return_objects:
+ return self.registry.values()
+ elif return_profile_names:
+ profile_names = []
+ for session in self.registry.values():
+ if session.profile_name not in profile_names:
+ profile_names.append(profile_name)
+ return profile_names
+ else:
+ return self.registry.keys()
@property
def non_running_sessions(self):
@@ -239,36 +419,65 @@ class X2goSessionRegistry(object):
STILL UNDOCUMENTED
"""
- return [ s for s in self.registry.values() if s not in self.running_sessions ]
+ return [ s for s in self.registry.values() if s not in self.running_sessions() ]
+
+ def connected_sessions_of_profile_name(self, profile_name, return_objects=False):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ if return_objects:
+ return self.connected_sessions() and [ s for s in self.connected_sessions() if s.profile_name == profile_name ]
+ else:
+ return self.connected_sessions() and [ s.get_uuid() for s in self.connected_sessions() if s.profile_name == profile_name ]
- def registered_sessions_of_name(self, profile_name):
+ def registered_sessions_of_profile_name(self, profile_name, return_objects=False):
"""\
STILL UNDOCUMENTED
"""
- return self.registered_sessions and [ s for s in self.registered_sessions if s.profile_name == profile_name ]
- def running_sessions_of_name(self, profile_name):
+ if return_objects:
+ return self.registered_sessions() and [ s for s in self.registered_sessions() if s.profile_name == profile_name ]
+ else:
+ return self.registered_sessions() and [ s.get_uuid() for s in self.registered_sessions() if s.profile_name == profile_name ]
+
+ def virgin_sessions_of_profile_name(self, profile_name, return_objects=False):
+
+ if return_objects:
+ return self.virgin_sessions() and [ s for s in self.virgin_sessions() if s.profile_name == profile_name ]
+ else:
+ return self.virgin_sessions() and [ s.get_uuid() for s in self.virgin_sessions() if s.profile_name == profile_name ]
+
+
+ def running_sessions_of_profile_name(self, profile_name, return_objects=False):
"""\
STILL UNDOCUMENTED
"""
- return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+ if return_objects:
+ return self.running_sessions() and [ s for s in self.running_sessions() if s.profile_name == profile_name ]
+ else:
+ return self.running_sessions() and [ s.get_uuid() for s in self.running_sessions() if s.profile_name == profile_name ]
- def suspended_sessions_of_name(self, profile_name):
+ def suspended_sessions_of_profile_name(self, profile_name, return_objects=False):
"""\
STILL UNDOCUMENTED
- """
- return self.running_sessions and [ s for s in self.running_sessions if s.profile_name == profile_name ]
+ """
+ if return_objects:
+ return self.suspended_sessions() and [ s for s in self.suspended_sessions() if s.profile_name == profile_name ]
+ else:
+ return self.suspended_sessions() and [ s.get_uuid() for s in self.suspended_sessions() if s.profile_name == profile_name ]
- def control_session_of_name(self, profile_name):
+ def control_session_of_profile_name(self, profile_name):
"""\
STILL UNDOCUMENTED
"""
- if self.registered_sessions_of_name(profile_name):
- session = self.registered_sessions_of_name(profile_name)[0]
+ _sessions = self.registered_sessions_of_profile_name(profile_name, return_objects=True)
+ if _sessions:
+ session = _sessions[0]
return session.control_session
return None
diff --git a/x2go/session.py b/x2go/session.py
index 08248a0..bab60b0 100644
--- a/x2go/session.py
+++ b/x2go/session.py
@@ -68,6 +68,7 @@ class X2goSession(object):
def __init__(self, server=None, control_session=None,
profile_id=None, profile_name='UNKNOWN',
+ session_name=None,
printing=None, share_local_folders=[],
control_backend=_X2goControlSession,
terminal_backend=_X2goTerminalSession,
@@ -80,7 +81,9 @@ class X2goSession(object):
sessions_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SESSIONS_ROOTDIR),
ssh_rootdir=os.path.join(_LOCAL_HOME, _X2GO_SSH_ROOTDIR),
known_hosts=None,
+ keep_controlsession_alive=False,
logger=None, loglevel=log.loglevel_DEFAULT,
+ virgin=True, running=None, suspended=None, terminated=None,
**params):
if logger is None:
@@ -89,16 +92,29 @@ class X2goSession(object):
self.logger = copy.deepcopy(logger)
self.logger.tag = __NAME__
- self._keep_alive = True
+ self._keep = None
self.uuid = uuid.uuid1()
self.connected = False
- self.running = False
- self.suspended = False
- self.terminated = False
+
+ self.virgin = virgin
+ self.running = running
+ self.suspended = suspended
+ self.terminated = terminated
+ self.keep_controlsession_alive = keep_controlsession_alive
+
+ self._current_status = {
+ 'virgin': self.virgin,
+ 'connected': self.connected,
+ 'running': self.running,
+ 'suspended': self.suspended,
+ 'terminated': self.terminated,
+ }
+ self._last_status = None
self.profile_id = profile_id
self.profile_name = profile_name
+ self.session_name = session_name
self.server = server
self.printing = printing
self.share_local_folders = share_local_folders
@@ -158,6 +174,7 @@ class X2goSession(object):
if known_hosts:
self.control_session.load_host_keys(known_hosts)
+
def __str__(self):
return self.__get_uuid()
@@ -171,6 +188,38 @@ class X2goSession(object):
def __call__(self):
return self.__get_uuid()
+ def __del__(self):
+
+ if self.has_control_session() and self.has_terminal_session():
+ self.get_control_session().dissociate(self.get_terminal_session())
+
+ if self.has_control_session():
+ if self.keep_controlsession_alive:
+ # regenerate this session instance for re-usage if this is the last session for a certain session profile
+ # and keep_controlsession_alive is set to True...
+ self.virgin = True
+ self.connected = self.is_connected()
+ self.running = None
+ self.suspended = None
+ self.terminated = None
+ self._current_status = {
+ 'virgin': self.virgin,
+ 'connected': self.connected,
+ 'running': self.running,
+ 'suspended': self.suspended,
+ 'terminated': self.terminated,
+ }
+ self._last_status = None
+ self.session_name = None
+
+ else:
+ self.get_control_session().__del__()
+ self.control_session = None
+
+ if self.has_terminal_session():
+ self.get_terminal_session().__del__()
+ self.terminal_session = None
+
def get_uuid(self):
"""\
STILL UNDOCUMENTED
@@ -210,19 +259,39 @@ class X2goSession(object):
return self.control_session._session_password
__get_password = get_password
- def get_server(self):
+ def get_server_peername(self):
"""\
After a session has been setup up you can query the
hostname of the host the sessions is connected to (or
about to connect to).
- @return: the hostname of the server the X2go session is
+ @return: the address of the server the X2go session is
connected to (as an C{(addr,port)} tuple)
- @rtype: tuple
+ @rtype: C{tuple}
"""
return self.control_session.get_transport().getpeername()
- __get_server = get_server
+ __get_server_peername = get_server_peername
+
+ def get_server_hostname(self):
+ """\
+ @return: the hostname of the server the X2go session is
+ connected to
+ @rtype: C{str}
+
+ """
+ return self.control_session.hostname
+ __get_server_hostname = get_server_hostname
+
+ def get_server_port(self):
+ """\
+ @return: the server-side TCP port that is used by the X2go session to
+ connect the session
+ @rtype: C{str}
+
+ """
+ return self.control_session.port
+ __get_server_port = get_server_port
def get_session_name(self):
"""\
@@ -233,8 +302,7 @@ class X2goSession(object):
@rtype: C{str}
"""
- if self.terminal_session is not None:
- return self.terminal_session.get_session_name() or None
+ return self.session_name
__get_session_name = get_session_name
def get_session_cmd(self):
@@ -255,6 +323,14 @@ class X2goSession(object):
return self.control_session
__get_control_session = get_control_session
+ def has_control_session(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ return self.control_session is not None
+ __has_control_session = has_control_session
+
def get_terminal_session(self):
"""\
STILL UNDOCUMENTED
@@ -314,11 +390,11 @@ class X2goSession(object):
STILL UNDOCUMENTED
"""
- self.connected = False
- self.running = False
- self.suspended = False
- self.terminated = False
self.control_session.disconnect()
+ self.connected = False
+ self.running = None
+ self.suspended = None
+ self.terminated = None
__disconnect = disconnect
def set_print_action(self, print_action, **kwargs):
@@ -332,13 +408,21 @@ class X2goSession(object):
__set_print_action = set_print_action
def is_alive(self):
- _alive = self.control_session.is_alive()
- if not _alive:
- self.disconnect()
- return _alive
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ self.connected = self.control_session.is_alive()
+ if not self.connected:
+ self._X2goSession__disconnect()
+ return self.connected
__is_alive = is_alive
def clean_sessions(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
if self.is_alive():
self.control_session.clean_sessions()
else:
@@ -346,11 +430,53 @@ class X2goSession(object):
__clean_sessions = clean_sessions
def list_sessions(self):
+ """\
+ STILL UNDOCUMENTED
+
+ """
if not self.is_alive():
self._X2goSession__disconnect()
return self.control_session.list_sessions()
__list_sessions = list_sessions
+ def update_status(self, session_list=None):
+ """\
+ STILL UNDOCUMENTED
+
+ """
+ self._last_status = copy.deepcopy(self._current_status)
+ if session_list is None:
+ try:
+ session_list = self.control_session.list_sessions()
+ self.connected = True
+ except X2goControlSessionException:
+ self.connected = False
+ self.running = None
+ self.suspended = None
+ self.terminated = None
+ try:
+ _session_info = session_list[self.get_session_name()]
+ self.running = _session_info.is_running()
+ self.suspended = _session_info.is_suspended()
+ if not self.virgin:
+ self.terminated = not (_session_info.is_running() or _session_info.is_suspended())
+ else:
+ self.terminated = None
+ except KeyError:
+ self.running = False
+ self.suspended = False
+ if not self.virgin:
+ self.terminated = True
+
+ self._current_status = {
+ 'virgin': self.virgin,
+ 'connected': self.connected,
+ 'running': self.running,
+ 'suspended': self.suspended,
+ 'terminated': self.terminated,
+ }
+ __update_status = update_status
+
def resume(self, session_name=None):
"""\
Resume or continue a suspended / running X2go session on the
@@ -360,11 +486,22 @@ class X2goSession(object):
@type session_name: C{str}
"""
+ _new_session = False
+ if self.session_name is None:
+ self.session_name = session_name
+
if self.is_alive():
_control = self.control_session
- _terminal = _control.resume(session_name=session_name,
+ _terminal = _control.resume(session_name=self.session_name,
logger=self.logger, **self.terminal_params)
self.terminal_session = _terminal
+
+ if self.session_name is None:
+ _new_session = True
+ self.session_name = self.terminal_session.session_info.name
+
+ print 'STARTING SESSION: %s' % self.session_name
+
if _terminal is not None:
if SUPPORTED_SOUND and _terminal.params.snd_system is not 'none':
@@ -385,9 +522,10 @@ class X2goSession(object):
_terminal.share_local_folder(_folder)
# only run the session startup command if we do not resume...
- if session_name is None:
- _terminal.run_command()
+ if _new_session:
+ self.terminal_session.run_command()
+ self.virgin = False
self.suspended = False
self.running = True
self.terminated = False
@@ -404,6 +542,7 @@ class X2goSession(object):
Start a new X2go session on the remote X2go server.
"""
+ self.session_name = None
self.resume()
__start = start
@@ -420,11 +559,27 @@ class X2goSession(object):
"""
if self.is_alive():
- if self.terminal_session.suspend():
+ if self.has_terminal_session():
+ if self.terminal_session.suspend():
+
+ self.running = False
+ self.suspended = True
+ self.terminated = False
+ self.session_cleanup()
+ return True
+
+ elif self.has_control_session() and self.session_name:
+ if self.control_session.suspend(session_name=self.session_name):
+
+ self.running = False
+ self.suspended = True
+ self.terminated = False
+ self.session_cleanup()
+ return True
+
+ else:
+ raise X2goClientException('cannot suspend session')
- self.running = False
- self.suspended = True
- return True
else:
self._X2goSession__disconnect()
return False
@@ -443,12 +598,26 @@ class X2goSession(object):
"""
if self.is_alive():
- if self.terminal_session.terminate():
+ if self.has_terminal_session():
+ if self.terminal_session.terminate():
+
+ self.running = False
+ self.suspended = False
+ self.terminated = True
+ self.session_cleanup()
+ return True
+
+ elif self.has_control_session() and self.session_name:
+ if self.control_session.terminate(session_name=self.session_name):
+
+ self.running = False
+ self.suspended = False
+ self.terminated = True
+ self.session_cleanup()
+ return True
+ else:
+ raise X2goClientException('cannot terminate session')
- self.running = False
- self.suspended = False
- self.terminated = True
- return True
else:
self._X2goSession__disconnect()
@@ -495,7 +664,6 @@ class X2goSession(object):
return False
__session_ok = session_ok
-
def is_connected(self):
"""\
Test if this registered X2go session is connected to the
@@ -505,7 +673,12 @@ class X2goSession(object):
@rtype: C{bool}
"""
- return self.control_session.is_connected()
+ self.connected = self.control_session.is_connected()
+ if not self.connected:
+ self.running = None
+ self.suspended = None
+ self.terminated = None
+ return self.connected
__is_connected = is_connected
def is_running(self):
@@ -516,7 +689,14 @@ class X2goSession(object):
@rtype: C{bool}
"""
- return self.is_connected() and self.control_session.is_running(self.get_session_name())
+ if self.is_connected():
+ self.running = self.control_session.is_running(self.get_session_name())
+ if self.running:
+ self.suspended = False
+ self.terminated = False
+ if self.virgin and not self.running:
+ self.running = None
+ return self.running
__is_running = is_running
def is_suspended(self):
@@ -527,7 +707,14 @@ class X2goSession(object):
@rtype: C{bool}
"""
- return self.is_connected() and self.control_session.is_suspended(self.get_session_name())
+ if self.is_connected():
+ self.suspended = self.control_session.is_suspended(self.get_session_name())
+ if self.suspended:
+ self.running = False
+ self.terminated = False
+ if self.virgin and not self.suspended:
+ self.suspended = None
+ return self.suspended
__is_suspended = is_suspended
def has_terminated(self):
@@ -538,7 +725,14 @@ class X2goSession(object):
@rtype: C{bool}
"""
- return self.is_connected() and self.control_session.has_terminated(self.get_session_name())
+ if self.is_connected():
+ self.terminated = not self.virgin and self.control_session.has_terminated(self.get_session_name())
+ if self.terminated:
+ self.running = False
+ self.suspended = False
+ if self.virgin and not self.terminated:
+ self.terminated = None
+ return self.has_terminated
__has_terminated = has_terminated
def share_local_folder(self, folder_name):
@@ -557,4 +751,10 @@ class X2goSession(object):
return self.terminal_session.share_local_folder(folder_name=folder_name)
__share_local_folder = share_local_folder
+ def session_cleanup(self):
+ """\
+ STILL UNDOCUMENTED
+ """
+ if self.has_terminal_session():
+ self.terminal_session.release_proxy()
diff --git a/x2go/utils.py b/x2go/utils.py
index 8a2fa06..2fc705b 100644
--- a/x2go/utils.py
+++ b/x2go/utils.py
@@ -32,6 +32,7 @@ import paramiko
# Python X2go modules
from defaults import _pack_methods_nx3
+from defaults import X2GO_SESSIONPROFILE_DEFAULTS
def is_in_nx3packmethods(method):
@@ -109,6 +110,12 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
_params = copy.deepcopy(_options)
+ # get rid of unknown session profile options
+ _known_options = X2GO_SESSIONPROFILE_DEFAULTS.keys()
+ for p in _params.keys():
+ if p not in _known_options:
+ del _params[p]
+
_rename_dict = {
'host': 'server',
'user': 'username',
@@ -188,7 +195,7 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
_params['session_type'] = 'desktop'
del _params['rootless']
- # currently ignored in Python X2go, use it for client implementations
+ # currently known but ignored in Python X2go
_ignored_options = [
'iconvto',
'iconvfrom',
@@ -203,9 +210,12 @@ def _convert_SessionProfileOptions_2_SessionParams(_options):
'icon',
'applications',
'xdmcpserver',
+ 'usesshproxy',
+ 'sshproxy',
]
for i in _ignored_options:
del _params[i]
+
return _params
def session_names_by_timestamp(session_infos):
diff --git a/x2go/x2go_exceptions.py b/x2go/x2go_exceptions.py
index 2eef4e5..e969875 100644
--- a/x2go/x2go_exceptions.py
+++ b/x2go/x2go_exceptions.py
@@ -39,11 +39,13 @@ SSHException = paramiko.SSHException
class _X2goException(exceptions.BaseException): pass
class X2goClientException(_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 X2goSessionRegistryException(_X2goException): pass
class X2goSettingsException(_X2goException): pass
class X2goFwTunnelException(_X2goException): pass
class X2goRevFwTunnelException(_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