[X2Go-Commits] [x2gobroker] 01/01: Provide tool: x2gobroker-testagent.

git-admin at x2go.org git-admin at x2go.org
Tue Mar 18 19:23:00 CET 2014


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 at 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 at obviously-nice.de>
+# Copyright (C) 2011-2014 by Heinz-Markus Graesing <heinz-m.graesing at obviously-nice.de>
+# Copyright (C) 2012-2014 by Mike Gabriel <mike.gabriel at 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



More information about the x2go-commits mailing list