#!/usr/bin/perl -wT
#
# (c)2001 Sebastian Hetze, Linux Information Systems AG
# send bug reports to <S.Hetze@Linux-AG.com>
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# you should have received a copy of the GNU General Public License
# along with this program (or with Nagios);  if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA
#
#
# Check apache status information provided by mod_status to find
# out about the load (number of servers working) and the
# performance (average response time for recent requests).
#
# Usage:
# check_apache -H <host> [-lhV] [-w <warn>] [-c <crit>] [-u <url>]
#
# check_apache <host> <warn> <crit> <url> (if you cannot avoid it)
#
# Should have the username/password facility added to allow challenges.
#

require 5.004;

use strict;
use lib utils.pm ;
use Plugin;
use Plugin::Parameter qw($helpparameterlist $versionparameterlist $hostnameparameter
			 $warningparameter $criticalparameter $timeoutparameter
			 $verboseparameter);

use LWP::UserAgent;
use URI::URL;

use vars qw($opt_V $opt_h $opt_l $opt_w $opt_c $opt_H $opt_u $opt_v $opt_t $xml);
use utils qw(%ERRORS &usage);

sub switch2load() {
  $warningparameter->default(20);
  $criticalparameter->default(20);
  $opt_l = 1;
}

my $loadparameter = new Plugin::Parameter(-name => "load", -flags => [ 'l', 'load' ],
					  -binding => \&switch2load,
					  -description => "Check load instead of performance");
my $urlparameter = new Plugin::Parameter(-name => "url", -flags => [ 'u', 'url' ], -type => "PATH",
					 -default => "/server-status",
					 -description => "Location of mod_status interface on server");

$warningparameter->default(500);
$warningparameter->description("Load or performance level at which a warning message will be generated");
$criticalparameter->default(1000);
$criticalparameter->description("Load or performance level at which a critical message will be generated");

my @commandparameterlist = ( $hostnameparameter,
			     $loadparameter,
			     $warningparameter,
			     $criticalparameter,
			     $urlparameter,
			     $timeoutparameter,
			     $verboseparameter );

my $plugin = new Plugin(-revision       => '$Revision: 1.1.1.1 $',
			-copyright      => "2001 Sebastian Hetze  Linux Information Systems AG, 2004 Howard Wilkinson <howard\@cohtech.com>",
			-shortcomment   => "This plugin checks the apache HTTP service on the specified host. It uses the mod_status facilities provided by the apache server. The monitoring server must be authorized in httpd.conf.",
			-parameterlists => [ \@commandparameterlist, $helpparameterlist, $versionparameterlist ]);


$plugin->init();

my $autostring = ($opt_l)?"?auto":"";

$plugin->start_timeout($opt_t, "No response from HTTP server (alarm)");

#
#              now we set things up for the real work
#              and fire up the request
#
my $ua = new LWP::UserAgent;
$ua->agent("Nagios/0.1 " . $ua->agent);

my $urlstring = "http://" . $opt_H . $opt_u . $autostring;
my $url = url($urlstring);

my $req = new HTTP::Request 'GET', $url;
my $res = $ua->request($req);

$plugin->stop_timeout();

#
#              hopefully we´ve got something usefull
#
if ($res->is_success) {
  if($opt_l) {
    my ($accesses, $kbytes, $load, $uptime, $rps, $bps, $bpr, $busy, $idle, $score);
    my %scores = ();
    foreach $_ (split /^/m, $res->content) {
      next if /^\s*$/;
      #
      #              this is the load checking section
      #              we parse the whole content, just in case someone
      #              wants to use this some day in the future
      #
      if (/^Total Accesses:\s+([0-9.]+)/) { $accesses = $1; next; }
      if (/^Total kBytes:\s+([0-9.]+)/) { $kbytes = $1; next; }
      if (/^CPULoad:\s+([0-9.]+)\s+/) { $load = $1; next; }
      if (/^Uptime:\s+([0-9.]+)\s+/) { $uptime = $1; next; }
      if (/^ReqPerSec:\s+([0-9.]+)\s+/) { $rps = $1; next; }
      if (/^BytesPerSec:\s+([0-9.]+)\s+/) { $bps = $1; next; }
      if (/^BytesPerReq:\s+([0-9.]+)\s+/) { $bpr = $1; next; }
      if (/^BusyServers:\s+([0-9.]+)\s+/) { $busy = $1; next; }
      if (/^IdleServers:\s+([0-9.]+)\s+/) { $idle = $1; next; }
      if (/^Scoreboard:\s+([SRWKDLG_.]+)\s+/) { $score = $1; next; }
      print "Unknown Status\n";
      exit $ERRORS{"UNKNOWN"};
    }
    #
    #              now we even parse the whole scoreboard, just for fun
    #
    foreach my $scorepoint (split //m, $score) {
      if($scorepoint eq '.') { $scores{'.'}+=1; next; }  # Unused
      if($scorepoint eq '_') { $scores{'_'}+=1; next; }  # Waiting
      if($scorepoint eq 'S') { $scores{'S'}+=1; next; }  # Starting
      if($scorepoint eq 'R') { $scores{'R'}+=1; next; }  # Reading
      if($scorepoint eq 'W') { $scores{'W'}+=1; next; }  # Writing
      if($scorepoint eq 'K') { $scores{'K'}+=1; next; }  # Keepalive
      if($scorepoint eq 'D') { $scores{'D'}+=1; next; }  # DNS Lookup
      if($scorepoint eq 'L') { $scores{'L'}+=1; next; }  # Logging
      if($scorepoint eq 'G') { $scores{'G'}+=1; next; }  # Going
    }

    if($busy>$opt_c) {
      printf "HTTPD CRITICAL: %.0f servers running\n", $busy;
      exit $ERRORS{"CRITICAL"};
    }
    if($busy>$opt_w) {
      printf "HTTPD WARNING: %.0f servers running\n", $busy;
      exit $ERRORS{"WARNING"};
    }
    printf "HTTPD ok: %.0f servers running, %d idle\n", $busy, $idle;
    exit $ERRORS{"OK"};
  } else {
    #
    #              this is the performance check section
    #              We are a bit lazy here, no parsing of the initial data
    #              block and the scoreboard.
    #              However, you have the whole set of per server
    #              information to play with ;-)
    #              The actual performance is measured by adding up the
    #              milliseconds required to process the most recent
    #              requests of all instances and then taking the average.
    #
    my $lines = 0;
    my $req_sum = 0;
    foreach my $tablerow (split /<tr>/m, $res->content) {
      my ($empty,$Srv,$PID,$Acc,$M,$CPU,$SS,$Req,$Conn,$Child,$Slot,$Client,$VHost,$Request)
	= split /<td>/, $tablerow;
      if($Req) {
	$lines+=1;
	$req_sum+=$Req;
      }
      undef $Req;
    }
    my $average=$req_sum/$lines;
    if($average>$opt_c) {
      printf "HTTPD CRITICAL: average response time %.0f
	milliseconds\n", $average;
      exit $ERRORS{"CRITICAL"};
    }
    if($average>$opt_w) {
      printf "HTTPD WARNING: average response time %.0f
	milliseconds\n", $average;
      exit $ERRORS{"WARNING"};
    }
    if($average>0) {
      printf "HTTPD ok: average response time %.0f milliseconds\n",
        $average;
      exit $ERRORS{"OK"};
    }
    print "Unknown Status\n";
    exit $ERRORS{"UNKNOWN"};
  }
} else {
  print "HTTP request failed\n";
  exit $ERRORS{"CRITICAL"};
}

#
#              the end
#
