#! /usr/bin/perl
# Check haproxy load balance status
# anders@fupp.net, 2009-05-19

use Getopt::Std;
use IO::Socket;
use MIME::Base64;

$timeout = 10;

getopts('H:b:s:u:p:dc');

sub usage {
	print "Usage:\n\tcheck_haproxy_lbstatus -H <host> -b <backend> -s <stats-url>\n\t -u <user> -p <pass> [-c (failure is critical)]\n";
	exit(3);
}
usage unless ($opt_H && $opt_b && $opt_s);

if ($opt_c) {
	$failexit = 2;
} else {
	$failexit = 1;
}

$vhost = $opt_s;
$vhost =~ s@^\w+://(.+?)/.*@\1@;
# Remove port number:
$vhost =~ s@\:\d+$@@;
$baseurl = $opt_s;
$baseurl =~ s@^\w+://.+?(/)@\1@;
$port = $opt_s;
if ($port =~ /^\w+:\/\/.+?\:(\d+)\/.*$/) {
	$port = $1;
} else {
	$port = 80;
}

if ($opt_d) {
	print "vhost=$vhost\n";
	print "baseurl=$baseurl\n";
	print "port=$port\n";
}

sub unknown {
	my $txt = shift;
	print "Could not check haproxy load balance status for $opt_H in backend $opt_b on $vhost";
	if ($txt) {
		print ", $txt";
	} elsif ($httpresponse) {
		print ", got $httpresponse";
	}
	print "\n";
	exit(3);
}

# Konstruer request
$req = "GET $baseurl;csv;norefresh HTTP/1.1\r\nHost: $vhost\r\n";
if ($opt_u) {
	$req .= "Authorization: Basic " . encode_base64($opt_u . ":" . $opt_p, "") . "\r\n";
}
$req .= "Connection: close\r\n\r\n";

if ($opt_d) { print "Request:\n$req"; }


my $sock = new IO::Socket::INET (
	PeerAddr => $vhost,
	PeerPort => $port,
	Proto => 'tcp',
	Timeout => $timeout
	);
unknown("could not connect") unless ($sock);
print $sock $req;

# HTTP respons
$httpresponse = <$sock>;
# Skip HTTP headere;
while (<$sock>) { last if (/^\s*$/); }
# Fields line;
$fields = <$sock>;
$fields =~ s@^# @@;
chomp($fields);
$fields =~ s@,$@@;
@fields = split(/,/, $fields);

#print "Felter: @fields X\n";
while (<$sock>) {
	@line = split(/,/, $_);

	next if ($line[1] =~ /^(FRONTEND|BACKEND)$/);
#	print "Jongo line: @line\n";
#	print "line0: $line[0] line1: @line[1] numfields " . $#fields . " \n";
	for ($i = 2; $i <= $#fields; $i++) {
		$status{"$line[0]"}{"$line[1]"}{"$fields[$i]"} = $line[$i];
#		print "Ke $line[$i] ";
	}
#	print "\n";
#}
#	last if (/^(\r\n|\n)$/);
#	last if (/^\s*$/);
#	print;
#	$data .= $_;
}
close($sock);

chomp($httpresponse);
$httpcode = $httpresponse;
$httpcode =~ s@^HTTP/[\d\.]+ (\d+).*@$1@g;

if ($opt_d) {
	foreach $gr (keys %status) {
		print "gruppe: $gr\n";
		foreach $host (keys %{ $status{"$gr"} }) {
			print "\thost: $host\n";
			print "\tvalues: ";
			foreach $type (keys %{ $status{"$gr"}{"$host"} }) {
				print "$type=" . $status{"$gr"}{"$host"}{"$type"} . " ";
			}
			print "\n";
		}
	}
}

$mystatus = $status{"$opt_b"}{"$opt_H"}{"status"};
$lastchg = $status{"$opt_b"}{"$opt_H"}{"lastchg"};

if ($opt_d) {
	print "Host: $opt_H\n";
	print "Backend: $opt_b\n";
	print "Status: $mystatus\n";
	print "Last change: $lastchg\n";
}

unknown unless ($httpcode == 200);
if ($mystatus eq "UP") {
	print "Host $opt_H is UP on $vhost for $lastchg seconds\n";
	exit(0);
} elsif ($mystatus eq "DOWN") {
	print "Host $opt_H is DOWN on $vhost for $lastchg seconds\n";
	exit($failexit);
} elsif ($mystatus ne "") {
	print "Host $opt_H is in UNKNOWN status ($mystatus) on $vhost for $lastchg seconds\n";
	exit($failexit);
} else {
	unknown("host not found");
} 
