#!/usr/bin/perl -w
#
# (c)2002 Jack Coates, jack@monkeynoodle.org
# Thanks due to countless scripts posted on the web and to
# David Talkington on the shell.scripting@moongroup.com list.
# 
# 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_multisvc.pl is a Nagios plugin designed to check multiple 
# services and return a severity value which is based on
# the number of services that are down. The services do not need 
# to be on a single host. Some example usages:
#
# Servers 1-10 all run Apache on port 80 behind a load balancer. 
# The load-balanced virtual IP is monitored as a 
# paging-notification service and each host is monitored as an 
# email-notification service, but you'd also like to 
# be paged if fifty percent of the hosts have died.
#
# Server 11 runs several processes on different ports that all do 
# the same thing and are load-balanced by an external 
# application. You don't care if one or two processes die, but 
# you do want to know if they're all dead.

# An external configuration file is required. The file defines 
# the service-host relationships and individual check
# commands that we'll need. Its default location is 
# check_multisvc.cfg in the nagios config directory, or you 
# can define its location in hosts.cfg or services.cfg
# with check_command check_multisvc.pl!-F /path/to/config/file.
# You must edit the .cfg file before this plugin will work.

use strict;
use Getopt::Long;
use vars qw($opt_F $opt_w $opt_c $opt_H);
use lib "/usr/lib/nagios/plugins";
use lib "/usr/local/nagios/libexec";
use utils qw($TIMEOUT %ERRORS &print_revision &support);
my $PROGNAME = "check_multisvc.pl";
my $state = "OK";
my $counter = "0";
my %config = ();
my $key = undef;
my $value = undef;
my $warn = undef;
my $crit = undef;
my $check = undef;
my $result = undef;
my $info = undef;

sub print_help () {
        print "$PROGNAME [-h|--help] Gives this usage statement.\n";
        print "[-V|--version] Prints version number.\n";
        print "[-F|--filename] /path/to/filename.\n";
        print "-w|--warn # Number of failed checks to issue WARN at.\n";
        print "-c|--critical # Number of failed checks to issue CRITICAL at.\n";
        print "[-H|--host] Optional hostname/IP to pass (use %HOST% in your cfg file).\n";
        print "Note: $PROGNAME will look for a config file in /etc/nagios/\n";
        print "          or /usr/local/nagios/etc/ before failing.\n\n";
        &support;
        exit $ERRORS{'UNKNOWN'};
}

sub version () {
        &print_revision ($PROGNAME,"1.1");
        &support;
        exit $ERRORS{'UNKNOWN'};
}

# parse command line for config file, options
Getopt::Long::Configure('bundling', 'no_ignore_case');
GetOptions
        ("V|version"     => \&version,
         "h|help"        => \&print_help,
         "w|warn=n"      => \$warn,
         "c|crit=n"      => \$crit,
         "H|host=s"      => \$opt_H,
         "F|filename=s"  => \$opt_F);

if ( !defined($opt_F) ) {
        if (-e '/etc/nagios/check_multisvc.cfg') {$opt_F = "/etc/nagios/check_multisvc.cfg"}
        elsif (-e '/usr/local/nagios/etc/check_multisvc.cfg') {$opt_F = "/usr/local/nagios/etc/check_multisvc.cfg"}
        else {
                print "\nPROBLEM: I need a config file.\n";
                &print_help;
                exit $ERRORS{'UNKNOWN'};
                }
        }

# Just in case of problems, let's not hang Nagios
my $DEFAULT_SOCKET_TIMEOUT = $TIMEOUT;
$SIG{'ALRM'} = sub { 
        print "Timeout Exceeded.\n";
        exit $ERRORS{'UNKNOWN'};
        };
alarm($TIMEOUT);

# read config file and insert values and checks into an hash.
open (CONFIG, "<$opt_F") or die "Can't open config file $opt_F.\n";
while (<CONFIG>) {
        chomp;                        # no newline
        s/#.*//;                      # no comments
        s/^\s+//;                     # no leading white
        s/\s+$//;                     # no trailing white
        next unless length;           # anything left?
        my ($key, $value) = split(/\s+/, $_, 2);
        if ( defined($key) && defined ($value) ) { $value =~ s/%HOST%/$opt_H/; $config{$key} = $value }
        }

# run the checks.
foreach my $key (sort keys (%config)) {
        if ( $config{$key} ) {
                open(CMD, "$config{$key} |") or die "Can't execute command $config{$key}.\n";
                waitpid($?, 0);
                while (<CMD>) {
                        ($check,$result,$info) = split(/\s+/, $_, 3);
                        if ($result !~ m/ok/i) { $counter ++ }
                        print "$check, $result, $info, $counter\n";
                        }
                close(CMD);
                }
        }

# count up the results and let Nagios know.
if ($counter >= $warn && $counter < $crit) { print "$PROGNAME WARNING"; exit $ERRORS{'WARNING'} }
if ($counter >= $crit) { print "$PROGNAME CRITICAL"; exit $ERRORS{'CRITICAL'} }
print "$PROGNAME OK";
exit $ERRORS{'OK'};

