#! /usr/bin/perl -w
#
# Ping of multiple Hosts via icmp protocol
#
# Copyright (C) 2009 by Herbert Stadler
# email: hestadler@gmx.at
#
# License Information:
# 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 3 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; if not, see .
#
#
#
############################################################################
use POSIX;
use strict;
use Getopt::Long;
use lib ".";
use lib "/usr/lib/nagios/plugins";
use lib "/usr/lib64/nagios/plugins";
use lib "/usr/local/nagios/libexec";
use utils qw(%ERRORS);
my ($opt_version,$opt_help,$opt_verbose);
my ($opt_timeout,$opt_license);
my ($opt_hostname,$opt_warn,$opt_crit,$opt_psize);
my ($opt_ping_timeout,$opt_ohosts,$opt_stop_1st_reached,$opt_ping_count);
my ($PROGNAME,$REVISION);
my ($state,$msg);
use constant DEF_TIMEOUT =>30;
use constant DEF_P_COUNT =>3;
use constant DEF_PACKETSIZE =>64;
use constant DEF_P_TIMEOUT =>5;
use constant PCOMMAND_LINUX =>"/bin/ping -c \$count\$ -s \$packetsize\$ -W \$timeout\$ \$destination\$ 2>/dev/null";
$ENV{'PATH'}='';
$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
$PROGNAME = "check_mping";
$REVISION = "1.0";
# checking commandline arguments
my $arg_status = check_args();
if ($arg_status){
print "ERROR: some arguments wrong\n";
exit $ERRORS{"UNKNOWN"};
}
# set alarmhandler for timeout handling
$SIG{'ALRM'} = sub {
print ("ERROR: plugin timed out after $opt_timeout seconds \n");
exit $ERRORS{"UNKNOWN"};
};
alarm($opt_timeout);
# set default values for program exit
if (defined ($opt_stop_1st_reached)) {
$msg = "MPING CRITICAL - No Hosts reached ";
$state = $ERRORS{'CRITICAL'};
} else {
$msg = "MPING OK - No Problems found ";
$state = $ERRORS{'OK'};
}
my $l_tmsg;
my @hosts;
push (@hosts,$opt_hostname);
if ( defined ($opt_ohosts)) {
my @otherhosts=split(",",$opt_ohosts);
foreach my $others (@otherhosts) {
push (@hosts,$others);
}
}
foreach my $l_hostname (@hosts) {
# return value: Round Trip Time in ms
my $rtt=Do_Ping($l_hostname);
if (defined ($opt_stop_1st_reached)) {
# if one server was reached than everything is OK
if ( $rtt ) {
if ( $opt_verbose ) {
printf("RTT %-20s: %.3f ms\n",$l_hostname,$rtt);
}
$state = $ERRORS{'OK'};
Set_StatusCode($rtt,$l_hostname);
last;
}
} else {
# all servers are to ping
if ( $rtt ) {
if ( $opt_verbose ) {
printf("RTT %-20s: %.3f ms\n",$l_hostname,$rtt);
}
Set_StatusCode($rtt,$l_hostname);
} else {
if ( $opt_verbose ) {
printf("RTT %-20s: not reached\n",$l_hostname);
}
create_msg(sprintf("%s:nr",$l_hostname));
$state = $ERRORS{'CRITICAL'};
}
}
}
if ($state == $ERRORS{'OK'}){
$msg = "MPING OK - ".$l_tmsg if ( defined ($l_tmsg));
}elsif ($state == $ERRORS{'WARNING'}){
$msg = "MPING WARNING - ".$l_tmsg;
}elsif ($state == $ERRORS{'CRITICAL'}){
$msg = "MPING CRITICAL - ".$l_tmsg if ( defined ($l_tmsg));
}
# and now "over and out"
print "$msg\n";
exit $state;
#--------------------------------------------------------------------------#
# S U B R O U T I N E S #
#--------------------------------------------------------------------------#
#--------------------------------------------------------------------------
sub Set_StatusCode {
#--------------------------------------------------------------------------
my ($rtt,$l_hostname)=@_;
if ($rtt < $opt_warn ) {
create_msg(sprintf("%s:%.3f ms",$l_hostname,$rtt));
} elsif ( $rtt < $opt_crit) {
create_msg(sprintf("%s:%.3f ms",$l_hostname,$rtt));
if ( $state != $ERRORS{'CRITICAL'} ) {
$state = $ERRORS{'WARNING'};
}
} else {
$state = $ERRORS{'CRITICAL'};
create_msg(sprintf("%s:%.3f ms",$l_hostname,$rtt));
}
}
#--------------------------------------------------------------------------
sub Do_Ping {
#--------------------------------------------------------------------------
my ($l_host)=@_;
my $PINGCMD=PCOMMAND_LINUX;
$PINGCMD=~s/\$count\$/$opt_ping_count/;
$PINGCMD=~s/\$packetsize\$/$opt_psize/;
$PINGCMD=~s/\$timeout\$/$opt_ping_timeout/;
$PINGCMD=~s/\$destination\$/$l_host/;
if ( $opt_verbose ) {
printf("Executing Command: %s\n",$PINGCMD);
}
if (open (INDATA, $PINGCMD . " |") ) {
while () {
if ( $opt_verbose ) {
printf("%s",$_);
}
# rtt min/avg/max/mdev = 0.481/0.709/1.160/0.318 ms
if(/^rtt min\/avg\/max\/mdev\s+=\s+([.0-9]+)\/([.0-9]+)\/([.0-9]+)\/([.0-9]+)\s+ms/){
my $avg=$2;
if ( $opt_verbose ) {
printf("Average RTT: %.3f\n",$avg);
}
return ($avg);
}
}
close(INDATA);
}
return (undef);
}
#--------------------------------------------------------------------------
sub create_msg {
#--------------------------------------------------------------------------
my ($l_txt)=@_;
if (! defined $l_txt) {return};
if (defined $l_tmsg) {
$l_tmsg.=",";
}
$l_tmsg.=$l_txt;
}
#--------------------------------------------------------------------------
sub check_args {
#--------------------------------------------------------------------------
Getopt::Long::Configure('bundling');
GetOptions
("V" => \$opt_version,
"version" => \$opt_version,
"L" => \$opt_license,
"license" => \$opt_license,
"v" => \$opt_verbose,
"verbose" => \$opt_verbose,
"h|?" => \$opt_help,
"help" => \$opt_help,
"s" => \$opt_stop_1st_reached,
"stop1st" => \$opt_stop_1st_reached,
"t=i" => \$opt_timeout,
"timeout=i" => \$opt_timeout,
"H=s" => \$opt_hostname,
"hostname=s" => \$opt_hostname,
"o=s" => \$opt_ohosts,
"ohostname=s" => \$opt_ohosts,
"w=i" => \$opt_warn,
"warning=i" => \$opt_warn,
"c=i" => \$opt_crit,
"critical=i" => \$opt_crit,
);
if ($opt_license) {
print_gpl($PROGNAME,$REVISION);
exit $ERRORS{'OK'};
}
if ($opt_version) {
print_revision($PROGNAME,$REVISION);
exit $ERRORS{'OK'};
}
if ($opt_help) {
print_help();
exit $ERRORS{'OK'};
}
if ( ! defined($opt_hostname)){
print "\nERROR: Hostname not defined\n\n";
print_usage();
exit $ERRORS{'UNKNOWN'};
}
unless (defined $opt_warn) {
print "\nERROR: Parameter WARNING not defined\n\n";
print_usage();
exit $ERRORS{'UNKNOWN'};
}
unless (defined $opt_crit) {
print "\nERROR: Parameter CRITICAL not defined\n\n";
print_usage();
exit $ERRORS{'UNKNOWN'};
}
if ( $opt_warn >= $opt_crit ) {
print "\nERROR: Parameter WARN greater than parameter CRIT\n\n";
print_usage();
exit $ERRORS{'UNKNOWN'};
}
unless (defined $opt_timeout) {
$opt_timeout = DEF_TIMEOUT;
}
$opt_psize =DEF_PACKETSIZE;
$opt_ping_timeout =DEF_P_TIMEOUT;
$opt_ping_count =DEF_P_COUNT;
return $ERRORS{'OK'};
}
#--------------------------------------------------------------------------
sub print_usage {
#--------------------------------------------------------------------------
print "Usage: $PROGNAME [-h] [-s] [-L] [-t timeout] [-v] [-V] -H hostname -w warn_rtt_ms -c crit_rtt_ms [-o hostname1[,hostname2]] \n\n";
}
#--------------------------------------------------------------------------
sub print_help {
#--------------------------------------------------------------------------
print_revision($PROGNAME,$REVISION);
print_usage();
printf (" Multi Destination Pinger, pinging a list of hosts \n");
printf ("-t (--timeout) Timeout in seconds (default=%d)\n",DEF_TIMEOUT);
printf ("-H (--hostname) Hostname to monitor\n");
printf ("-o (--ohostname) Additional hostnames to monitor\n");
printf (" example: -o hostname1,hostname2\n");
printf ("-h (--help) Help\n");
printf ("-V (--version) Programm version\n");
printf ("-v (--verbose) Print some useful information\n");
printf ("-L (--license) Print license information\n");
printf ("-w (--warning) Warning threshold round trip time (in ms)\n");
printf ("-c (--critical) Critical threshold round trip time (in ms)\n");
printf ("-s (--stop1st) Stop pinging if one server was reached -> status OK\n");
printf ("\n");
}
#--------------------------------------------------------------------------
sub print_gpl {
#--------------------------------------------------------------------------
print <.
EOD
}
#--------------------------------------------------------------------------
sub print_revision {
#--------------------------------------------------------------------------
my ($l_prog,$l_revision)=@_;
print <.
=cut