This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository python-x2go. commit f5f6f6db53dff875a642583da56c0ada78a47231 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 4 13:58:21 2014 +0100 Provide session profile backend for a http broker. --- debian/changelog | 2 + x2go/backends/control/plain.py | 5 + x2go/backends/profiles/base.py | 210 +++++++++++++++++++++++++++++---- x2go/backends/profiles/file.py | 16 +++ x2go/backends/profiles/httpbroker.py | 215 +++++++++++++++++++++++++++++++--- x2go/client.py | 40 +++++-- x2go/defaults.py | 2 +- x2go/inifiles.py | 4 +- x2go/registry.py | 1 + x2go/utils.py | 27 +++-- 10 files changed, 461 insertions(+), 61 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0c28057..3d7ff02 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,8 @@ python-x2go (0.5.0.0-0x2go1) UNRELEASED; urgency=low not really used by third-party products, if at all). - Fix setting default values in X2GoClientXConfig class. - Default to xdg-open as default PDF viewer command. + - Provide basic session profile backend for a http broker. + - Make session profile backends more unicode robust. -- Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Sun, 05 Jan 2014 16:35:57 +0100 diff --git a/x2go/backends/control/plain.py b/x2go/backends/control/plain.py index bb0ec98..fa756df 100644 --- a/x2go/backends/control/plain.py +++ b/x2go/backends/control/plain.py @@ -51,6 +51,7 @@ import x2go.defaults as defaults import x2go.checkhosts as checkhosts from x2go.defaults import BACKENDS as _BACKENDS +from x2go.defaults import CURRENT_LOCAL_USER as _current_user import x2go._paramiko x2go._paramiko.monkey_patch_paramiko() @@ -817,6 +818,10 @@ class X2GoControlSession(paramiko.SSHClient): """ _fake_hostname = None + if not username: + self.logger('no username specified, cannot connect without username', loglevel=log.loglevel_ERROR) + raise paramiko.AuthenticationException('no username specified, cannot connect without username') + if type(password) not in (types.StringType, types.UnicodeType): password = '' if type(sshproxy_password) not in (types.StringType, types.UnicodeType): diff --git a/x2go/backends/profiles/base.py b/x2go/backends/profiles/base.py index 6985f9a..641e5e4 100644 --- a/x2go/backends/profiles/base.py +++ b/x2go/backends/profiles/base.py @@ -36,7 +36,7 @@ from x2go.defaults import X2GO_DESKTOPSESSIONS as _X2GO_DESKTOPSESSIONS import x2go.log as log import x2go.utils as utils -from x2go.x2go_exceptions import X2GoNotImplementedYetException +from x2go.x2go_exceptions import X2GoProfileException class X2GoSessionProfiles(): @@ -74,7 +74,7 @@ class X2GoSessionProfiles(): if utils._checkSessionProfileDefaults(session_profile_defaults): self.defaultSessionProfile = session_profile_defaults - self.session_profiles = self.populate_session_profiles() + self.populate_session_profiles() def __call__(self, profile_id_or_name): """\ @@ -90,6 +90,29 @@ class X2GoSessionProfiles(): _profile_id = self.check_profile_id_or_name(self, profile_id_or_name) return self.get_profile_config(profile_id=_profile_id) + def init_profile_cache(self, profile_id_or_name): + """\ + Some session profile backends (e.g. the broker backends cache + dynamic session profile data). On new connections, it is + recommented to (re-)initialize these caches. + + @param profile_id_or_name: profile ID or profile name + @type profile_id_or_name: C{str} + + """ + profile_id = self.check_profile_id_or_name(profile_id_or_name) + + # allow backend specific clean-up + self._init_profile_cache(profile_id) + + def _init_profile_cache(self, profile_id): + """\ + Inherit from this class to (re-)initialize profile ID based + cache storage. + + """ + pass + def populate_session_profiles(self): """\ Load a session profile set from the configuration storage @@ -99,7 +122,7 @@ class X2GoSessionProfiles(): @rtype: C{dict} """ - return self. _populate_session_profiles() + self.session_profiles = self. _populate_session_profiles() def _populate_session_profiles(self): """\ @@ -126,6 +149,7 @@ class X2GoSessionProfiles(): """ _profile_id = self.check_profile_id_or_name(profile_id_or_name) + if not self._profile_metatypes.has_key(_profile_id) or force: _config = self.get_profile_config(_profile_id) if _config['host']: @@ -151,10 +175,74 @@ class X2GoSessionProfiles(): _metatype = 'RDP/direct' else: _metatype = 'not supported' - self._profile_metatypes[_profile_id] = _metatype + self._profile_metatypes[_profile_id] = unicode(_metatype) else: return self._profile_metatypes[_profile_id] + def is_mutable(self, profile_id_or_name): + """\ + Check if a given profile name (or ID) is mutable or not. + + @param profile_id_or_name: profile name or profile ID + @type profile_id_or_name: C{str} + + @return: C{True} if the session profile of the specified name/ID is mutable + @rtype: C{bool} + + """ + try: + profile_id = self.check_profile_id_or_name(profile_id_or_name) + return self._is_mutable(profile_id) + except X2GoProfileException: + return None + + def _is_mutable(self, profile_id): + """\ + Inherit from this base class and provide your own decision making + code here if a given profile ID is mutable or not. + + @param profile_id: profile ID + @type profile_id: C{str} + + @return: C{True} if the session profile of the specified ID is mutable + @rtype: C{bool} + + """ + return False + + def supports_mutable_profiles(self): + """\ + Check if the current session profile backend supports + mutable session profiles. + + @return: list of mutable profiles + @rtype: C{list) + + """ + return self._supports_mutable_profiles() + + def _supports_mutable_profiles(self): + """\ + Inherit from this base class and provide your own decision making + code here if a your session profile backend supports mutable + session profiles or not. + + @return: list of mutable profiles + @rtype: C{list) + + """ + return False + + def mutable_profile_ids(self): + """\ + List all mutable session profiles. + + @return: List up all session profile IDs of mutable session profiles. + @rtype: C{bool} + + """ + return [ p for p in self.profile_ids if self._is_mutable(p) ] + def write(self): """\ Store session profile data to the storage backend. @@ -220,28 +308,31 @@ class X2GoSessionProfiles(): _profile_id = profile_id or self.check_profile_id_or_name(profile_id_or_name) _profile_config = {} for option in self._get_profile_options(_profile_id): - _profile_config[option] = self._get_profile_parameter(_profile_id, option, key_type=self.get_profile_option_type(option)) + value = self._get_profile_parameter(_profile_id, option, key_type=self.get_profile_option_type(option)) - if parameter is not None: - if parameter in _profile_config.keys(): + if option == 'export': + _strvalue = value.replace(',', ';').strip().strip('"').strip().strip(';').strip() + value = {} + if _strvalue: + _export_paths = _strvalue.split(';') + for _path in _export_paths: + if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path + _auto_export_path = re.match('.*:1$', _path) and True or False + _export_path = ':'.join(_path.split(':')[:-1]) + value[_export_path] = _auto_export_path - value = _profile_config[parameter] + if type(value) is types.StringType: + value = unicode(value) - if parameter == 'export': - _strvalue = value.replace(',', ';').strip().strip('"').strip().strip(';').strip() - value = {} - if _strvalue: - _export_paths = _strvalue.split(';') - for _path in _export_paths: - if not re.match('.*:(0|1)$', _path): _path = '%s:1' % _path - _auto_export_path = re.match('.*:1$', _path) and True or False - _export_path = ':'.join(_path.split(':')[:-1]) - value[_export_path] = _auto_export_path + _profile_config[option] = value + if parameter is not None: + if parameter in _profile_config.keys(): + value = _profile_config[parameter] return value - else: raise X2GoProfileException('no such session profile parameter: %s' % parameter) + return _profile_config def default_profile_config(self): @@ -303,7 +394,7 @@ class X2GoSessionProfiles(): @rtype: C{bool} """ - return profile_id in self.profile_ids + return unicode(profile_id) in self.profile_ids @property def profile_names(self): @@ -326,7 +417,7 @@ class X2GoSessionProfiles(): @rtype: C{bool} """ - return profile_name in self.profile_names + return unicode(profile_name) in self.profile_names def to_profile_id(self, profile_name): """\ @@ -341,7 +432,7 @@ class X2GoSessionProfiles(): """ _profile_ids = [ p for p in self.profile_ids if self.to_profile_name(p) == profile_name ] if len(_profile_ids) == 1: - return _profile_ids[0] + return unicode(_profile_ids[0]) elif len(_profile_ids) == 0: return None else: @@ -360,9 +451,9 @@ class X2GoSessionProfiles(): """ _profile_config = self.get_profile_config(profile_id=profile_id) if _profile_config.has_key('name'): - return _profile_config['name'] + return unicode(_profile_config['name']) else: - return '' + return u'' def add_profile(self, profile_id=None, force_add=False, **kwargs): """\ @@ -396,7 +487,7 @@ class X2GoSessionProfiles(): self._cached_profile_ids = [] self._cached_profile_names = [] - return profile_id + return unicode(profile_id) def delete_profile(self, profile_id_or_name): """\ @@ -440,11 +531,14 @@ class X2GoSessionProfiles(): except X2GoProfileException: profile_id = profile_id_or_name + if not self.is_mutable(profile_id): + raise X2GoProfileException("session profile cannot be modified, it is marked as immutable") + if option == 'name': profile_name = value current_profile_name = self.get_value(profile_id, option) if not profile_name: - raise X2GoProfileException('profile name for profile id %s may not be empty' % profile_id) + raise X2GoProfileException('profile name for profile id %s must not be empty' % profile_id) else: self._cached_profile_names = [] if profile_name != current_profile_name and profile_name in self.profile_names: @@ -462,6 +556,10 @@ class X2GoSessionProfiles(): _config = self.get_profile_config(profile_id=profile_id) if _config.has_key('host') and _config['host'] != value: self._profiles_need_profile_id_renewal.append(profile_id) + if type(value) is types.TupleType: + value = list(value) + if type(value) is not types.ListType: + value = value.split(',') self._update_value(profile_id, option, value) @@ -495,6 +593,8 @@ class X2GoSessionProfiles(): _profile_id = profile_id_or_name else: raise X2GoProfileException('No session profile with id or name ,,%s\'\' exists.' % profile_id_or_name) + if _profile_id is not None: + _profile_id = unicode(_profile_id) return _profile_id def to_session_params(self, profile_id_or_name=None, profile_id=None): @@ -557,3 +657,61 @@ class X2GoSessionProfiles(): """ return [] + def get_server_hostname(self, profile_id): + """\ + Retrieve host name of the X2Go Server configured in a session profile. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the host name of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return self._get_server_hostname(profile_id) + + def _get_server_hostname(self, profile_id): + """\ + Inherit from this class and provide a way for actually obtaining + a the server host name for a given profile ID. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the host name of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return [u'localhost'] + + def get_server_port(self, profile_id): + """\ + Retrieve SSH port of the X2Go Server configured in a session profile. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the SSH port of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return self._get_server_port(profile_id) + + def _get_server_hostname(self, profile_id): + """\ + Inherit from this class and provide a way for actually obtaining + a the server SSH port for a given profile ID. + + @param profile_id: the profile's unique ID + @type profile_id: C{str} + + @return: the SSH port of the X2Go Server configured by the session profile + of the given profile ID + @rtype: C{list} + + """ + return 22 + diff --git a/x2go/backends/profiles/file.py b/x2go/backends/profiles/file.py index 9e7edcf..0f08336 100644 --- a/x2go/backends/profiles/file.py +++ b/x2go/backends/profiles/file.py @@ -26,6 +26,8 @@ applications. """ __NAME__ = 'x2gosessionprofiles-pylib' +import types + # Python X2Go modules from x2go.defaults import X2GO_SESSIONPROFILES_CONFIGFILES as _X2GO_SESSIONPROFILES_CONFIGFILES import x2go.backends.profiles.base as base @@ -90,6 +92,12 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): self.get_profile_metatype(session_profile) return session_profiles + def _is_mutable(self, profile_id): + return True + + def _supports_mutable_profiles(self): + return True + def _write(self): self._write_user_config = self.write_user_config return inifiles.X2GoIniFile.write(self) @@ -98,6 +106,8 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): self.iniConfig.remove_section(profile_id) def _update_value(self, profile_id, option, value): + if option == 'host': + value = ','.join(value) inifiles.X2GoIniFile.update_value(self, profile_id, option, value) def _get_profile_parameter(self, profile_id, option, key_type): @@ -108,3 +118,9 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles, inifiles.X2GoIniFile): def _get_profile_ids(self): return [ s for s in self.iniConfig.sections() if s != "none" ] + + def _get_server_hostname(self, profile_id): + return self.get_profile_config(profile_id)['host'] + + def _get_server_port(self, profile_id): + return self.get_profile_config(profile_id)['sshport'] diff --git a/x2go/backends/profiles/httpbroker.py b/x2go/backends/profiles/httpbroker.py index 0d27cb4..569e851 100644 --- a/x2go/backends/profiles/httpbroker.py +++ b/x2go/backends/profiles/httpbroker.py @@ -26,8 +26,16 @@ applications. """ __NAME__ = 'x2gosessionprofiles-pylib' +import re +import requests +import copy +import types +try: import simplejson as json +except ImportError: import json + # Python X2Go modules -from x2go.defaults import X2GO_SESSIONPROFILE_DEFAULTS +from x2go.defaults import X2GO_SESSIONPROFILE_DEFAULTS as _X2GO_SESSIONPROFILE_DEFAULTS +from x2go.defaults import CURRENT_LOCAL_USER as _CURRENT_LOCAL_USER import x2go.backends.profiles.base as base import x2go.log as log @@ -35,14 +43,27 @@ from x2go.x2go_exceptions import X2GoNotImplementedYetException class X2GoSessionProfiles(base.X2GoSessionProfiles): - defaultSessionProfile = X2GO_SESSIONPROFILE_DEFAULTS + defaultSessionProfile = _X2GO_SESSIONPROFILE_DEFAULTS - def __init__(self, session_profile_defaults=None, logger=None, loglevel=log.loglevel_DEFAULT): + def __init__(self, session_profile_defaults=None, + broker_url="http://localhost:8080/json/", + broker_username=None, + broker_password=None, + broker_noauth=False, + logger=None, loglevel=log.loglevel_DEFAULT, + **kwargs): """\ Retrieve X2Go session profiles from a HTTP(S) session broker. @param session_profile_defaults: a default session profile @type session_profile_defaults: C{dict} + @param broker_url: URL for accessing the X2Go Session Broker + @type broker_url: C{str} + @param broker_password: use this password for authentication against the X2Go Session Broker (avoid + password string in the C{broker_URL} parameter is highly recommended) + @type broker_password: C{str} + @param broker_noauth: the X2Go Session Broker accepts connections without authentication + @type broker_noauth: C{bool} @param logger: you can pass an L{X2GoLogger} object to the L{X2GoSessionProfilesHTTPSBROKER} constructor @type logger: L{X2GoLogger} instance @@ -51,7 +72,139 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @type loglevel: C{int} """ + self.broker_noauth = broker_noauth + if broker_url.upper() != "HTTP": + match = re.match('^(?P<protocol>(http(|s)))://(|(?P<user>[a-zA-Z0-9_\.-]+)(|:(?P<password>.*))@)(?P<hostname>[a-zA-Z0-9\.-]+)(|:(?P<port>[0-9]+))($|/(?P<path>.*)$)', broker_url) + p = match.groupdict() + if p['user']: + self.broker_username = p['user'] + else: + self.broker_username = broker_username + if not self.broker_noauth: + if p['password']: + self.broker_password = p['password'] + else: + self.broker_password = broker_password + else: + self.broker_password = None + + # fine-tune the URL + p['path'] = "/{path}".format(**p) + if p['port'] is not None: + p['port'] = ":{port}".format(**p) + + self.broker_url = "{protocol}://{hostname}{port}{path}".format(**p) + + else: + self.broker_username = broker_username + self.broker_password = broker_password + self.broker_url = broker_url + base.X2GoSessionProfiles.__init__(self, session_profile_defaults=session_profile_defaults, logger=logger, loglevel=loglevel) + if self.broker_url != "HTTP": + self.logger("Using session broker at URL: %s" % self.broker_url, log.loglevel_NOTICE) + + self._broker_profile_cache = {} + self._mutable_profile_ids = None + self._broker_auth_successful = None + + self._broker_type = "http" + + def get_broker_noauth(self): + return self.broker_noauth + + def get_broker_username(self): + return self.broker_username + + def get_broker_url(self): + return self.broker_url + + def set_broker_url(self, broker_url): + self.broker_url = broker_url + + def get_broker_type(self): + return self._broker_type + + def broker_simpleauth(self, broker_username, broker_password): + if self.broker_url is not None: + request_data = { + 'user': broker_username or '', + 'password': broker_password or '', + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200: + self.broker_username = broker_username or '' + self.broker_password = broker_password or '' + self._broker_auth_successful = True + return True + self._broker_auth_successful = False + return False + + def broker_disconnect(self): + _profile_ids = copy.deepcopy(self.profile_ids) + + # forget nearly everything... + for profile_id in _profile_ids: + self.init_profile_cache(profile_id) + try: del self._profile_metatypes[profile_id] + except KeyError: pass + try: self._profiles_need_profile_id_renewal.remove(profile_id) + except ValueError: pass + try: self._cached_profile_names.remove(self.to_profile_name(profile_id)) + except ValueError: pass + try: self._cached_profile_ids.remove(profile_id) + except ValueError: pass + del self.session_profiles[profile_id] + self._mutable_profile_ids = None + self._broker_auth_successful = False + self.broker_password = None + + def is_broker_authenticated(self): + if self._broker_auth_successful is None: + # do a test auth against the given broker URL + self.broker_simpleauth(self.broker_username, self.broker_password) + return self._broker_auth_successful + + def broker_listprofiles(self): + if self.broker_url is not None: + request_data = { + 'task': 'listprofiles', + 'user': self.broker_username, + 'password': self.broker_password, + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): + payload = json.loads(r.text) + if payload.has_key('mutable_profile_ids'): + self._mutable_profile_ids = payload['mutable_profile_ids'] + self._broker_auth_successful = True + return payload['profiles'] if payload['task'] == 'listprofiles' else {} + self._broker_auth_successful = False + return {} + + def broker_selectsession(self, profile_id): + if self.broker_url is not None: + if not self._broker_profile_cache.has_key(profile_id) or not self._broker_profile_cache[profile_id]: + request_data = { + 'task': 'selectsession', + 'profile-id': profile_id, + 'user': self.broker_username, + 'password': self.broker_password, + } + r = requests.post(self.broker_url, data=request_data) + if r.status_code == 200 and r.headers['content-type'].startswith("text/json"): + payload = json.loads(r.text) + self._broker_profile_cache[profile_id] = payload['selected_session'] if payload['task'] == 'selectsession' else {} + self._broker_auth_successful = True + else: + self._broker_auth_successful = False + self._broker_profile_cache[profile_id] + return self._broker_profile_cache[profile_id] + return {} + + def _init_profile_cache(self, profile_id): + if self._broker_profile_cache.has_key(unicode(profile_id)): + del self._broker_profile_cache[unicode(profile_id)] def _populate_session_profiles(self): """\ @@ -62,31 +215,61 @@ class X2GoSessionProfiles(base.X2GoSessionProfiles): @rtype: C{dict} """ - session_profiles = LOAD + if self.broker_noauth or \ + self.broker_username and self.broker_password: - for session_profile in session_profiles: - for key, default_value in self.defaultSessionProfile.iteritems(): - if not self.iniConfig.has_option(session_profile, key): - self._storeValue(session_profile, key, default_value) - # update cached meta type session profile information - self.get_profile_metatype(session_profile) + session_profiles = self.broker_listprofiles() + _session_profiles = copy.deepcopy(session_profiles) + + for session_profile in _session_profiles: + session_profile = unicode(session_profile) + for key, default_value in self.defaultSessionProfile.iteritems(): + key = unicode(key) + if type(default_value) is types.StringType: + default_value = unicode(default_value) + if not session_profiles[session_profile].has_key(key): + session_profiles[session_profile][key] = default_value + + else: + session_profiles = {} return session_profiles + def _is_mutable(self, profile_id): + if type(self._mutable_profile_ids) is types.ListType and profile_id in self._mutable_profile_ids: + return True + return False + + def _supports_mutable_profiles(self): + if type(self._mutable_profile_ids) is types.ListType: + return True + return False + def _write(self): - print "BROKER CLIENT: WRITING SESSION PROFILES IS NOT SUPPORTED" + print "not suported, yet" def _delete_profile(self, profile_id): - print "BROKER CLIENT: DELETING SESSION PROFILES IS NOT SUPPORTED" + del self.session_profiles[unicode(profile_id)] def _update_value(self, profile_id, option, value): - print "BROKER CLIENT: MODIFYING SESSION PROFILES IS NOT SUPPORTED" + if type(value) is types.StringType: + value = unicode(value) + self.session_profiles[unicode(profile_id)][unicode(option)] = value def _get_profile_parameter(self, profile_id, option, key_type): - print "TODO" + return key_type(self.session_profiles[unicode(profile_id)][unicode(option)]) def _get_profile_options(self, profile_id): - print "TODO" + return self.session_profiles[unicode(profile_id)].keys() def _get_profile_ids(self): - print "TODO" + self.session_profiles.keys() + return self.session_profiles.keys() + + def _get_server_hostname(self, profile_id): + selected_session = self.broker_selectsession(profile_id) + return selected_session['server'] + + def _get_server_port(self, profile_id): + selected_session = self.broker_selectsession(profile_id) + return int(selected_session['port']) diff --git a/x2go/client.py b/x2go/client.py index debba28..b1fa978 100644 --- a/x2go/client.py +++ b/x2go/client.py @@ -182,6 +182,9 @@ class X2GoClient(object): profiles_backend=_BACKENDS['X2GoSessionProfiles']['default'], settings_backend=_BACKENDS['X2GoClientSettings']['default'], printing_backend=_BACKENDS['X2GoClientPrinting']['default'], + broker_url=None, + broker_password=None, + broker_noauth=False, client_rootdir=None, sessions_rootdir=None, ssh_rootdir=None, @@ -215,6 +218,12 @@ class X2GoClient(object): @type settings_backend: C{str} @param printing_backend: X2Go client printing backend to use @type printing_backend: C{str} + @param broker_url: URL pointing to the X2Go Session Broker + @type broker_url: C{str} + @param broker_password: use this password for authentication against the X2Go Session Broker + @type broker_password: C{str} + @param broker_noauth: accessing the X2Go Session Broker works without credentials + @type broker_noauth: C{bool} @param client_rootdir: client base dir (default: ~/.x2goclient) @type client_rootdir: C{str} @param sessions_rootdir: sessions base dir (default: ~/.x2go) @@ -268,6 +277,11 @@ class X2GoClient(object): self.info_backend = utils._get_backend_class(info_backend, "X2GoServerSessionInfo") self.list_backend = utils._get_backend_class(list_backend, "X2GoServerSessionList") self.proxy_backend = utils._get_backend_class(proxy_backend, "X2GoProxy") + if broker_url is not None: + if broker_url.lower().startswith('ssh'): + profiles_backend = 'sshbroker' + elif broker_url.lower().startswith('http'): + profiles_backend = 'httpbroker' self.profiles_backend = utils._get_backend_class(profiles_backend, "X2GoSessionProfiles") self.settings_backend = utils._get_backend_class(settings_backend, "X2GoClientSettings") self.printing_backend = utils._get_backend_class(printing_backend, "X2GoClientPrinting") @@ -288,7 +302,7 @@ class X2GoClient(object): _settings_config_file = os.path.join(self.client_rootdir, _X2GO_SETTINGS_FILENAME) _printing_config_file = os.path.join(self.client_rootdir, _X2GO_PRINTING_FILENAME) _xconfig_config_file = os.path.join(self.client_rootdir, _X2GO_XCONFIG_FILENAME) - self.session_profiles = self.profiles_backend(config_files=[_sessions_config_file], logger=self.logger) + self.session_profiles = self.profiles_backend(config_files=[_sessions_config_file], logger=self.logger, broker_url=broker_url, broker_password=broker_password, broker_noauth=broker_noauth) self.client_settings = self.settings_backend(config_files=[_settings_config_file], logger=self.logger) self.client_printing = self.printing_backend(config_files=[_printing_config_file], client_instance=self, logger=self.logger) else: @@ -864,18 +878,27 @@ class X2GoClient(object): @rtype: C{str} """ + _p = None # detect profile name and profile id properly if profile_id and self.session_profiles.has_profile_id(profile_id): _p = profile_id elif profile_name and self.session_profiles.has_profile_name(profile_name): _p = profile_name - else: - _p = None - + elif profile_id: + try: + _p = self.session_profiles.check_profile_id_or_name(profile_id) + except x2go_exceptions.X2GoProfileException: + pass + elif profile_name: + try: + _p = self.session_profiles.check_profile_id_or_name(profile_name) + except x2go_exceptions.X2GoProfileException: + pass if _p: - _profile_id = self.session_profiles.check_profile_id_or_name(_p) _profile_name = self.session_profiles.to_profile_name(_profile_id) + else: + _profile_id = None # test if session_name has already been registered. If yes, return it immediately. if type(session_name) is types.StringType: @@ -886,8 +909,10 @@ class X2GoClient(object): if known_hosts is None: known_hosts = os.path.join(_LOCAL_HOME, self.ssh_rootdir, 'known_hosts') + if _profile_id: - if _p: + # initialize session profile cache + self.session_profiles.init_profile_cache(_profile_id) _params = self.session_profiles.to_session_params(profile_id=_profile_id) del _params['profile_name'] @@ -897,7 +922,8 @@ class X2GoClient(object): if k in kwargs.keys(): _params[k] = kwargs[k] - server = _params['server'] + server = self.session_profiles.get_server_hostname(_profile_id) + _params['port'] = self.session_profiles.get_server_port(_profile_id) del _params['server'] _params['client_instance'] = self diff --git a/x2go/defaults.py b/x2go/defaults.py index 59373f4..ee785a5 100644 --- a/x2go/defaults.py +++ b/x2go/defaults.py @@ -296,7 +296,7 @@ X2GO_SESSIONPROFILE_DEFAULTS = { 'usekbd': True, 'layout': 'us', 'type': 'pc105/us', 'variant': '', 'sound': False, 'soundsystem': 'pulse', 'startsoundsystem': False, 'soundtunnel':True, 'defsndport':True, 'sndport':4713, 'name': 'NEW_PROFILE', 'icon': ':icons/128x128/x2gosession.png', - 'host': 'server.mydomain', 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False, 'forwardsshagent': False, + 'host': ['server.mydomain'], 'user': CURRENT_LOCAL_USER, 'key': '', 'sshport': 22, 'krblogin': False, 'forwardsshagent': False, 'rootless': True, 'applications': X2GO_GENERIC_APPLICATIONS, 'command':'TERMINAL', 'published': False, 'directrdp': False, 'directrdpsettings': '', 'rdpclient': 'rdesktop', 'rdpport': 3389, 'rdpoptions': '-u X2GO_USER -p X2GO_PASSWORD', 'rdpserver': '', diff --git a/x2go/inifiles.py b/x2go/inifiles.py index e363bee..1bc10d4 100644 --- a/x2go/inifiles.py +++ b/x2go/inifiles.py @@ -52,7 +52,6 @@ class X2GoIniFile(object): always contain the same fields. """ - user_config_file = None def __init__(self, config_files, defaults=None, logger=None, loglevel=log.loglevel_DEFAULT): """\ @@ -70,6 +69,7 @@ class X2GoIniFile(object): @type loglevel: C{int} """ + self.user_config_file = None self._write_user_config = True # make sure a None type gets turned into list type @@ -102,8 +102,8 @@ class X2GoIniFile(object): if not os.path.exists(file_name): utils.touch_file(file_name) _create_file = True + self.user_config_file = file_name break - self.load() if _create_file: diff --git a/x2go/registry.py b/x2go/registry.py index 66ad62f..ffe0708 100644 --- a/x2go/registry.py +++ b/x2go/registry.py @@ -560,6 +560,7 @@ class X2GoSessionRegistry(object): try: del _params['profile_id'] except: pass + print _params['port'] s = session.X2GoSession(server=server, control_session=control_session, profile_id=profile_id, profile_name=profile_name, session_name=session_name, diff --git a/x2go/utils.py b/x2go/utils.py index 13b2fe6..7f182ed 100644 --- a/x2go/utils.py +++ b/x2go/utils.py @@ -272,18 +272,27 @@ def _convert_SessionProfileOptions_2_SessionParams(options): _export = _params['export'] del _params['export'] - # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 - _export = _export.replace(",", ";") + if type(_export) is types.DictType: - _export = _export.strip().strip('"').strip().strip(';').strip() - _export_list = [ f for f in _export.split(';') if f ] + # since Python X2Go 0.5.0.0 + _params['share_local_folders'] = _export.keys() + + else: + + # before Python X2Go 0.5.0.0 (analysing the INI file's format for the export field) - _params['share_local_folders'] = [] - for _shared_folder in _export_list: # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 - if not ":" in _shared_folder: _shared_folder = "%s:1" % _shared_folder - if _shared_folder.split(":")[-1] == "1": - _params['share_local_folders'].append(":".join(_shared_folder.split(":")[:-1])) + _export = _export.replace(",", ";") + + _export = _export.strip().strip('"').strip().strip(';').strip() + _export_list = [ f for f in _export.split(';') if f ] + + _params['share_local_folders'] = [] + for _shared_folder in _export_list: + # fix for wrong export field usage in PyHoca-GUI/CLI and python-x2go before 20110923 + if not ":" in _shared_folder: _shared_folder = "%s:1" % _shared_folder + if _shared_folder.split(":")[-1] == "1": + _params['share_local_folders'].append(":".join(_shared_folder.split(":")[:-1])) if options['fullscreen']: _params['geometry'] = 'fullscreen' -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/python-x2go.git