#!/usr/bin/perl -w

# load check module

# Version: $Revision: 0.9 $
# Author: Benjamin Oshrin and Matt Selsky
# Date: $Date: 2007/02/06 13:14:30 $
#
# Copyright (c) 2002 - 2007
# The Trustees of Columbia University in the City of New York
# Academic Information Systems
# 
# License restrictions apply, see doc/license.html for details.

use strict;
use FindBin;
use lib "$FindBin::Bin/../common";
use Survivor::Check;

my %argfmt = ("warn" => "optional number between(0,inf)",
              "prob" => "optional number between(0,inf)",
	      "warn5" => "optional number between(0,inf)",
              "prob5" => "optional number between(0,inf)",
	      "warn15" => "optional number between(0,inf)",
              "prob15" => "optional number between(0,inf)");

my $sc = new Survivor::Check();

$sc->GetOpt(\%argfmt, \&LoadValidate);

my $r = $sc->Exec( \&LoadCheck);

exit($r);

sub LoadValidate {
    return(MODEXEC_OK, 0, "Load OK");
}

sub LoadCheck {
    my $self = shift;
    my $host = shift;

    my $UP;
    if($host eq 'localhost') {
	$UP = $self->Which('uptime');
    } else {
	$UP = $self->Which('rup');
    }
    
    unless(defined $UP) {
	return(MODEXEC_MISCONFIG, 0,
	       'uptime/rup executable not found');
    }

    # 5 and 15 minute load checking based on a suggestion by David Filion

    if((!defined($self->Arg('warn')) || $self->Arg('warn')==0) &&
       (!defined($self->Arg('prob')) || $self->Arg('prob')==0) &&
       (!defined($self->Arg('warn5')) || $self->Arg('warn5')==0) &&
       (!defined($self->Arg('prob5')) || $self->Arg('prob5')==0) &&
       (!defined($self->Arg('warn15')) || $self->Arg('warn15')==0) &&
       (!defined($self->Arg('prob15')) || $self->Arg('prob15')==0)) {
	return(MODEXEC_MISCONFIG, 0, 'No test specified');
    }

    # Although rup can take multiple hostnames, a non-responsive host
    # may prevent available hosts from providing data.  We use
    # internal parallelization instead.

    if($host eq 'localhost') {
	open(ANSWER, "$UP 2>&1 |");
    } else {
	open(ANSWER, "$UP $host 2>&1 |");
    }

    my $x = <ANSWER>;
    chomp($x);
    close(ANSWER);
    
    if ($x =~ /.*load average: /) {
	$x =~ s/.*load average: //;
	my($l1, $l5, $l15);

	if($x =~ /,/) {
	    ($l1, $l5, $l15) = split(/,/, $x, 3);
	} else {
	    ($l1, $l5, $l15) = split(/ /, $x, 3);
	}
	
	my $d = sprintf("%d", $l1);  # Scalar result must be integral

	# toss leading spaces
	$l5 =~ s/\s+//;
	$l15 =~ s/\s+//;

	# prob=0 or warn=0 means you don't care about that threshold

	if (defined($self->Arg('prob')) && $self->Arg('prob') > 0 &&
	    $l1 > $self->Arg('prob')) {
	    $self->AccResultAdd($host, MODEXEC_PROBLEM, 
				"Load $l1 exceeds " . $self->Arg('prob'));
	} elsif (defined($self->Arg('warn')) && $self->Arg('warn') > 0
		 && $l1 > $self->Arg('warn')) {
	    $self->AccResultAdd($host, MODEXEC_WARNING,
				"Load $l1 exceeds " . $self->Arg('warn'));
	}

	if (defined($self->Arg('prob5')) && $self->Arg('prob5') > 0 &&
	    $l5 > $self->Arg('prob5')) {
	    $self->AccResultAdd($host, MODEXEC_PROBLEM, 
				"5 minute load $l5 exceeds " .
				$self->Arg('prob5'));
	} elsif (defined($self->Arg('warn5')) && $self->Arg('warn5') > 0
		 && $l5 > $self->Arg('warn5')) {
	    $self->AccResultAdd($host, MODEXEC_WARNING,
				"5 minute load $l5 exceeds " .
				$self->Arg('warn5'));
	}

	if (defined($self->Arg('prob15')) && $self->Arg('prob15') > 0 &&
	    $l15 > $self->Arg('prob15')) {
	    $self->AccResultAdd($host, MODEXEC_PROBLEM, 
				"15 minute load $l15 exceeds " .
				$self->Arg('prob15'));
	} elsif (defined($self->Arg('warn15')) && $self->Arg('warn15') > 0
		 && $l15 > $self->Arg('warn15')) {
	    $self->AccResultAdd($host, MODEXEC_WARNING,
				"15 minute load $l15 exceeds " .
				$self->Arg('warn15'));
	}

	my($rc, $sc, $tx) = $self->AccResultGet($host, $d);

	if($rc == MODEXEC_OK)
	{
	    $tx = "Load is $l1";
	}
    
	return($rc, $sc, $tx);
    } else {
	# Error string: this is considered a problem
	return(MODEXEC_PROBLEM, 0, &clean_msg($x));
    }
}

sub clean_msg {
    my $err = shift;

    $err =~ s/^.*(RPC):/$1 -/;

    return $err;
}
