Subject: Bug#686: patch for load balancer

From: Sergey Savko <[email-masked]>
Date: Fri, 5 Dec 2014 16:55:08 +0400 (MSK)

X2go patch is to communicate with all application servers and receive rate of loading. The higher is the less loaded server. Coefficient considered of CPU clock frequency, number of cores, LA, number of users per server. We added modules Sys::Info and Sys::Load in x2gobroker-agent.pl
From 28740152b9d3629af73d61a3a7863dc53ae870f3 Mon Sep 17 00:00:00 2001
From: Sergey Savko <[email-masked]>
Date: Fri, 5 Dec 2014 15:29:56 +0300
Subject: [PATCH] X2go patch is to communicate with all application servers and
 receive rate of loading. The higher is the less loaded server. Coefficient
 considered of CPU clock frequency, number of cores, LA, number of users per
 server. We added modules Sys::Info and Sys::Load in x2gobroker-agent.pl

---
 lib/x2gobroker-agent.pl           | 27 ++++++++++++++++++++++++---
 x2gobroker/brokers/base_broker.py | 20 +++++++++++++++-----
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/lib/x2gobroker-agent.pl b/lib/x2gobroker-agent.pl
index d670895..d4c6c03 100755
--- a/lib/x2gobroker-agent.pl
+++ b/lib/x2gobroker-agent.pl
@@ -24,6 +24,10 @@ use strict;
 use File::Basename;
 use File::Which;
 
+use Sys::Info;
+use Sys::Info::Constants qw( :device_cpu );
+use Sys::Load qw/getload uptime/;
+
 my @available_tasks = (
     "availabletasks",
     "addauthkey",
@@ -177,14 +181,15 @@ if( (($mode eq 'findbusyservers_by_sessionstats') || ($mode eq 'findbusyservers'
 	#   1. if no server is returned, any of the configured servers is best server
 	#   2. if some servers are returned, a best server is one that is not returned
 	#   3. if all configured servers are returned, than evaluate the usage value
-	#      (e.g. 90:server1, 20:server2, 10:server3 -> best server is server3)
+	#      (e.g. 10:server1, 20:server2, 90:server3 -> best server is server3)
 
 	# The above interpretation has to be handled by the broker implementation
 	# calling »x2gobroker-agent findbusyservers«.
 
 	InitX2GoUser($uid, $uidNumber, $gidNumber, $home);
 	print "OK\n";
-	my $busy_servers = `sudo -u $uid -- x2gogetservers`;
+	# We don't need know all busy_servers, we need to know only the current server load
+	my $busy_servers = `/bin/su - $uid -c \"x2gogetservers\" | grep \$(hostname)`;
 
 	my %server_load = ();
 	my $num_sessions = 0;
@@ -194,11 +199,27 @@ if( (($mode eq 'findbusyservers_by_sessionstats') || ($mode eq 'findbusyservers'
 		$server_load{$hostname} = $num_users;
 		$num_sessions += $num_users;
 	}
+	        # give the highest priority
+        if ( ! $num_sessions ) {
+            my $hostname = `echo \$(hostname)`;
+            $server_load{$hostname} = 0.1;
+            $num_sessions = 0.1;
+        }
+        
+        my $LOADXX = ((getload())[0] + (getload())[1] + (getload())[2])*100/3;
+        my $LOADXX = sprintf("%.2f", $LOADXX);
+        
+        my %options;
+        my $info = Sys::Info->new;
+        my $cpu  = $info->device( CPU => %options );
+        
+        my $CPU = $cpu->speed;
+        my $NBCPU = $cpu->count;
 
 	# render the output result
 	my @result;
 	for my $hostname ( keys %server_load ) {
-		my $available = $server_load{$hostname}/$num_sessions*100;
+		my $available = ( $NBCPU * $CPU * 100 ) / $LOADXX / $num_sessions;
 		push @result, sprintf '%1$d:%2$s', $available, $hostname;
 	}
 	print join("\n", sort @result);
diff --git a/x2gobroker/brokers/base_broker.py b/x2gobroker/brokers/base_broker.py
index 880e1d7..fc0f44f 100644
--- a/x2gobroker/brokers/base_broker.py
+++ b/x2gobroker/brokers/base_broker.py
@@ -1218,10 +1218,20 @@ class X2GoBroker(object):
 
             # query remote agent on how busy our servers are...
             busy_servers = None
-            try:
-                success, busy_servers = x2gobroker.agent.find_busy_servers(username=username, remote_agent=remote_agent)
-            except x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException:
-                pass
+	    busy_each_server = dict()
+	    while server_list :
+		remote_agent_server = server_list[-1]
+		remote_agent_port = profile[u'sshport']
+		remote_agent = {u'hostname': remote_agent_server, u'port': remote_agent_port, }
+		try:
+		    success, busy_each_servers = x2gobroker.agent.find_busy_servers(username=username, remote_agent=remote_agent)
+		except x2gobroker.x2gobroker_exceptions.X2GoBrokerAgentException:
+		    pass
+		if busy_servers is None:
+		    busy_servers = busy_each_servers
+		else :
+		    busy_servers.update(busy_each_servers)
+		server_list = server_list[0:-1]
 
             if busy_servers is not None:
 
@@ -1260,7 +1270,7 @@ class X2GoBroker(object):
                         busy_servers[server] = 0
 
                 busy_server_list = [ (load, server) for server, load in busy_servers.items() ]
-                busy_server_list.sort()
+                busy_server_list.sort(reverse=True)
 
                 logger_broker.debug('base_broker.X2GoBroker.select_session(): load balancer analysis: {server_load}'.format(server_load=unicode(busy_server_list)))
 
-- 
1.9.1