Hi all, I just pushed a new feature to the X2Go Session Broker Git repo (master branch). This feature is still work in progress, but for multi-site testing, I need the packages from the nightly builds repo. So, stay tuned... Mike On Do 26 Mär 2015 11:47:54 CET, git-admin wrote:
This is an automated email from the git hooks/post-receive script.
x2go pushed a commit to branch master in repository x2gobroker.
commit c571e891e4203eedd1b4f68346e66eb49b09c7b5 Author: Mike Gabriel <mike.gabriel@das-netzwerkteam.de> Date: Thu Mar 26 09:57:39 2015 +0100
New feature: x2gobroker-loadchecker daemon.
bin/x2gobroker-ssh | Bin 10328 -> 10328 bytes debian/control | 33 ++ debian/x2gobroker-agent.postrm | 6 +- debian/x2gobroker-authservice.postrm | 6 +- debian/x2gobroker-daemon.postrm | 6 +- debian/x2gobroker-loadchecker.default | 1 + debian/x2gobroker-loadchecker.init | 1 + debian/x2gobroker-loadchecker.install | 3 + debian/x2gobroker-loadchecker.manpages | 1 + debian/x2gobroker-loadchecker.postinst | 76 +++++ ...ervice.postrm => x2gobroker-loadchecker.postrm} | 8 +- debian/x2gobroker-loadchecker.service | 1 + debian/x2gobroker-wsgi.postrm | 6 +- defaults/python-x2gobroker.default | 3 + defaults/x2gobroker-loadchecker.default | 20 ++ etc/broker/defaults.conf | 3 + etc/broker/x2gobroker-loadchecker-logger.conf | 51 ++++ etc/x2gobroker.conf | 49 +++ init/x2gobroker-loadchecker.init | 104 +++++++ lib/x2gobroker-agent.pl | 49 +++ logrotate/x2gobroker-loadchecker | 14 + man/man8/x2gobroker-authservice.8 | 2 +- man/man8/x2gobroker-loadchecker.8 | 93 ++++++ sbin/x2gobroker-loadchecker | 319 ++++++++++++++++++++ x2gobroker-loadchecker.service | 12 + x2gobroker.spec | 119 ++++++++ x2gobroker/agent.py | 25 ++ x2gobroker/brokers/base_broker.py | 115 +++++++ x2gobroker/defaults.py | 18 ++ x2gobroker/loadchecker.py | 219 ++++++++++++++ 30 files changed, 1346 insertions(+), 17 deletions(-)
diff --git a/bin/x2gobroker-ssh b/bin/x2gobroker-ssh index 10f24a3..ad1a492 100755 Binary files a/bin/x2gobroker-ssh and b/bin/x2gobroker-ssh differ diff --git a/debian/control b/debian/control index aca8fce..1a90ed5 100644 --- a/debian/control +++ b/debian/control @@ -115,6 +115,37 @@ Description: X2Go Session Broker (PAM authentication service) This package contains the authentication service against the PAM system.
+Package: x2gobroker-loadchecker +Architecture: all +Depends:
- ${python:Depends},
- ${misc:Depends},
- adduser,
- python,
- python-argparse,
- python-setproctitle,
- python-x2gobroker (>= ${source:Version}), python-x2gobroker (<< ${source:Version}.1~), +Suggests:
- x2gobroker-daemon, +Description: X2Go Session Broker (load checker service)
- X2Go is a server based computing environment with
- session resuming
- low bandwidth support
- session brokerage support
- client side mass storage mounting support
- client side printing support
- audio support
- authentication by smartcard and USB stick
- .
- The session broker is a server tool for X2Go that tells your X2Go Client
- application in a terminal server cluster what servers and session types are
- most appropriate for the user in front of the X2Go terminal.
- .
- A session broker is most useful in load balanced X2Go server farms.
- .
- This package contains the load checker service required for broker setups
- with dynamic load balancing.
- Package: x2gobroker-daemon Architecture: all Depends: @@ -123,6 +154,8 @@ Depends: x2gobroker (>= ${source:Version}), x2gobroker (<< ${source:Version}.1~), Recommends: x2gobroker-authservice, +Suggests:
- x2gobroker-loadchecker, Description: X2Go Session Broker (standalone daemon) X2Go is a server based computing environment with
- session resuming diff --git a/debian/x2gobroker-agent.postrm b/debian/x2gobroker-agent.postrm index 0739da6..0f5c579 100755 --- a/debian/x2gobroker-agent.postrm +++ b/debian/x2gobroker-agent.postrm @@ -23,15 +23,15 @@ case "$1" in dpkg-statoverride --remove /usr/lib/x2go/x2gobroker-agent fi
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; then if dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then dpkg-statoverride --remove /var/log/x2gobroker fi rm -Rf /var/log/x2gobroker fiif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
- x2gobroker-daemon, x2gobroker-authservice, x2gobroker-wsgi)
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
- x2gobroker-daemon, x2gobroker-authservice, x2gobroker-wsgi, x2gobroker-loadchecker) getent passwd x2gobroker 1>/dev/null && deluser x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker diff --git a/debian/x2gobroker-authservice.postrm b/debian/x2gobroker-authservice.postrm index 851bfa5..6db5213 100755 --- a/debian/x2gobroker-authservice.postrm +++ b/debian/x2gobroker-authservice.postrm @@ -19,15 +19,15 @@ set -e case "$1" in purge)
/usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-agent ] ; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; then if dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then dpkg-statoverride --remove /var/log/x2gobroker fi rm -Rf /var/log/x2gobroker fiif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
- by x2gobroker-daemon, x2gobroker-agent, x2gobroker-wsgi)
/usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
- by x2gobroker-daemon, x2gobroker-agent, x2gobroker-wsgi, x2gobroker-loadchecker) getent passwd x2gobroker 1>/dev/null && deluser x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker diff --git a/debian/x2gobroker-daemon.postrm b/debian/x2gobroker-daemon.postrm index 5d76a1b..ab50ca0 100755 --- a/debian/x2gobroker-daemon.postrm +++ b/debian/x2gobroker-daemon.postrm @@ -19,15 +19,15 @@ set -e case "$1" in purge)
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; then if dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then dpkg-statoverride --remove /var/log/x2gobroker fi rm -Rf /var/log/x2gobroker fiif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
- by x2gobroker-agent, x2gobroker-authservice, x2gobroker-wsgi)
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
- by x2gobroker-agent, x2gobroker-authservice, x2gobroker-wsgi, x2gobroker-loadchecker) getent passwd x2gobroker 1>/dev/null && deluser x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker diff --git a/debian/x2gobroker-loadchecker.default b/debian/x2gobroker-loadchecker.default new file mode 120000 index 0000000..25ba295 --- /dev/null +++ b/debian/x2gobroker-loadchecker.default @@ -0,0 +1 @@ +../defaults/x2gobroker-loadchecker.default \ No newline at end of file diff --git a/debian/x2gobroker-loadchecker.init b/debian/x2gobroker-loadchecker.init new file mode 120000 index 0000000..b970565 --- /dev/null +++ b/debian/x2gobroker-loadchecker.init @@ -0,0 +1 @@ +../init/x2gobroker-loadchecker.init \ No newline at end of file diff --git a/debian/x2gobroker-loadchecker.install b/debian/x2gobroker-loadchecker.install new file mode 100644 index 0000000..769abbc --- /dev/null +++ b/debian/x2gobroker-loadchecker.install @@ -0,0 +1,3 @@ +sbin/x2gobroker-loadchecker usr/sbin/ +logrotate/x2gobroker-loadchecker etc/logrotate.d/ +etc/broker/x2gobroker-loadchecker-logger.conf etc/x2go/broker \ No newline at end of file diff --git a/debian/x2gobroker-loadchecker.manpages b/debian/x2gobroker-loadchecker.manpages new file mode 100644 index 0000000..1832989 --- /dev/null +++ b/debian/x2gobroker-loadchecker.manpages @@ -0,0 +1 @@ +man/man8/x2gobroker-loadchecker.8 \ No newline at end of file diff --git a/debian/x2gobroker-loadchecker.postinst b/debian/x2gobroker-loadchecker.postinst new file mode 100755 index 0000000..c2f42ce --- /dev/null +++ b/debian/x2gobroker-loadchecker.postinst @@ -0,0 +1,76 @@ +#!/bin/sh +# postinst script for x2gobroker-loadchecker +# +# see: dh_installdeb(1)
- +set -e
- +# summary of how this script can be called: +# * <postinst> `configure' <most-recently-configured-version> +# * <old-postinst> `abort-upgrade' <new version> +# * <conflictor's-postinst> `abort-remove' `in-favour' <package> +# <new-version> +# * <postinst> `abort-remove' +# * <deconfigured's-postinst> `abort-deconfigure' `in-favour' +# <failed-install-package> <version> `removing' +# <conflicting-package> <version> +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package
- +case "$1" in
- configure)
# setup user/group x2gobroker
if ! getent group x2gobroker 1>/dev/null; then
else
fi
if ! getent passwd x2gobroker 1>/dev/null; then
else
- 2>/dev/null; then
- 2>/dev/null; then
fi
# the x2gobroker-daemon needs special permissions on its log directory
if ! dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then
fi
/var/log/x2gobroker && chmod 2755 /var/log/x2gobrokermkdir -p /var/log/x2gobroker && chown x2gobroker:adm
/var/log/x2gobroker/authservice.logtouch /var/log/x2gobroker/authservice.log && chown x2gobroker:adm
/var/log/x2gobroker/error.logtouch /var/log/x2gobroker/error.log && chown x2gobroker:adm
;;
- abort-upgrade|abort-remove|abort-deconfigure)
;;
- *)
echo "postinst called with unknown argument \`$1'" 1>&2
exit 1
+esac;;
- +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts.
- +#DEBHELPER#
- +exit 0 diff --git a/debian/x2gobroker-authservice.postrm b/debian/x2gobroker-loadchecker.postrm similarity index 86% copy from debian/x2gobroker-authservice.postrm copy to debian/x2gobroker-loadchecker.postrm index 851bfa5..588f3a1 100755 --- a/debian/x2gobroker-authservice.postrm +++ b/debian/x2gobroker-loadchecker.postrm @@ -1,5 +1,5 @@ #! /bin/sh -# postrm script for x2gobroker-authservice +# postrm script for x2gobroker-loadchecker
# see: dh_installdeb(1) # summary of how this script can be called: @@ -19,15 +19,15 @@ set -e case "$1" in purge)
/usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-agent ] ; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-authservice ]; then if dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then dpkg-statoverride --remove /var/log/x2gobroker fi rm -Rf /var/log/x2gobroker fiif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ]; thenif [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
- by x2gobroker-daemon, x2gobroker-agent, x2gobroker-wsgi)
if [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d
/usr/share/doc/x2gobroker-agent ] && [ ! -d /usr/share/doc/x2gobroker-wsgi ] && [ ! -d /usr/share/doc/x2gobroker-authservice ]; then
by x2gobroker-daemon, x2gobroker-agent, x2gobroker-wsgi, x2gobroker-authservice) getent passwd x2gobroker 1>/dev/null && deluser x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker diff --git a/debian/x2gobroker-loadchecker.service b/debian/x2gobroker-loadchecker.service new file mode 120000 index 0000000..426059a --- /dev/null +++ b/debian/x2gobroker-loadchecker.service @@ -0,0 +1 @@ +../x2gobroker-authservice.service \ No newline at end of file diff --git a/debian/x2gobroker-wsgi.postrm b/debian/x2gobroker-wsgi.postrm index 4c7c120..1299a7a 100755 --- a/debian/x2gobroker-wsgi.postrm +++ b/debian/x2gobroker-wsgi.postrm @@ -35,15 +35,15 @@ case "$1" in
apacheconf_remove
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-daemon ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; then if dpkg-statoverride --list /var/log/x2gobroker 1>/dev/null; then dpkg-statoverride --remove /var/log/x2gobroker fi rm -Rf /var/log/x2gobroker fiif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-daemon ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
- by x2gobroker-agent, x2gobroker-authservice, x2gobroker-daemon)
/usr/share/doc/x2gobroker-authservice ] && [ ! -d /usr/share/doc/x2gobroker-daemon ] && [ ! -d /usr/share/doc/x2gobroker-loadchecker ]; thenif [ ! -d /usr/share/doc/x2gobroker-agent ] && [ ! -d
- by x2gobroker-agent, x2gobroker-authservice, x2gobroker-daemon, x2gobroker-loadchecker) getent passwd x2gobroker 1>/dev/null && deluser x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker getent group x2gobroker 1>/dev/null && delgroup x2gobroker diff --git a/defaults/python-x2gobroker.default b/defaults/python-x2gobroker.default index 73ee9ac..d31c113 100644 --- a/defaults/python-x2gobroker.default +++ b/defaults/python-x2gobroker.default @@ -37,3 +37,6 @@
The unix socket file for communication between the broker and the
authentication service. #X2GOBROKER_AUTHSERVICE_SOCKET=/run/x2gobroker/x2gobroker-authservice.socket + +# The unix socket file for communication between the broker and the authentication service. +#X2GOBROKER_LOADCHECKER_SOCKET=/run/x2gobroker/x2gobroker-loadchecker.socket diff --git a/defaults/x2gobroker-loadchecker.default b/defaults/x2gobroker-loadchecker.default new file mode 100644 index 0000000..b5bcd3e --- /dev/null +++ b/defaults/x2gobroker-loadchecker.default @@ -0,0 +1,20 @@ +# X2Go Session Broker (Load Checker Service) configuration +# SystemV-like init systems + +# For PAM authentication the X2Go Session Broker needs its authentication +# service. The session broker itself runs as a non-privileged user (see below) +# whereas the authentication service must run as super-user root. +# +# If you do not use PAM as authentication mechanism with the X2Go Session Broker, +# you can disable the authentication service here. +START_LOADCHECKER=false + +# Control debug mode (0=disable, 1=enable) of the X2Go Broker Authentication +# Service. +# +# Logging is (by default) written to /var/log/x2gobroker/*log. +# +# This option can also be configured in /etc/default/python-x2go. +# The value configured here overrides the value from python-x2go +# defaults and only sets the x2gobroker-authservice into debug mode. +#X2GOBROKER_DEBUG=0 diff --git a/etc/broker/defaults.conf b/etc/broker/defaults.conf index 01ca667..38dfc2d 100644 --- a/etc/broker/defaults.conf +++ b/etc/broker/defaults.conf @@ -35,6 +35,9 @@ # The unix socket file for communication between the broker and the authentication service. #X2GOBROKER_AUTHSERVICE_SOCKET=/run/x2gobroker/x2gobroker-authservice.socket
+# The unix socket file for communication between the broker and the authentication service. +#X2GOBROKER_LOADCHECKER_SOCKET=/run/x2gobroker/x2gobroker-loadchecker.socket + [daemon] # X2Go Session Broker configuration for Debian
diff --git a/etc/broker/x2gobroker-loadchecker-logger.conf b/etc/broker/x2gobroker-loadchecker-logger.conf new file mode 100644 index 0000000..e18a143 --- /dev/null +++ b/etc/broker/x2gobroker-loadchecker-logger.conf @@ -0,0 +1,51 @@ +# This file is part of the X2Go Project - http://www.x2go.org +# Copyright (C) 2012-2015 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. + +# WARNING: only modify this file if you _exactly_ know what you are doing!!! + +[loggers] +keys=root,loadchecker + +[logger_root] +level=NOTSET +handlers=stderrHandler + +[handlers] +keys=stderrHandler,loadcheckerFileHandler + +[formatters] +keys=loadcheckerFormatter + +[handler_stderrHandler] +class=StreamHandler +args=(sys.stderr,) + +[logger_loadchecker] +level=DEBUG +handlers=loadcheckerFileHandler +qualname=loadchecker +propagate=0 + +[handler_loadcheckerFileHandler] +class=FileHandler +formatter=loadcheckerFormatter +args=('/var/log/x2gobroker/loadchecker.log',) + +[formatter_loadcheckerFormatter] +format=%(asctime)s - %(name)s - %(levelname)s - %(message)s +datefmt= diff --git a/etc/x2gobroker.conf b/etc/x2gobroker.conf index 1901673..8d57ae1 100644 --- a/etc/x2gobroker.conf +++ b/etc/x2gobroker.conf @@ -247,6 +247,53 @@ # false in the session profile configuration). #default-portscan-x2goservers = true
+# Use load checker for querying X2Go Servers' loads in regular intervals +# +# When load-balancing shall be used, the simplest way to detect "server load" +# is counting the numbers of running and suspended sessions. No extra daemon +# nor service is required for this. +# +# However, simply counting running and suspended sessions per X2Go Server +# as a representative for the server load can be highly inaccurate. A better +# approach is checking each X2Go Server's load in regular intervals by a +# separate daemon (running on the broker host) and querying this load checker +# service before selecting the best server on session startup requests. +# +# The load factor calculation uses this algorithm: +# +# ( memAvail/1000 ) * numCPUs * typeCPUs +# load-factor = -------------------------------------- +# loadavg*100 * numSessions +# +# (memAvail in MByte, typeCPUs in MHz) +# +# The higher the load-factor, the more likely that a server will be chosen +# for the next to be allocated X2Go session. +# +# If you set the default-use-load-checker option here, the queries to the +# x2gobroker-loadchecker daemon will be performed for all broker backends by +# defaults. +# +# The x2gobroker-loadchecker only gets consulted, if: +# +# o if enabled here for all backends +# o or if enabled on a per broker backend basis (see below) +# +# and +# +# o the session profile defines more than one host +# o the session profile does not block queries to the load checker daemon +# on a per profile basis +# +#default-use-load-checker = false + +# If the x2gobroker-loadchecker daemon gets used, define here how +# many seconds to sleep between querying system load from the +# associated X2Go Servers. +# +#load-checker-intervals = 300 + + ### ### Auth Mechs section ### @@ -291,6 +338,7 @@ [broker_inifile] #enable = true #session-profiles = /etc/x2go/broker/x2gobroker-sessionprofiles.conf +#use-load-checker = false
#[broker_ldap] -> MUSIC OF THE FUTURE #enable = false @@ -304,4 +352,5 @@ #group-search-filter = (&(objectClass=posifxGroup)(cn=*)) #starttls = false #agent-query-mode = SSH +#use-load-checker = true
diff --git a/init/x2gobroker-loadchecker.init b/init/x2gobroker-loadchecker.init new file mode 100755 index 0000000..de8f2d0 --- /dev/null +++ b/init/x2gobroker-loadchecker.init @@ -0,0 +1,104 @@ +#!/bin/sh +# +# Start the X2Go Session Broker PAM Authentication Service +# +# Copyright © 2014 Mike Gabriel <mike.gabriel@das-netzwerkteam.de> +# Distributable under the terms of the GNU AGPL version 3+. +# +### BEGIN INIT INFO +# Provides: x2gobroker-loadchecker +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: X2Go Session Broker PAM Authentication Service +# Description: PAM authentication service for X2Go Session Broker +### END INIT INFO +# + +set -eu + +LOADCHECKER=/usr/sbin/x2gobroker-loadchecker +test -d /run && RUNDIR=/run || RUNDIR=/var/run +PIDFILE_LOADCHECKER=$RUNDIR/x2gobroker/x2gobroker-loadchecker.pid +DEBIANCONFIG_COMMON=/etc/default/python-x2gobroker +DEBIANCONFIG_LOADCHECKER=/etc/default/x2gobroker-loadchecker + +test -x "$LOADCHECKER" || exit 0 + +START_LOADCHECKER=false +X2GOBROKER_DEBUG=0 +X2GOBROKER_DAEMON_USER='x2gobroker' +X2GOBROKER_DAEMON_GROUP='x2gobroker' +X2GOBROKER_LOADCHECKER_SOCKET="$RUNDIR/x2gobroker/x2gobroker-loadchecker.socket" +test -f $DEBIANCONFIG_COMMON && . $DEBIANCONFIG_COMMON +test -f $DEBIANCONFIG_LOADCHECKER && . $DEBIANCONFIG_LOADCHECKER + +if ! getent passwd $X2GOBROKER_DAEMON_USER 1>/dev/null 2>/dev/null; then
- X2GOBROKER_DAEMON_USER=nobody +fi +if ! getent group $X2GOBROKER_DAEMON_GROUP 1>/dev/null 2>/dev/null; then
- X2GOBROKER_DAEMON_GROUP=nogroup +fi
- +# create PID directory +mkdir -p $RUNDIR/x2gobroker +chown $X2GOBROKER_DAEMON_USER:$X2GOBROKER_DAEMON_GROUP $RUNDIR/x2gobroker +chmod 0770 $RUNDIR/x2gobroker
- +export X2GOBROKER_DEBUG +export X2GOBROKER_DAEMON_USER +export X2GOBROKER_DAEMON_GROUP +export X2GOBROKER_LOADCHECKER_SOCKET
- +. /lib/lsb/init-functions
- +is_true() +{
- case "${1:-}" in
[Yy]es|[Yy]|1|[Tt]|[Tt]rue) return 0;;
*) return 1;
- esac +}
- +case "${1:-}" in
- start)
if [ -f $PIDFILE_LOADCHECKER ]; then
- $LOADCHECKER).*$X2GOBROKER_LOADCHECKER_SOCKET.*" 1>/dev/null 2>/dev/null; then
- file ($PIDFILE_LOADCHECKER). Delete it manually!"
fi
if is_true $START_LOADCHECKER; then
- does not exist
- "$(basename $LOADCHECKER)"
- $LOADCHECKER -- -s $X2GOBROKER_LOADCHECKER_SOCKET -o $X2GOBROKER_DAEMON_USER -g $X2GOBROKER_DAEMON_GROUP -p 0660
fi
- ;;
- stop)
if [ -f $PIDFILE_LOADCHECKER ] ; then
- "$(basename $LOADCHECKER)"
- $PIDFILE_LOADCHECKER
fi
- ;;
- restart|reload|force-reload)
${0:-} stop
${0:-} start
- ;;
- *)
echo "Usage: ${0:-} {start|stop|restart|reload|force-reload}" >&2
exit 1
+esac;;
- +exit 0 diff --git a/lib/x2gobroker-agent.pl b/lib/x2gobroker-agent.pl index 242f78a..9463018 100755 --- a/lib/x2gobroker-agent.pl +++ b/lib/x2gobroker-agent.pl @@ -36,6 +36,7 @@ if ( system("x2goversion x2goserver 1>/dev/null") == 0 ) "listsessions", "findbusyservers", "findbusyservers_by_sessionstats",
@@ -133,6 +134,54 @@ if($mode eq 'ping') exit; }"checkload", "getservers", "suspendsession", "terminatesession",
+if ( $mode eq 'checkload' ) { through a
- print "OK\n";
- # Read the values from /proc/loadavg and combine all three values in a linear
# way and make a percent value out of the result:
- open FILE, "< /proc/loadavg" or die return ("Cannot open /proc/loadavg: $!");
- my ($avg1, $avg5, $avg15, undef, undef) = split / /, <FILE>;
- close FILE;
- my $loadavgXX = ( $avg1 + $avg5 + $avg15 ) * 100/3;
- if ( $loadavgXX == 0 ) {
# load may not be ZERO
$loadavgXX = 1;
- }
- # calculate total memory vs. free memory
my $memAvail;
- open FILE, "< /proc/meminfo" or die return ("Cannot open /proc/meminfo: $!");
- foreach(<FILE>) {
if ( m/^MemAvailable:\s+(\S+)/ ) {
last;
}
- }
- close(FILE);
- # check number and type of available CPU cores
- my $numCPU = 0;
- my $typeCPU;
- open FILE, "< /proc/cpuinfo" or die return ("Cannot open /proc/cpuinfo: $!");
- foreach(<FILE>) {
if ( m/model name.*CPU\ \@\ ([\d\.]+)/ ) {
}
- }
- close(FILE);
- print sprintf 'loadavgXX:%1$d', $loadavgXX;
- print "\n";
- print sprintf 'memAvail:%1$d', $memAvail;
- print "\n";
- print sprintf 'numCPU:%1$d', $numCPU;
- print "\n";
- print sprintf 'typeCPU:%1$d', $typeCPU;
- print "\n";
- exit; +}
- if($mode eq 'availabletasks') { print "OK\n"; diff --git a/logrotate/x2gobroker-loadchecker b/logrotate/x2gobroker-loadchecker new file mode 100644 index 0000000..e5c8c65 --- /dev/null +++ b/logrotate/x2gobroker-loadchecker @@ -0,0 +1,14 @@ +/var/log/x2gobroker/loadchecker.log {
- weekly
- missingok
- rotate 52
- compress
- delaycompress
- notifempty
- create 640 root adm
- su root adm
- sharedscripts
- postrotate
invoke-rc.d x2gobroker-loadchecker restart > /dev/null
- endscript +} diff --git a/man/man8/x2gobroker-authservice.8 b/man/man8/x2gobroker-authservice.8 index eff8569..8981ee6 100644 --- a/man/man8/x2gobroker-authservice.8 +++ b/man/man8/x2gobroker-authservice.8 @@ -31,7 +31,7 @@ Thus, the PAM authentication has been moved into a separate service. The communi between X2Go Session Broker and PAM Authentication Service is handled through a unix domain socket file (\fI<RUNDIR>/x2gobroker/x2gobroker-authservice.socket\fR). .PP -This command is normally started through an init script. +This command is normally started through the host's init system. .SH COMMON OPTIONS \fBx2gobroker-authservice\fR accepts the following common options: .TP diff --git a/man/man8/x2gobroker-loadchecker.8 b/man/man8/x2gobroker-loadchecker.8 new file mode 100644 index 0000000..f025f5e --- /dev/null +++ b/man/man8/x2gobroker-loadchecker.8 @@ -0,0 +1,93 @@ +'\" -*- coding: utf-8 -*- +.if \n(.g .ds T< \\FC +.if \n(.g .ds T> \\F[\n[.fam]] +.de URL +\\$2 \(la\\$1\(ra\\$3 +.. +.if \n(.g .mso www.tmac +.TH x2gobroker-loadchecker 8 "Mar 2015" "Version 0.0.3.x" "X2Go Session Broker" +.SH NAME +x2gobroker-loadchecker \- Load checker service for X2Go Session Broker +.SH SYNOPSIS +'nh +.fi +.ad l +\fBx2gobroker-loadchecker\fR \kx +.if (\nx>(\n(.l/2)) .nr x (\n(.l/5) +'in \n(.iu+\nxu +[ +\fIoptions\fR +] +'in \n(.iu-\nxu +.ad b +'hy +.SH DESCRIPTION +\fBx2gobroker-loadchecker\fR is a service that collects system load metrics from +broker-associated X2Go Servers. +.PP +When load-balancing shall be used, the simplest way to detect "server load" +is counting the numbers of running and suspended sessions. No extra daemon +nor service is required for this. The server with the least amount of sessions +will be selected for starting the next X2Go session. +.PP +However, simply counting running and suspended sessions per X2Go Server +as a representative for the server load can be highly inaccurate. A better +approach is checking each X2Go Server's load in regular intervals by the +\fBx2gobroker-loadchecker\fR daemon (running on the broker host) and querying +the \fBx2gobroker-loadchecker\fR daemon before selecting the best server on +session startup requests. +.PP +The \fBx2gobroker-loadchecker\fR collects server metrics of all +associated X2Go Servers and keeps the latest load factors in RAM. Once +the broker needs load factors of a certain session profile (i.e., of all +servers configured in that session profile), the +\fBx2gobroker-loadchecker\fR delivers that info immediately. The +remembered load factors may not be 100% up-to-date (default: collected +within the last five minutes), but the response time of the load checker +is much faster than a query to all possible X2Go Servers would be. +.PP +The load factor calculation uses this algorithm: +.PP
( memAvail[MByte]/1000 ) * numCPUs * typeCPUs[MHz]
- load-factor = --------------------------------------------------
+.PP +The higher the load-factor, the more likely that a server will be chosen +for the next to be allocated X2Go session. +.PP +The communication +between X2Go Session Broker and the Load Checker Service is handledloadavg*100 * numSessions
+unix domain socket file (\fI<RUNDIR>/x2gobroker/x2gobroker-loadchecker.socket\fR). +.PP +This command is normally started through the host's init system. +.SH COMMON OPTIONS +\fBx2gobroker-loadchecker\fR accepts the following common options: +.TP +\*(T<\fB\-h, \-\-help\fR\*(T> +Display a help with all available command line options and exit. +.TP +\*(T<\fB\-D, \-\-daemonize\fR\*(T> +Fork this application to background and detach from the running terminal. +.TP +\*(T<\fB\-P, \-\-pidfile\fR\*(T> +Custom PID file location when daemonizing (default: \fI<RUNDIR>/x2gobroker/x2gobroker-loadchecker.pid\fR). +.TP +\*(T<\fB\-L, \-\-logdir\fR\*(T> +Directory where stdout/stderr will be redirected after having daemonized (default: \fI/var/log/x2gobroker/\fR). +.TP +\*(T<\fB\-s <LOADCHECKERSOCKET>, \-\-socket <LOADCHECKERSOCKET>\fR\*(T> +File name of the unix domain socket file used for communication between broker and load checker service. +.TP +\*(T<\fB\-o <OWNER>, \-\-owner <OWNER>\fR\*(T> +User ownership of the \fI<LOADCHECKERSOCKET>\fR file. +.TP +\*(T<\fB\-g <GROUP>, \-\-group <GROUP>\fR\*(T> +Group ownership of the \fI<LOADCHECKERSOCKET>\fR file. +.TP +\*(T<\fB\-p <PERMISSIONS>, \-\-permissions <PERMISSIONS>\fR\*(T> +Set these file permissions for the \fI<LOADCHECKERSOCKET>\fR file. Use numerical permissions (e.g. 0640). +.SH "FILES" +<RUNDIR>/x2gobroker/x2gobroker-loadchecker.socket +.SH AUTHOR +This manual has been written for the X2Go project by +Mike Gabriel <mike.gabriel@das-netzwerkteam.de>. diff --git a/sbin/x2gobroker-loadchecker b/sbin/x2gobroker-loadchecker new file mode 100755 index 0000000..8d6ae32 --- /dev/null +++ b/sbin/x2gobroker-loadchecker @@ -0,0 +1,319 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# This file is part of the X2Go Project - http://www.x2go.org +# Copyright (C) 2012-2015 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 +import asyncore +import socket +import getpass +import logging.config +import atexit +import ConfigParser + +if os.path.isdir('/run'): profile_id, hostname)
- RUNDIR = '/run' +else:
- RUNDIR = '/var/run'
- +try:
- import daemon
- import lockfile
- CAN_DAEMONIZE = True
- pidfile = '{run}/x2gobroker/x2gobroker-loadchecker.pid'.format(run=RUNDIR)
- daemon_logdir = '/var/log/x2gobroker/' +except ImportError:
- CAN_DAEMONIZE = False
- +from pwd import getpwnam +from grp import getgrnam
- +PROG_NAME = os.path.basename(sys.argv[0]) +PROG_OPTIONS = sys.argv[1:] +setproctitle.setproctitle("%s %s" % (PROG_NAME, " ".join(PROG_OPTIONS)))
- +from x2gobroker import __VERSION__ +from x2gobroker import __AUTHOR__ +import x2gobroker.loadchecker
- +global load_checker
- +class LoadCheckerServiceHandler(asyncore.dispatcher_with_send):
- def __init__(self, sock, logger=None):
self.logger = logger
asyncore.dispatcher_with_send.__init__(self, sock)
self._buf = ''
- def handle_read(self):
data = self._buf + self.recv(1024)
if not data:
self.close()
return
reqs, data = data.rsplit('\n', 1)
self._buf = data
output = ""
for req in reqs.split('\n'):
backend, profile_id, hostname = req.split('\r')
self.logger.debug('LoadCheckServiceHandler.handle_read(): received load check query: backend={backend}, profile_id={profile_id}, hostname={hostname}'.format(backend=backend, profile_id=profile_id, hostname=hostname))if self.logger:
if hostname:
load_factor = load_checker.get_server_load(backend,
if load_factor is not None:
output += "{lf}".format(lf=load_factor)
self.logger.info('LoadCheckServiceHandler.handle_read(): load check result for backend={backend}, profile_id={profile_id}, hostname={hostname}: {lf}'.format(backend=backend, profile_id=profile_id, hostname=hostname, lf=load_factor))if self.logger:
else:
output += "LOAD-UNAVAILABLE"
self.logger.warning('LoadCheckServiceHandler.handle_read(): load check failure for backend={backend}, profile_id={profile_id}, hostname={hostname}: LOAD-UNAVAILABLE'.format(backend=backend, profile_id=profile_id, hostname=hostname))if self.logger:
else:
load_checker.get_profile_load(backend, profile_id)load_factors =
if load_factors:
for h in load_factors.keys():
if load_factors[h] is not None:
+="{hostname}:{loadfactor}".format(hostname=h, loadfactor=load_factors[h])output
self.logger.info('LoadCheckServiceHandler.handle_read(): load check result for backend={backend}, profile_id={profile_id}, hostname={hostname}: {lf}'.format(backend=backend, profile_id=profile_id, hostname=h, lf=load_factors[h]))if self.logger:
else:
"{hostname}:LOAD-UNAVAILABLE".formate(hostname=h)output +=
self.logger.warning('LoadCheckServiceHandler.handle_read(): load check failure for backend={backend}, profile_id={profile_id}, hostname={hostname}: LOAD-UNAVAILABLE'.format(backend=backend, profile_id=profile_id, hostname=h))if self.logger:
else:
output += "LOAD-UNAVAILABLE"
self.logger.warning('LoadCheckServiceHandler.handle_read(): load check failure for backend={backend}, profile_id={profile_id}: LOAD-UNAVAILABLE'.format(backend=backend, profile_id=profile_id))if self.logger:
self.send(output)
- def handle_close(self):
self.close()
- +class LoadCheckerService(asyncore.dispatcher_with_send):
- def __init__(self, socketfile, owner='root', group_owner='root', permissions='0660', logger=None):
self.logger = logger
asyncore.dispatcher_with_send.__init__(self)
self.create_socket(socket.AF_UNIX, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(socketfile)
getgrnam(group_owner).gr_gid)os.chown(socketfile, getpwnam(owner).pw_uid,
os.chmod(socketfile, int(permissions, 8))
self.listen(1)
- def handle_accept(self):
conn, _ = self.accept()
LoadCheckerServiceHandler(conn, logger=self.logger)
- +def loop():
- ### the "loop" has two tasks...
- # 1. Do regular queries to remote X2Go Broker Agent instances to collect
- # load average, CPU usage and type, memory usage, etc.
- load_checker.start()
- # 2. Provide a listening UNIX domain socket file that can be used for querying
- # server states.
- asyncore.loop()
- +def cleanup_on_exit():
- os.remove(X2GOBROKER_LOADCHECKER_SOCKET)
- try: os.remove(pidfile)
- except: pass
- +# load the defaults.conf file, if present +iniconfig_loaded = None +iniconfig_section = '-'.join(PROG_NAME.split('-')[1:]) +X2GOBROKER_DEFAULTS = "/etc/x2go/broker/defaults.conf" +if os.path.isfile(X2GOBROKER_DEFAULTS) and os.access(X2GOBROKER_DEFAULTS, os.R_OK):
- iniconfig = ConfigParser.SafeConfigParser()
- iniconfig.optionxform = str
- iniconfig_loaded = iniconfig.read(X2GOBROKER_DEFAULTS)
- +# normally this would go into defaults.py, however, we do not want to pull in defaults.py here as that will create +# unwanted logfiles (access.log, broker.log, error.log) when x2gobroker-loadchecker is installed as standalone service +if os.environ.has_key('X2GOBROKER_DEBUG'):
- X2GOBROKER_DEBUG = ( os.environ['X2GOBROKER_DEBUG'].lower() in ('1', 'on', 'true', 'yes', ) ) +elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_DEBUG'):
- X2GOBROKER_DEBUG=iniconfig.get(iniconfig_section, 'X2GOBROKER_DEBUG') +elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_DEBUG'):
- X2GOBROKER_DEBUG=iniconfig.get('common', 'X2GOBROKER_DEBUG') +else:
- X2GOBROKER_DEBUG = False
- +if os.environ.has_key('X2GOBROKER_DAEMON_USER'):
- X2GOBROKER_DAEMON_USER=os.environ['X2GOBROKER_DAEMON_USER'] +elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_DAEMON_USER'):
- X2GOBROKER_DAEMON_USER=iniconfig.get(iniconfig_section, 'X2GOBROKER_DAEMON_USER') +elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_DAEMON_USER'):
- X2GOBROKER_DAEMON_USER=iniconfig.get('common', 'X2GOBROKER_DAEMON_USER') +else:
- X2GOBROKER_DAEMON_USER="x2gobroker"
- +if os.environ.has_key('X2GOBROKER_LOADCHECKER_LOGCONFIG'):
- X2GOBROKER_LOADCHECKER_LOGCONFIG=os.environ['X2GOBROKER_LOADCHECKER_LOGCONFIG'] +elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_LOADCHECKER_LOGCONFIG'):
- X2GOBROKER_LOADCHECKER_LOGCONFIG=iniconfig.get(iniconfig_section, 'X2GOBROKER_LOADCHECKER_LOGCONFIG') +elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_LOADCHECKER_LOGCONFIG'):
- X2GOBROKER_LOADCHECKER_LOGCONFIG=iniconfig.get('common', 'X2GOBROKER_LOADCHECKER_LOGCONFIG') +else:
- X2GOBROKER_LOADCHECKER_LOGCONFIG="/etc/x2go/broker/x2gobroker-loadchecker-logger.conf"
- +if os.environ.has_key('X2GOBROKER_LOADCHECKER_SOCKET'):
- X2GOBROKER_LOADCHECKER_SOCKET=os.environ['X2GOBROKER_LOADCHECKER_SOCKET'] +elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_LOADCHECKER_SOCKET'):
- X2GOBROKER_LOADCHECKER_SOCKET=iniconfig.get(iniconfig_section, 'X2GOBROKER_LOADCHECKER_SOCKET') +elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_LOADCHECKER_SOCKET'):
- X2GOBROKER_LOADCHECKER_SOCKET=iniconfig.get('common', 'X2GOBROKER_LOADCHECKER_SOCKET') +else:
- X2GOBROKER_LOADCHECKER_SOCKET="{run}/x2gobroker/x2gobroker-loadchecker.socket".format(run=RUNDIR)
- +if __name__ == '__main__':
- common_options = [
X2GOBROKER_LOADCHECKER_SOCKET, 'metavar': 'LOADCHECKERSOCKET', 'help': 'socket file for LoadChecker communication', },{'args':['-s','--socket-file'], 'default':
of the LoadChecker socket file', },{'args':['-o','--owner'], 'default': 'root', 'help': 'owner
ownership of the LoadChecker socket file', },{'args':['-g','--group'], 'default': 'root', 'help': 'group
'set these file permissions for the LoadChecker socket file', },{'args':['-p','--permissions'], 'default': '0660', 'help':
'store_true', 'help': 'enable debugging code', },{'args':['-d','--debug'], 'default': False, 'action':
'action': 'store_true', 'help': 'force output of log message to the stderr (rather than to the log files)', },{'args':['-i','--debug-interactively'], 'default': False,
- ]
- if CAN_DAEMONIZE:
common_options.extend([
'action': 'store_true', 'help': 'Detach the X2Go Broker process from the current terminal and fork to background', },{'args':['-D', '--daemonize'], 'default': False,
'help': 'Alternative file path for the daemon\'s PID file', },{'args':['-P', '--pidfile'], 'default': pidfile,
'help': 'Directory where log files for the process\'s stdout and stderr can be created', },{'args':['-L', '--logdir'], 'default': daemon_logdir,
])
- p = argparse.ArgumentParser(description='X2Go Session Broker (Load Checker Service)',\
- formatter_class=argparse.RawDescriptionHelpFormatter, \
add_help=True, argument_default=None)
- p_common = p.add_argument_group('common parameters')
- for (p_group, opts) in ( (p_common, common_options), ):
for opt in opts:
args = opt['args']
del opt['args']
p_group.add_argument(*args, **opt)
- cmdline_args = p.parse_args()
- # standalone daemon mode (x2gobroker-loadchecker as daemon) or interactive mode (called from the cmdline)?
- if getpass.getuser() in (X2GOBROKER_DAEMON_USER, 'root') and not cmdline_args.debug_interactively:
configuration for logging# we run in standalone daemon mode, so let's use the system
logging.config.fileConfig(X2GOBROKER_LOADCHECKER_LOGCONFIG)
# create loadchecker logger
logger_loadchecker = logging.getLogger('loadchecker')
- else:
logger_root = logging.getLogger()
stderr_handler = logging.StreamHandler(sys.stderr)
- stderr_handler.setFormatter(logging.Formatter(fmt='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt=''))
# all loggers stream to stderr...
logger_root.addHandler(stderr_handler)
logger_loadchecker = logging.getLogger('loadchecker')
logger_loadchecker.addHandler(stderr_handler)
logger_loadchecker.propagate = 0
- if cmdline_args.debug_interactively:
cmdline_args.debug = True
- # raise log level to DEBUG if requested...
- if cmdline_args.debug or X2GOBROKER_DEBUG:
X2GOBROKER_DEBUG = True
logger_loadchecker.setLevel(logging.DEBUG)
- logger_loadchecker.info('X2Go Session Broker ({version}), written by {author}'.format(version=__VERSION__, author=__AUTHOR__))
- logger_loadchecker.info('Setting up the Load Checker service\'s environment...')
- logger_loadchecker.info(' X2GOBROKER_DEBUG: {value}'.format(value=X2GOBROKER_DEBUG))
- logger_loadchecker.info(' X2GOBROKER_LOADCHECKER_SOCKET: {value}'.format(value=X2GOBROKER_LOADCHECKER_SOCKET))
- load_checker = x2gobroker.loadchecker.LoadChecker(logger=logger_loadchecker)
- if CAN_DAEMONIZE and cmdline_args.daemonize:
# create directory for the PID file
pidfile = os.path.expanduser(cmdline_args.pidfile)
if not os.path.isdir(os.path.dirname(pidfile)):
try:
os.makedirs(os.path.dirname(pidfile))
except:
pass
(os.path.exists(pidfile) and not os.access(pidfile, os.W_OK)):if not os.access(os.path.dirname(pidfile), os.W_OK) or
print("")
p.print_usage()
{pidfile} path".format(pidfile=pidfile))print("Insufficent privileges. Cannot create PID file
print("")
sys.exit(-3)
# create directory for logging
daemon_logdir = os.path.expanduser(cmdline_args.logdir)
if not os.path.isdir(daemon_logdir):
try:
os.makedirs(daemon_logdir)
except:
pass
if not os.access(daemon_logdir, os.W_OK):
print("")
p.print_usage()
for stdout/stderr log files: {logdir}".format(logdir=daemon_logdir))print("Insufficent privileges. Cannot create directory
print("")
sys.exit(-3)
else:
if not daemon_logdir.endswith('/'):
daemon_logdir += '/'
- socket_file = cmdline_args.socket_file
- if os.path.exists(socket_file):
os.remove(socket_file)
- if not os.path.exists(os.path.dirname(socket_file)):
os.makedirs(os.path.dirname(socket_file))
- runtimedir_permissions = int(cmdline_args.permissions, 8)
- if runtimedir_permissions & 0400: runtimedir_permissions = runtimedir_permissions | 0100
- if runtimedir_permissions & 0040: runtimedir_permissions = runtimedir_permissions | 0010
- if runtimedir_permissions & 0004: runtimedir_permissions = runtimedir_permissions | 0001
- try:
getpwnam(cmdline_args.owner).pw_uid, getpwnam(cmdline_args.group).pw_gid)os.chown(os.path.dirname(socket_file),
os.chmod(os.path.dirname(socket_file), runtimedir_permissions)
- except OSError:
pass
- LoadCheckerService(socket_file, owner=cmdline_args.owner, group_owner=cmdline_args.group, permissions=cmdline_args.permissions, logger=logger_loadchecker)
- atexit.register(cleanup_on_exit)
- try:
if CAN_DAEMONIZE and cmdline_args.daemonize:
os.listdir('/proc/self/fd') if fd not in (0,1,2) ]keep_fds = [int(fd) for fd in
file(daemon_logdir+'x2gobroker-loadchecker.stdout', 'w+')daemon_stdout =
file(daemon_logdir+'x2gobroker-loadchecker.stderr', 'w+')daemon_stderr =
stderr=daemon_stderr, files_preserve=keep_fds, umask=0o027, pidfile=lockfile.FileLock(pidfile), detach_process=True):with daemon.DaemonContext(stdout=daemon_stdout,
file(pidfile, 'w+').write(str(os.getpid())+"\n")
loop()
else:
loop()
- except KeyboardInterrupt:
diff --git a/x2gobroker-loadchecker.service b/x2gobroker-loadchecker.service new file mode 100644 index 0000000..692e15f --- /dev/null +++ b/x2gobroker-loadchecker.service @@ -0,0 +1,12 @@ +[Unit] +Description=X2Go Session Broker Load Checker Servicepass
- +[Service] +User=root +Group=root +Type=forking +ExecStart=/usr/sbin/x2gobroker-loadchecker --socket-file=/run/x2gobroker/x2gobroker-loadchecker.socket --daemonize -o root -g x2gobroker -p 0660 --pidfile=/run/x2gobroker/x2gobroker-loadchecker.pid +PIDFile=/run/x2gobroker/x2gobroker-loadchecker.pid
- +[Install] +WantedBy=multi-user.target diff --git a/x2gobroker.spec b/x2gobroker.spec index bcb398f..55b1fdb 100644 --- a/x2gobroker.spec +++ b/x2gobroker.spec @@ -14,6 +14,7 @@ Url: http://www.x2go.org/ Source0: http://code.x2go.org/releases/source/%name/%name-%version.tar.gz Source1: x2gobroker-daemon.init Source2: x2gobroker-authservice.init +Source2: x2gobroker-loadchecker.init Source3: x2gobroker-rpmlintrc
%if 0%{?el5} @@ -147,6 +148,46 @@ A session broker is most useful in load balanced X2Go server farms.
This package contains the authentication service against the PAM system.
+%package loadchecker +Summary: X2Go Session Broker (load checker service) +%if 0%{?suse_version} +Group: Productivity/Networking/Remote Desktop +%else +Group: Applications/Communications +%endif +%if 0%{?suse_version} +Requires: python +%else +Requires: python2 +%endif +Requires: python-argparse +Requires: python-setproctitle +Requires: logrotate +Requires(pre): python-x2gobroker = %{version}-%{release} +%if 0%{?suse_version} +Requires(pre): permissions +%endif + +%description loadchecker +X2Go is a server based computing environment with
- session resuming
- low bandwidth support
- session brokerage support
- client side mass storage mounting support
- client side printing support
- audio support
- authentication by smartcard and USB stick
- +The session broker is a server tool for X2Go that tells your X2Go Client +application in a terminal server cluster what servers and session types are +most appropriate for the user in front of the X2Go terminal.
- +A session broker is most useful in load balanced X2Go server farms.
- +This package contains the load checker service required for broker setups +with dynamic load balancing.
- %package daemon Summary: X2Go Session Broker (standalone daemon) %if 0%{?suse_version} @@ -346,6 +387,8 @@ grep -l -r -E '^#!/usr/bin/env python$' | while read file; do \ %endif sed -i logrotate/x2gobroker-authservice \ -e 's/adm/root/' +sed -i logrotate/x2gobroker-loadchecker \
- -e 's/adm/root/' sed -i logrotate/x2gobroker-daemon \ -e 's/adm/root/' sed -i logrotate/x2gobroker-wsgi \ @@ -379,14 +422,18 @@ ln -s "%_sysconfdir/x2go/x2gobroker-wsgi.apache.vhost" \ mkdir -p %{buildroot}%{_unitdir} install -pm0644 x2gobroker-daemon.service %{buildroot}%{_unitdir} install -pm0644 x2gobroker-authservice.service %{buildroot}%{_unitdir} +install -pm0644 x2gobroker-loadchecker.service %{buildroot}%{_unitdir} rm -f %{buildroot}%{_sysconfdir}/default/x2gobroker-daemon rm -f %{buildroot}%{_sysconfdir}/default/x2gobroker-authservice +rm -f %{buildroot}%{_sysconfdir}/default/x2gobroker-loadchecker rm -f %{buildroot}%{_sysconfdir}/default/python-x2gobroker %else
SysV session cleanup script
%if 0%{?el5} rm -f %{buildroot}%{_sysconfdir}/x2go/broker/defaults.conf mkdir -p %{buildroot}%{_initrddir} +install -pm0755 %SOURCE3 \
- "$b/%_initrddir/x2gobroker-loadchecker" install -pm0755 %SOURCE2 \ "$b/%_initrddir/x2gobroker-authservice" install -pm0755 %SOURCE1 \ @@ -395,6 +442,8 @@ install -pm0755 %SOURCE1 \ %if 0%{?el6} || ( 0%{?suse_version} && 0%{?suse_version} < 1140) rm -f %{buildroot}%{_sysconfdir}/x2go/broker/defaults.conf mkdir -p "$b/%_initddir" +install -pm0755 %SOURCE3 \
- "$b/%_initddir/x2gobroker-loadchecker" install -pm0755 %SOURCE2 \ "$b/%_initddir/x2gobroker-authservice" install -pm0755 %SOURCE1 \ @@ -480,6 +529,56 @@ fi
%if 0%{?suse_version} >= 1230 +%pre loadchecker +%service_add_pre x2gobroker-loadchecker.service +%endif + +%post loadchecker +%if 0%{?fedora} || 0%{?el7} || 0%{?suse_version} >= 1230 +%if 0%{?suse_version} +%service_add_post x2gobroker-loadchecker.service +%else +%systemd_post x2gobroker-loadchecker.service +%endif +%else +/sbin/chkconfig --add x2gobroker-loadchecker +if [ "$1" -ge "1" ] ; then
- /sbin/service x2gobroker-loadchecker condrestart >/dev/null 2>&1 || : +fi +%endif +%if 0%{?suse_version} +%set_permissions %{_localstatedir}/log/x2gobroker
- +%verifyscript loadchecker +%verify_permissions -e %{_localstatedir}/log/x2gobroker +%endif
- +%preun loadchecker +%if 0%{?fedora} || 0%{?el7} || 0%{?suse_version} >= 1230 +%if 0%{?suse_version} +%service_del_preun x2gobroker-loadchecker.service +%else +%systemd_preun x2gobroker-loadchecker.service +%endif +%else +if [ "$1" = 0 ]; then
/sbin/service x2gobroker-loadchecker stop >/dev/null 2>&1
+fi +%endif/sbin/chkconfig --del x2gobroker-loadchecker
- +%if 0%{?fedora} || 0%{?el7} || 0%{?suse_version} >= 1230 +%postun loadchecker +%if 0%{?suse_version} +%service_del_postun x2gobroker-loadchecker.service +%else +%systemd_postun x2gobroker-loadchecker.service +%endif +%endif
- +%if 0%{?suse_version} >= 1230 %pre daemon %service_add_pre x2gobroker-daemon.service %endif @@ -620,6 +719,26 @@ fi %attr(02750,x2gobroker,x2gobroker) %_localstatedir/log/x2gobroker
+%files loadchecker +%defattr(-,root,root) +%if 0%{?el5} +%_initrddir/x2gobroker-loadchecker +%endif +%if 0%{?el6} +%_initddir/x2gobroker-loadchecker +%endif +%if 0%{?fedora} || 0%{?el7} || 0%{?suse_version} >= 1230 +%{_unitdir}/x2gobroker-loadchecker.service +%endif +%if 0%{?el5} || 0%{?el6} || (0%{?suse_version} && 0%{?suse_version} < 1140) +%config %_sysconfdir/default/x2gobroker-loadchecker +%endif +%config %_sysconfdir/logrotate.d/x2gobroker-loadchecker +%_sbindir/x2gobroker-loadchecker +%_mandir/man8/x2gobroker-loadchecker.8* +%attr(02750,x2gobroker,x2gobroker) %_localstatedir/log/x2gobroker + + %files daemon %defattr(-,root,root) %_bindir/x2gobroker-daemon diff --git a/x2gobroker/agent.py b/x2gobroker/agent.py index 5364825..462f188 100644 --- a/x2gobroker/agent.py +++ b/x2gobroker/agent.py @@ -338,6 +338,31 @@ def find_busy_servers(username, remote_agent=None, **kwargs): tasks['findbusyservers'] = find_busy_servers
+def checkload(remote_agent=None, **kwargs): p['typeCPU'] * 100 ) / p['loadavgXX'] )
- """\
- Query X2Go Broker Agent for a summary of system load specific
- parameters.
- @param remote_agent: information about the remote agent that is to be called.
- @type remote_agent: C{dict}
- """
- _success, _load_params = call_broker_agent('foo', task='checkload', remote_agent=remote_agent, **kwargs)
- p = {}
- for _param in _load_params:
if ':' in _param:
key, val = _param.split(':', 1)
p[key] = float(val)
- load_factor = None
- try:
load_factor = long( ( (p['memAvail']/1000) * p['numCPU'] *
except KeyError:
pass
return load_factor
def add_authorized_key(username, pubkey_hash, authorized_keys_file='%h/.x2go/authorized_keys', remote_agent=None, **kwargs): """\ Add a public key hash to the user's authorized_keys file. diff --git a/x2gobroker/brokers/base_broker.py b/x2gobroker/brokers/base_broker.py index fe9ecc5..ad22803 100644 --- a/x2gobroker/brokers/base_broker.py +++ b/x2gobroker/brokers/base_broker.py @@ -708,6 +708,59 @@ class X2GoBroker(object):
return unicode(_group_db)
def get_use_load_checker(self):
"""\
Is this broker backend configured to access an X2Go Broker
LoadChecker daemon.
@return: C{True} if there should a load checker daemon running.
@rtype: C{bool}
"""
_use_load_checker = False
if self.config.has_value('global', 'default-use-load-checker'):
_use_load_checker = self.config.get_value('global',
'default-use-load-checker') or _use_load_checker
if
self.config.has_value('broker_{backend}'.format(backend=self.backend_name), 'use-load-checker'):
_use_load_checker =
self.config.get_value('broker_{backend}'.format(backend=self.backend_name), 'use-load-checker') or _use_load_checker
return _use_load_checker
def use_load_checker(self, profile_id):
"""\
Actually query the load checker daemon for the given
session profile ID.
This method will check:
- broker backend configured to use load checker daemon?
- more than one host configured?
- load checker queries not explicitly disabled in session profile?
@param profile_id: choose remote agent for this profile ID
@type profile_id: C{unicode}
@return: C{True} if there is a load checker daemon running.
@rtype: C{bool}
"""
# only use load checker if...
# it is enabled for the broker backend...
if self.get_use_load_checker():
_profile = self.get_profile(profile_id)
# it is not explicitly disabled per session profile definition
if _profile and
_profile.has_key(u'broker-use-load-checker') and _profile['broker-use-load-checker'] is False:
return False
# more than one host is defined in the session profile
if len(_profile[u'host']) < 2:
return False
else:
return False
return True
def _import_nameservice_module(self, service='libnss'): try: if self.nameservice_module is None: @@ -1046,6 +1099,49 @@ class X2GoBroker(object):
return remote_agent
def get_all_remote_agents(self, profile_id):
"""\
Get all remote agents.
@param profile_id: choose remote agent for this profile ID
@type profile_id: C{unicode}
@return: C{list} of remote agents for the given profile ID
@rtype: C{list}
"""
remote_agents = []
# no remote agent needed for shadow sessions
if self.is_shadow_profile(profile_id):
return remote_agents
agent_query_mode = self.get_agent_query_mode(profile_id).upper()
if agent_query_mode == u'SSH' and
x2gobroker.agent.has_remote_broker_agent_setup():
profile = self.get_profile(profile_id)
server_list = profile[u'host']
while server_list:
remote_agent_hostname = server_list[-1]
remote_agent_hostaddr = remote_agent_hostname
remote_agent_port = profile[u'sshport']
if
profile.has_key('sshport={hostname}'.format(hostname=remote_agent_hostname)):
remote_agent_port =
profile["sshport={hostname}".format(hostname=remote_agent_hostname)]
if
profile.has_key('host={hostname}'.format(hostname=remote_agent_hostname)):
remote_agent_hostaddr =
profile["host={hostname}".format(hostname=remote_agent_hostname)]
remote_agents.append({
u'hostname': remote_agent_hostname,
u'hostaddr': remote_agent_hostaddr,
u'port': remote_agent_port, }
)
server_list = server_list[0:-1]
return remote_agents
def is_shadow_profile(self, profile_id): """\ Detect from the session profile, if it defines a desktop sharing (shadow) @@ -1357,6 +1453,25 @@ class X2GoBroker(object): if busy_server not in server_list: del busy_servers[busy_server]
# dynamic load-balancing
if self.use_load_checker(self, profile_id):
busy_servers_temp = copy.deepcopy(busy_servers)
load_factors =
x2gobroker.loadchecker.checkload(self.backend_name, profile_id)
if load_factors:
for busy_server in busy_servers_temp.keys():
# FIXME: this may need love later
for peculiar multi-farm setups with non-FQDN hostnames in session profile configurations
if busy_server in
load_factors.keys() and type(load_factors[busy_server]) == types.LongType:
# do the load-factor /
relX2GoServerUsage calculation here...
busy_servers_temp[busy_server]
= load_factors[busy_server] / busy_servers[busy_server]
else:
# ignore the load checker,
results are garbage...
busy_servers_temp = None
break
if busy_servers_temp is not None:
busy_servers = copy.deepcopy(busy_servers_temp)
busy_server_list = [ (load, server) for server,
load in busy_servers.items() ] busy_server_list.sort()
diff --git a/x2gobroker/defaults.py b/x2gobroker/defaults.py index c7d4dbf..a6d4830 100644 --- a/x2gobroker/defaults.py +++ b/x2gobroker/defaults.py @@ -131,6 +131,19 @@ else: RUNDIR = '/var/run/x2gobroker' X2GOBROKER_AUTHSERVICE_SOCKET="{run}/x2gobroker/x2gobroker-authservice.socket".format(run=RUNDIR)
+if os.environ.has_key('X2GOBROKER_LOADCHECKER_SOCKET'): + X2GOBROKER_LOADCHECKER_SOCKET=os.environ['X2GOBROKER_LOADCHECKER_SOCKET'] +elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_LOADCHECKER_SOCKET'):
- X2GOBROKER_LOADCHECKER_SOCKET=iniconfig.get(iniconfig_section, 'X2GOBROKER_LOADCHECKER_SOCKET') +elif iniconfig_loaded and iniconfig.has_option('common', 'X2GOBROKER_LOADCHECKER_SOCKET'):
- X2GOBROKER_LOADCHECKER_SOCKET=iniconfig.get('common', 'X2GOBROKER_LOADCHECKER_SOCKET') +else:
- if os.path.isdir('/run/x2gobroker'):
RUNDIR = '/run'
- else:
RUNDIR = '/var/run/x2gobroker'
- X2GOBROKER_LOADCHECKER_SOCKET="{run}/x2gobroker/x2gobroker-loadchecker.socket".format(run=RUNDIR)
- if os.environ.has_key('X2GOBROKER_DEFAULT_BACKEND'): X2GOBROKER_DEFAULT_BACKEND = os.environ['X2GOBROKER_DEFAULT_BACKEND'] elif iniconfig_loaded and iniconfig.has_option(iniconfig_section, 'X2GOBROKER_DEFAULT_BACKEND'): @@ -210,6 +223,8 @@ X2GOBROKER_CONFIG_DEFAULTS = { u'default-sshproxy-authorized-keys': u'%h/.x2go/authorized_keys', u'default-agent-query-mode': u'NONE', u'default-portscan-x2goservers': True,
u'default-use-load-checker': False,
}, 'broker_base': { u'enable': False, @@ -220,6 +235,7 @@ X2GOBROKER_CONFIG_DEFAULTS = { u'user-db': u'libnss', u'group-db': u'libnss', u'desktop-shell': u'KDE',u'load-checker-intervals': 300,
}, 'broker_inifile': { u'enable': True, @@ -227,6 +243,7 @@ X2GOBROKER_CONFIG_DEFAULTS = { u'auth-mech': u'', u'user-db': u'', u'group-db': u'',u'load-checker': False,
}, 'broker_ldap': { u'enable': False, @@ -240,6 +257,7 @@ X2GOBROKER_CONFIG_DEFAULTS = { u'group-search-filter': u'(&(objectClass=posifxGroup)(cn=*))', u'starttls': False, u'agent-query-mode': u'SSH',u'use-load-checker': True,
}, }u'load-checker': True,
diff --git a/x2gobroker/loadchecker.py b/x2gobroker/loadchecker.py new file mode 100644 index 0000000..f38717e --- /dev/null +++ b/x2gobroker/loadchecker.py @@ -0,0 +1,219 @@ +# -*- coding: utf-8 -*- + +# This file is part of the X2Go Project - http://www.x2go.org +# Copyright (C) 2012-2015 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 threading +import time +import copy +import socket + +# X2Go Session Broker modules +import x2gobroker.defaults +import x2gobroker.config +from x2gobroker.loggers import logger_broker + + +def checkload(backend, profile_id, hostname=None): profile_id=profile_id, hostname=hostname))
- s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- logger_broker.debug('loadchecker.checkload(): connecting to load checker service socket {socket}'.format(socket=x2gobroker.defaults.X2GOBROKER_LOADCHECKER_SOCKET))
- try:
s.connect(x2gobroker.defaults.X2GOBROKER_LOADCHECKER_SOCKET)
- except socket.error, e:
connecting to the load checker service socket {socket}: {errmsg}'.format(socket=x2gobroker.defaults.X2GOBROKER_LOADCHECKER_SOCKET, errmsg=str(e)))logger_broker.error('loadchecker.checkload(): failure when
- if hostname is not None:
load_factor = 'LOAD-UNAVAILABLE'
backend={backend}, profile_id={profile_id}, hostname={hostname} to load checker service'.format(backend=backend, profile_id=profile_id, hostname=hostname))logger_broker.debug('loadchecker.checkload(): sending
try:
- s.send('{backend}\r{profile_id}\r{hostname}\n'.format(backend=backend,
load_factor = s.recv(1024)
s.close()
except socket.error, e:
when sending data to the load checker service socket {socket}: {errmsg}'.format(socket=x2gobroker.defaults.X2GOBROKER_LOADCHECKER_SOCKET, errmsg=str(e)))logger_broker.error('loadchecker.checkload(): failure
if load_factor.startswith('LOAD-UNAVAILABLE'):
unavailable for backend={backend}, profile_id={profile_id}, hostname={hostname}'.format(backend=backend, profile_id=profile_id, hostname=hostname))logger_broker.warning('loadchecker.checkload(): load
return None
for backend={backend}, profile_id={profile_id}, hostname={hostname} is: {lf}'.format(backend=backend, profile_id=profile_id, hostname=hostname, lf=load_factor))logger_broker.info('loadchecker.checkload(): load factor
return load_factor
- else:
raw_output = ""
backend={backend}, profile_id={profile_id} to load checker service'.format(backend=backend, profile_id=profile_id, hostname=hostname))logger_broker.debug('loadchecker.checkload(): sending
try:
- s.send('{backend}\r{profile_id}\r\n'.format(backend=backend, profile_id=profile_id))
raw_output = s.recv(1024)
s.close()
except socket.error, e:
when sending data to the load checker service socket {socket}: {errmsg}'.format(socket=x2gobroker.defaults.X2GOBROKER_LOADCHECKER_SOCKET, errmsg=str(e)))logger_broker.error('loadchecker.checkload(): failure
load_factors = {}
items = raw_output.split('\n')
for item in items:
if ":" in item:
key, val = item.split(':', 1)
load_factors[key] = val
for backend={backend}, profile_id={profile_id} are: {lf}'.format(backend=backend, profile_id=profile_id, hostname=hostname, lf=load_factors))logger_broker.info('loadchecker.checkload(): load metrics
return load_factors
- +class LoadChecker(threading.Thread):
- def __init__(self, config_file=None, config_defaults=None, logger=None, **kwargs):
"""\
X2Go Broker Agent instancesInitialize a new LoadChecker instance for querying remote
about server/system load, CPU usage, etc.
"""
self.logger = logger
self.config_file = config_file
x2gobroker.defaults.X2GOBROKER_CONFIGif self.config_file is None: self.config_file =
self.config_defaults = config_defaults
x2gobroker.defaults.X2GOBROKER_CONFIG_DEFAULTSif self.config_defaults is None: self.config_defaults =
self.kwargs = kwargs
threading.Thread.__init__(self, target=self.loadchecker)
self.server_load = {}
self.keep_alive = True
self.daemon = True
- def get_server_load(self, backend, profile_id, hostname):
"""\
Retrieve system load for a given server (via broker backend,
profile ID and hostname).
@param backend: broker backend to query.
@type backend: C{unicode}
@param profile_id: profile ID of the session profile to query
@type profile_id: C{unicode}
@param hostname: hostname of the X2Go Server
@type hostname: C{unicode}
error occurs)@return: load factor of the given server (or None if an
@rtype: C{int}
"""
try:
return self.server_load[backend][profile_id][hostname]
except KeyError:
return None
- def get_profile_load(self, backend, profile_id):
"""\
(and a givenRetrieve system load for all servers for a given profile ID
broker backend).
@param backend: broker backend to query.
@type backend: C{unicode}
@param profile_id: profile ID of the session profile to query
@type profile_id: C{unicode}
error occurs)@return: load factor of the given server (or None if an
@rtype: C{dict}
"""
try:
return self.server_load[backend][profile_id]
except KeyError:
return None
- def loadchecker(self):
"""\
available X2Go Broker Agents in regularThis is the actual thread runner that queries configured /
intervals about system load, CPU types and usage.
"""
time_to_sleep = 0
while self.keep_alive:
# in every loop we re-read the main configuration file(s)
effect immediately...# this allows changes to the config files to take
x2gobroker.config.X2GoBrokerConfigFile(config_files=self.config_file, defaults=self.config_defaults)self.config =
self.config.get_value('global', 'load-checker-intervals')self.load_checker_intervals =
for bs in self.config.list_sections() if bs.startswith('broker_') and self.config.get_value(bs, 'enable') ]self.broker_backends = [ "_".join(bs.split('_')[1:])
different broker backends at the same time, so we initialize# potentially, the X2Go Session Broker can manage
# all configured/enabled broker backends
self.brokers = {}
num_queries = 0
for backend in self.broker_backends:
self.logger.debug('LoadChecker.loadchecker(): load checker thread waking up...')if self.logger:
if not self.server_load.has_key(backend):
self.server_load[backend] = {}
_broker_backend_module = None
_broker_backend_module".format(backend=backend))exec("import x2gobroker.brokers.{backend}_broker as
_broker_backend_module.X2GoBroker(config_file=self.config_file, config_defaults=self.config_defaults, **self.kwargs)self.brokers[backend] =
self.brokers[backend].get_profile_ids() if self.brokers[backend].use_load_checker(id) ]profile_ids_to_check = [ id for id in
for profile_id in profile_ids_to_check:
if not self.server_load[backend].has_key(profile_id):
self.server_load[backend][profile_id] = {}
self.brokers[backend].get_all_remote_agents(profile_id)remote_agents =
for remote_agent in remote_agents:
- self.server_load[backend][profile_id][remote_agent[u'hostname']] = x2gobroker.agent.checkload(remote_agent)
self.logger.info('LoadChecker.loadchecker(): contacted remote broker agent for backend={backend}, profile_id={profile_id}, hostname={hostname}, new load factor is: {lf}'.format(backend=backend, profile_id=profile_id, hostname=remote_agent[u'hostname'], lf=self.server_load[backend][profile_id][remote_agent[u'hostname']]))if self.logger:
num_queries += 1
if time_to_sleep > 0:
self.logger.debug('LoadChecker.loadchecker(): sleeping for {secs}secs before querying next server'.format(secs=time_to_sleep))if self.logger:
time.sleep(time_to_sleep)
# clean up vanished hostnames
self.server_load[backend][profile_id].keys()_hostnames =
for hostname in _hostnames:
in remote_agents ]:if hostname not in [ ra[u'hostname'] for ra
self.server_load[backend][profile_id][hostname]del
# clean up vanished profile IDs
copy.deepcopy(self.server_load[backend].keys())_profile_ids =
for profile_id in _profile_ids:
if profile_id not in profile_ids_to_check:
del self.server_load[backend][profile_id]
# clean up vanished backends
_backends = copy.deepcopy(self.server_load.keys())
for backend in _backends:
if backend not in self.broker_backends:
del self.server_load[backend]
distribute next round of queries over the# don't do all queries every 300-or-so seconds, but
# complete load_checker_intervals range
if time_to_sleep == 0:
self.logger.debug('LoadChecker.loadchecker(): sleeping for {secs}secs before starting next query cycle'.format(secs=self.load_checker_intervals))if self.logger:
time.sleep(self.load_checker_intervals)
if num_queries > 0:
if time_to_sleep > 0:
self.logger.debug('LoadChecker.loadchecker(): performed {num} queries, sleeping for {secs}secs before starting next query cycle'.format(num=num_queries, secs=self.load_checker_intervals - time_to_sleep * num_queries))if self.logger:
time_to_sleep * num_queries)time.sleep(self.load_checker_intervals -
(num_queries +1)time_to_sleep = self.load_checker_intervals /
else:
if num_queries == 0:
self.logger.warning('LoadChecker.loadchecker(): performed {num} queries in this cycle, if this message keeps repeating itself, consider disabling the X2Go Broker Load Checker daemon'.format(num=num_queries, secs=self.load_checker_intervals - time_to_sleep * num_queries))if self.logger:
time_to_sleep = 0
- def stop_thread(self):
self.keep_alive = False
-- Alioth's /srv/git/code.x2go.org/x2gobroker.git//..//_hooks_/post-receive-email on /srv/git/code.x2go.org/x2gobroker.git
x2go-commits mailing list x2go-commits@lists.x2go.org http://lists.x2go.org/listinfo/x2go-commits
-- DAS-NETZWERKTEAM mike gabriel, herweg 7, 24357 fleckeby fon: +49 (1520) 1976 148 GnuPG Key ID 0x25771B31 mail: mike.gabriel@das-netzwerkteam.de, http://das-netzwerkteam.de freeBusy: https://mail.das-netzwerkteam.de/freebusy/m.gabriel%40das-netzwerkteam.de.xf...