This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch master in repository x2gobroker. from 05d2df5 x2gobroker.conf: fix comment new 436b30f Provide tool: x2gobroker-testagent. The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Summary of changes: bin/x2gobroker | 22 +---- debian/changelog | 1 + debian/rules | 1 + lib/x2gobroker-agent.pl | 24 +++++ .../x2gobroker-testagent | 94 ++++++++++++-------- x2gobroker/agent.py | 43 ++++++++- x2gobroker/brokers/base_broker.py | 6 +- x2gobroker/utils.py | 19 ++++ 8 files changed, 147 insertions(+), 63 deletions(-) copy bin/x2gobroker-testauth => sbin/x2gobroker-testagent (52%) -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/x2gobroker.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2gobroker. commit 436b30fe4508905a92baf41a3c98d0e8778f000e Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Tue Mar 18 19:23:03 2014 +0100 Provide tool: x2gobroker-testagent. --- bin/x2gobroker | 22 +----- debian/changelog | 1 + debian/rules | 1 + lib/x2gobroker-agent.pl | 24 +++++++ sbin/x2gobroker-testagent | 142 +++++++++++++++++++++++++++++++++++++ x2gobroker/agent.py | 43 ++++++++++- x2gobroker/brokers/base_broker.py | 6 +- x2gobroker/utils.py | 19 +++++ 8 files changed, 234 insertions(+), 24 deletions(-) diff --git a/bin/x2gobroker b/bin/x2gobroker index b94443c..b1f8258 100755 --- a/bin/x2gobroker +++ b/bin/x2gobroker @@ -92,25 +92,7 @@ except ImportError: from x2gobroker import __VERSION__ from x2gobroker import __AUTHOR__ from x2gobroker.loggers import logger_broker, logger_access, logger_error, tornado_log_request - -def drop_privileges(uid=x2gobroker.defaults.X2GOBROKER_DAEMON_USER, gid=x2gobroker.defaults.X2GOBROKER_DAEMON_USER): - if os.getuid() != 0: - # We're not root so, like, whatever dude - return - - # Get the uid/gid from the name - running_uid = pwd.getpwnam(uid).pw_uid - running_gid = grp.getgrnam(gid).gr_gid - - # Remove group privileges - os.setgroups([]) - - # Try setting the new uid/gid - os.setgid(running_gid) - os.setuid(running_uid) - - # Ensure a very conservative umask - old_umask = os.umask(077) +from x2gobroker.utils import drop_privileges interactive_mode_warning = False # check effective UID the broker runs as and complain appropriately... @@ -166,7 +148,7 @@ if __name__ == "__main__": cmdline_args = p.parse_args() if os.getuid() == 0 and cmdline_args.drop_privileges: - drop_privileges() + drop_privileges(uid=x2gobroker.defaults.X2GOBROKER_DAEMON_USER, gid=x2gobroker.defaults.X2GOBROKER_DAEMON_GROUP) if cmdline_args.config_file is not None: x2gobroker.defaults.X2GOBROKER_CONFIG = cmdline_args.config_file diff --git a/debian/changelog b/debian/changelog index 69afeed..0ac02f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -98,6 +98,7 @@ x2gobroker (0.0.3.0-0x2go1) UNRELEASED; urgency=low - Handle selectsessions calls with a non-existent profile ID gracefully. - Session profiles with marker user=BROKER_USER will now auto-fill-in the broker username into the session profile's 'user' option. + - Provide tool: x2gobroker-testagent. * debian/control: + Replace LDAP support with session brokerage support in LONG_DESCRIPTION. + Fix SYNOPSIS texts. diff --git a/debian/rules b/debian/rules index b1eb079..3b69310 100755 --- a/debian/rules +++ b/debian/rules @@ -24,6 +24,7 @@ export PREFIX=/usr include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/makefile.mk DEB_PYTHON_SYSTEM = $(shell test -f /usr/bin/dh_python2 && echo "" || echo "pysupport") DEB_PYTHON_INSTALL_ARGS_python-x2gobroker ?= --root=$(DEB_DESTDIR) --prefix=$(DEB_PYTHON_PREFIX_ARG) --no-compile -O0 --install-layout=deb diff --git a/lib/x2gobroker-agent.pl b/lib/x2gobroker-agent.pl index abab968..7c04a42 100755 --- a/lib/x2gobroker-agent.pl +++ b/lib/x2gobroker-agent.pl @@ -24,6 +24,19 @@ use strict; use File::Basename; +my @available_tasks = ( + "availabletasks", + "listsessions", + "findbusyservers", + "findbusyservers_by_sessionstats", + "getservers", + "addauthkey", + "delauthkey", + "suspendsession", + "terminatesession", +); + + sub InitX2GoUser { my ($user, $uidNumber, $gidNumber, $home)=@_; @@ -111,6 +124,17 @@ if($uidNumber < 1000) die 'operation on system user'; } +if($mode eq 'availabletasks') +{ + InitX2GoUser($uid, $uidNumber, $gidNumber, $home); + print "OK\n"; + my $available_task; + foreach $available_task (@available_tasks) { + print "$available_task\n"; + } +} + + if($mode eq 'listsessions') { InitX2GoUser($uid, $uidNumber, $gidNumber, $home); diff --git a/sbin/x2gobroker-testagent b/sbin/x2gobroker-testagent new file mode 100755 index 0000000..c22b5a7 --- /dev/null +++ b/sbin/x2gobroker-testagent @@ -0,0 +1,142 @@ +#!/usr/bin/env python + +# This file is part of the X2Go Project - http://www.x2go.org +# Copyright (C) 2011-2014 by Oleksandr Shneyder <oleksandr.shneyder@obviously-nice.de> +# Copyright (C) 2011-2014 by Heinz-Markus Graesing <heinz-m.graesing@obviously-nice.de> +# Copyright (C) 2012-2014 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +# +# X2Go Session Broker is free software; you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# X2Go Session Broker is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program; if not, write to the +# Free Software Foundation, Inc., +# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + +import os +import sys +import setproctitle +import argparse +import logging + +# perform an authentication against the authentication mechanism configured for WSGI +try: + import x2gobroker.defaults +except ImportError: + sys.path.insert(0, os.path.join(os.getcwd(), '..')) + import x2gobroker.defaults +import x2gobroker.loggers + +import x2gobroker.agent +from x2gobroker.utils import drop_privileges + +PROG_NAME = os.path.basename(sys.argv[0]) +PROG_OPTIONS = sys.argv[1:] +try: + _password_index = PROG_OPTIONS.index('--password')+1 + PROG_OPTIONS[_password_index] = "XXXXXXXX" +except ValueError: + # ignore if --password option is not specified + pass +setproctitle.setproctitle("%s %s" % (PROG_NAME, " ".join(PROG_OPTIONS))) + +if __name__ == "__main__": + + agent_options = [ + {'args':['--drop-privileges'], 'default': False, 'action': 'store_true', 'help': 'Drop privileges to user {x2gobroker} (recommended)'.format(x2gobroker=x2gobroker.defaults.X2GOBROKER_DAEMON_USER), }, + {'args':['-H','--host'], 'default': 'LOCAL', 'metavar': 'HOSTNAME', 'help': 'Test X2Go Session Broker Agent on this host (default: LOCAL)', }, + {'args':['-p','--port'], 'default': 22, 'metavar': 'PORT', 'help': 'For remote agent calls (via SSH) use this port as SSH port (default: 22)', }, + {'args':['-u','--username'], 'default': None, 'metavar': 'USERNAME', 'help': 'When testing the broker agent, test on behalf of this user (default: none)', }, + {'args':['-t','--task'], 'default': 'PING_ICMP', 'metavar': 'AGENT_TASK', 'help': 'Perform this task on the (remote) broker agent', }, + {'args':['--list-tasks'], 'default': False, 'action': 'store_true', 'help': 'List available broker agent tasks', }, + ] + misc_options = [ + {'args':['-C','--config-file'], 'default': None, 'metavar': 'CONFIG_FILE', 'help': 'Specify a special configuration file name, default is: {default}'.format(default=x2gobroker.defaults.X2GOBROKER_CONFIG), }, + {'args':['-d','--debug'], 'default': False, 'action': 'store_true', 'help': 'enable debugging code', }, + ] + p = argparse.ArgumentParser(description='X2Go Session Broker (Agent Test Utility)',\ + formatter_class=argparse.RawDescriptionHelpFormatter, \ + add_help=True, argument_default=None) + p_agent = p.add_argument_group('agent parameters') + p_misc = p.add_argument_group('miscellaneous parameters') + + for (p_group, opts) in ( (p_agent, agent_options), (p_misc, misc_options), ): + for opt in opts: + args = opt['args'] + del opt['args'] + p_group.add_argument(*args, **opt) + + cmdline_args = p.parse_args() + + if cmdline_args.username is None and not cmdline_args.list_tasks: + p.print_help() + print + print "*** Cannot continue without username... ***" + print + sys.exit(-1) + + if cmdline_args.config_file is not None: + x2gobroker.defaults.X2GOBROKER_CONFIG = cmdline_args.config_file + + if cmdline_args.drop_privileges: + drop_privileges(uid=x2gobroker.defaults.X2GOBROKER_DAEMON_USER, gid=x2gobroker.defaults.X2GOBROKER_DAEMON_GROUP) + + if cmdline_args.debug: + x2gobroker.defaults.X2GOBROKER_DEBUG = cmdline_args.debug + # raise log level to DEBUG if requested... + if x2gobroker.defaults.X2GOBROKER_DEBUG and not x2gobroker.defaults.X2GOBROKER_TESTSUITE: + x2gobroker.loggers.logger_broker.setLevel(logging.DEBUG) + x2gobroker.loggers.logger_error.setLevel(logging.DEBUG) + + username = cmdline_args.username + hostname = cmdline_args.host + port = cmdline_args.port + task = cmdline_args.task + + list_tasks = cmdline_args.list_tasks + +local_agent = (hostname == 'LOCAL') +query_mode = local_agent and 'LOCAL' or 'SSH' +if local_agent: remote_agent = None +else: remote_agent = {'hostname': hostname, 'port': port, } + +agent_client_tasks = x2gobroker.agent.tasks +if 'availabletasks' in agent_client_tasks: + try: + remote_agent_tasks = x2gobroker.agent.tasks_available(username=username, query_mode=query_mode, remote_agent=remote_agent) + except x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException, e: + print e + sys.exit(0) + +def call_agent(task): + return agent_client_tasks[task](username=username, query_mode=query_mode, remote_agent=remote_agent) + +if __name__ == "__main__": + + if not local_agent and not x2gobroker.agent.has_remote_broker_agent_setup(): + + print "This instance of X2Go Session Broker is not able to contact any remote" + print "X2Go Session Broker Agent instances. Check this broker's SSH setup!!!" + print + print "Aborting any futher tests..." + sys.exit(-1) + + if list_tasks: + print "The queried broker agent supports these tasks / features:" + print + for task in remote_agent_tasks: + try: + print " {task_name}: {task_function_obj}".format(task_name=task, task_function_obj=agent_client_tasks[task]) + except KeyError: + print " {task_name}: not supported by this broker version".format(task_name=task) + print + sys.exit(0) + + call_agent(task) diff --git a/x2gobroker/agent.py b/x2gobroker/agent.py index 183985f..7d0baca 100644 --- a/x2gobroker/agent.py +++ b/x2gobroker/agent.py @@ -35,6 +35,8 @@ import x2gobroker.defaults import x2gobroker.x2gobroker_exceptions from x2gobroker.loggers import logger_broker, logger_error +tasks = {} + class delayed_execution(threading.Thread): @@ -54,7 +56,6 @@ class delayed_execution(threading.Thread): self.agent_func(**self.kwargs) - def has_remote_broker_agent_setup(): """\ Peform some integrity checks that may indicate that a remote @@ -72,6 +73,7 @@ def has_remote_broker_agent_setup(): elif os.path.exists(os.path.join(home, '.ssh', 'id_ecdsa')): return True + def call_local_broker_agent(username, mode, cmdline_args=[]): """\ Launch X2Go Broker Agent locally and process its output. @@ -110,6 +112,7 @@ def call_local_broker_agent(username, mode, cmdline_args=[]): raise x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException('Query to local X2Go Broker Agent failed with no response') + def call_remote_broker_agent(username, mode, cmdline_args=[], remote_agent=None): """\ Launch remote X2Go Broker Agent via SSH and process its output. @@ -162,7 +165,9 @@ def call_remote_broker_agent(username, mode, cmdline_args=[], remote_agent=None) client.close() if result and result[0].startswith('OK'): return [ r for r in result[1:] if r ] - except (paramiko.SSHException, paramiko.AuthenticationException, paramiko.BadHostKeyException, socket.error): + except paramiko.AuthenticationException: + raise x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException('Authentication to remote X2Go Broker Agent Host failed (user: {user}, hostname: {hostname}, port: {port}) failed'.format(user=remote_username, hostname=remote_hostname, port=remote_port)) + except (paramiko.SSHException, paramiko.BadHostKeyException, socket.error): raise x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException('Query to remote X2Go Broker Agent (user: {user}, hostname: {hostname}, port: {port}) failed'.format(user=remote_username, hostname=remote_hostname, port=remote_port)) @@ -212,6 +217,7 @@ def ping(query_mode='LOCAL', remote_agent=None): return remote_agent is not None and \ icmp_ping(remote_agent['hostname']) and \ call_remote_broker_agent(username, mode='ping', remote_agent=remote_agent) +tasks['ping'] = ping def list_sessions(username, query_mode='LOCAL', remote_agent=None): @@ -230,6 +236,7 @@ def list_sessions(username, query_mode='LOCAL', remote_agent=None): return call_local_broker_agent(username, mode='listsessions') else: return call_remote_broker_agent(username, mode='listsessions', remote_agent=remote_agent) +tasks['listsessions'] = list_sessions def suspend_session(username, session_name, query_mode='LOCAL', remote_agent=None): @@ -248,6 +255,7 @@ def suspend_session(username, session_name, query_mode='LOCAL', remote_agent=Non return call_local_broker_agent(username, mode='suspendsession', cmdline_args=[session_name, ], ) else: return call_remote_broker_agent(username, mode='suspendsession', cmdline_args=[session_name, ], remote_agent=remote_agent) +tasks['suspendsession'] = suspend_session def terminate_session(username, session_name, query_mode='LOCAL', remote_agent=None): @@ -266,6 +274,7 @@ def terminate_session(username, session_name, query_mode='LOCAL', remote_agent=N return call_local_broker_agent(username, mode='terminatesession', cmdline_args=[session_name, ], ) else: return call_remote_broker_agent(username, mode='terminatesession', cmdline_args=[session_name, ], remote_agent=remote_agent) +tasks['terminatesession'] = terminate_session def has_sessions(username, query_mode='LOCAL', remote_agent=None): @@ -287,6 +296,7 @@ def has_sessions(username, query_mode='LOCAL', remote_agent=None): _session_list = list_sessions(username, query_mode=query_mode, remote_agent=remote_agent) return ([ s.split('|')[3] for s in _session_list if s.split('|')[4] == 'R' ], [ s.split('|')[3] for s in _session_list if s.split('|')[4] == 'S' ]) + def find_busy_servers(username, query_mode='LOCAL', remote_agent=None): """\ Query X2Go Broker Agent for a list of servers with running @@ -317,6 +327,7 @@ def find_busy_servers(username, query_mode='LOCAL', remote_agent=None): server_usage.update({ server: int(usage) }) return server_usage +tasks['findbusyservers'] = find_busy_servers def add_authorized_key(username, pubkey_hash, authorized_keys_file='%h/.x2go/authorized_keys', query_mode='LOCAL', remote_agent=None): @@ -339,6 +350,7 @@ def add_authorized_key(username, pubkey_hash, authorized_keys_file='%h/.x2go/aut return call_local_broker_agent(username, mode='addauthkey', cmdline_args=[pubkey_hash, authorized_keys_file, ]) else: return call_remote_broker_agent(username, mode='addauthkey', cmdline_args=[pubkey_hash, authorized_keys_file, ], remote_agent=remote_agent) +tasks['addauthkey'] = add_authorized_key def delete_authorized_key(username, pubkey_hash, authorized_keys_file='%h/.x2go/authorized_keys', query_mode='LOCAL', remote_agent=None, delay_deletion=0): @@ -371,6 +383,7 @@ def delete_authorized_key(username, pubkey_hash, authorized_keys_file='%h/.x2go/ return call_local_broker_agent(username, mode='delauthkey', cmdline_args=[pubkey_hash, authorized_keys_file, ]) else: return call_remote_broker_agent(username, mode='delauthkey', cmdline_args=[pubkey_hash, authorized_keys_file, ], remote_agent=remote_agent) +tasks['delauthkey'] = delete_authorized_key def get_servers(username, query_mode='LOCAL', remote_agent=None): @@ -390,7 +403,30 @@ def get_servers(username, query_mode='LOCAL', remote_agent=None): if unicode(query_mode).upper() == u'LOCAL': return call_local_broker_agent(username, mode='getservers') else: - return call_local_broker_agent(username, mode='getservers', remote_agent=remote_agent) + return call_remote_broker_agent(username, mode='getservers', remote_agent=remote_agent) +tasks['getservers'] = get_servers + + +def tasks_available(username, query_mode='LOCAL', remote_agent=None): + """\ + Query X2Go Broker Agent for the list of available tasks. + + Depending on the remove broker agent's version, the result of this + query can vary tremendously from X2Go Server to X2Go Server. + + @param username: run the query on behalf of this username + @type username: C{unicode} + @param query_mode: query mode used when calling X2Go Broker Agent (C{LOCAL} or C{SSH}) + @type query_mode: C{unicode} + @param remote_agent: information about the remote agent that is to be called. + @type remote_agent: C{dict} + + """ + if unicode(query_mode).upper() == u'LOCAL': + return call_local_broker_agent(username, mode='availabletasks') + else: + return call_remote_broker_agent(username, mode='availabletasks', remote_agent=remote_agent) +tasks['availabletasks'] = tasks_available def genkeypair(local_username, client_address, key_type='RSA'): @@ -433,3 +469,4 @@ def genkeypair(local_username, client_address, key_type='RSA'): privkey = privkey_obj.getvalue() return (pubkey, privkey) + diff --git a/x2gobroker/brokers/base_broker.py b/x2gobroker/brokers/base_broker.py index ad49ef7..0edb946 100644 --- a/x2gobroker/brokers/base_broker.py +++ b/x2gobroker/brokers/base_broker.py @@ -1044,7 +1044,11 @@ class X2GoBroker(object): # find already running/suspended sessions and resume the first one found if remote_agent and server_list and username: - session_list = x2gobroker.agent.list_sessions(username=username, query_mode=agent_query_mode, remote_agent=remote_agent) + try: + session_list = x2gobroker.agent.list_sessions(username=username, query_mode=agent_query_mode, remote_agent=remote_agent) + except x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException: + session_list = [] + if session_list: # if resuming, always select the first session in the list, there should only be one suspended session diff --git a/x2gobroker/utils.py b/x2gobroker/utils.py index 34117d5..776f380 100644 --- a/x2gobroker/utils.py +++ b/x2gobroker/utils.py @@ -169,3 +169,22 @@ def matching_hostnames(server_list_a, server_list_b): matching_hosts = list(set(server_list_a).intersection(set(server_list_b))) return matching_hosts + +def drop_privileges(uid, gid): + if os.getuid() != 0: + # We're not root so, like, whatever dude + return + + # Get the uid/gid from the name + running_uid = pwd.getpwnam(uid).pw_uid + running_gid = grp.getgrnam(gid).gr_gid + + # Remove group privileges + os.setgroups([]) + + # Try setting the new uid/gid + os.setgid(running_gid) + os.setuid(running_uid) + + # Ensure a very conservative umask + old_umask = os.umask(077) \ No newline at end of file -- Alioth's /srv/git/_hooks_/post-receive-email on /srv/git/code.x2go.org/x2gobroker.git