diff options
-rw-r--r-- | contrib/check_snmp_procs.pl | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/contrib/check_snmp_procs.pl b/contrib/check_snmp_procs.pl new file mode 100644 index 00000000..678f6d54 --- /dev/null +++ b/contrib/check_snmp_procs.pl @@ -0,0 +1,590 @@ +#!/usr/bin/perl -w +# +# check_snmp_procs.pl +# Nagios script to check processes on remote host via snmp +# +# +# Copyright (c) 2003 David Alden +# +# 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; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# +# History +# ------- +# 02-25-2003 - Dave Alden <alden@math.ohio-state.edu> +# Initial creation +# +# +# TODO +# ---- +# make it work with snmp version 3 +# Suggestions??? +# +#use strict; +use Getopt::Long; +use Net::SNMP qw (oid_lex_sort oid_base_match SNMP_VERSION_1); +use lib utils.pm; +use utils qw(%ERRORS &print_revision &support &usage); + +my $PROGNAME="check_snmp_procs"; +my $REVISION="1.0"; + +# +my $opt_authprotocol; +my $opt_authpassword; +my $opt_community = 'ma4read'; +my $opt_critical; +my $opt_help; +my $opt_host = 'euler'; +my $opt_oidname = 'hrSWRunName'; +my $opt_port = 161; +my $opt_privpassword; +my $opt_regexp = 0; +my $opt_snmp_version = '2c'; +my $opt_timeout = $utils::TIMEOUT; +my $opt_username; +my $opt_verbose; +my $opt_version; +my $opt_wanted_procs; +my $opt_warning; + +# +my $max_no_processes = 999999; +my $session; +my $error; +my $no_procs; +my $exit_status; + +# +my @wanted_procs; +my %current_process_list; + +# +my %OIDS = (hrSWRunName => '1.3.6.1.2.1.25.4.2.1.2', + hrSWRunPath => '1.3.6.1.2.1.25.4.2.1.4'); + +my %OIDS_L = (hrSWRunName => length($OIDS{hrSWRunName}), + hrSWRunPath => length($OIDS{hrSWRunPath})); + +# +$ENV{'PATH'}=''; +$ENV{'BASH_ENV'}=''; +$ENV{'ENV'}=''; + +# +Getopt::Long::Configure('bundling'); +if (GetOptions( + "a:s" => \$opt_authprotocol, "authprotocol:s" => \$opt_authprotocol, + "A:s" => \$opt_authpassword, "authpassword:s" => \$opt_authpassword, + "C:s" => \$opt_community, "community:s" => \$opt_community, + "c:s" => \$opt_critical, "critical:s" => \$opt_critical, + "h" => \$opt_help, "help" => \$opt_help, + "H:s" => \$opt_host, "hostname:s" => \$opt_host, + "o:s" => \$opt_oidname, "oidname:s" => \$opt_oidname, + "P=s" => \$opt_password, "password=s" => \$opt_password, + "p=i" => \$opt_port, "port=i" => \$opt_port, + "r" => \$opt_regexp, "regexp" => \$opt_regexp, + "S" => \$opt_snmp_version, "snmpversion" => \$opt_snmp_version, + "t=i" => \$opt_timeout, "timeout=i" => \$opt_timeout, + "U=s" => \$opt_username, "username=s" => \$opt_username, + "v" => \$opt_verbose, "verbose" => \$opt_verbose, + "V" => \$opt_version, "version" => \$opt_version, + "N=s" => \$opt_wanted_procs, "names=s" => \$opt_wanted_procs, + "w:s" => \$opt_warning, "warning:s" => \$opt_warning) + == 0) { + print_usage(); + exit $ERRORS{'UNKNOWN'}; +} + +if ($opt_version) { + print_revision($PROGNAME, "\$Revision$REVISION \$"); + exit $ERRORS{'OK'}; +} + +if ($opt_help) { + print_help(); + exit $ERRORS{'OK'}; +} + +if (! utils::is_hostname($opt_host)){ + usage(); + exit $ERRORS{'UNKNOWN'}; +} + +($longest_wanted, @wanted_procs) = parse_wanted_procs($opt_verbose, $opt_wanted_procs, $opt_warning, $opt_critical); + +$SIG{'ALRM'} = sub { + print "Timeout: No Answer from Client\n"; + exit $ERRORS{'UNKNOWN'}; +}; +alarm($opt_timeout); + +($longest_current, %current_process_list) = get_process_list($opt_verbose, $opt_host, $opt_username, $opt_privpassword, $opt_authprotocol, $opt_authpassword, $opt_community, $opt_port, $opt_oidname, $opt_snmp_version); + +$exit_status = compare_process_list($opt_regexp, \%current_process_list, @wanted_procs); + +if ($opt_verbose) { + print_info($longest_current, \%current_process_list, $longest_wanted, @wanted_procs); +} + +exit($exit_status); + + +# +sub compare_process_list { + + my($regexp, $current_process_list, @wanted_procs) = @_; + my($proc, $i, $no_running_procs, @warning, @critical); + my $exit = $ERRORS{'OK'}; + + for ($i = 0; $i <= $#wanted_procs; $i++) { + + $proc = $wanted_procs[$i]; + + $no_running_procs = get_running_procs($regexp, $$proc{name}, $current_process_list); + + $$proc{no_matches} += $no_running_procs; + + if (($no_running_procs >= $$proc{warn_low}) && + ($no_running_procs <= $$proc{warn_high})) { + + push(@warning, $$proc{name} . "($no_running_procs)"); + + if ($exit != $ERRORS{'CRITICAL'}) { + $exit = $ERRORS{'WARNING'}; + } + + } elsif (($no_running_procs < $$proc{minimum}) || + ($no_running_procs >= $$proc{critical_low}) && + ($no_running_procs <= $$proc{critical_high})) { + + push(@critical, $$proc{name} . "($no_running_procs)"); + + $exit = $ERRORS{'CRITICAL'}; + } + } + + print "SNMPPROC "; + + if ($#critical >= 0) { + print "CRITICAL:"; + } elsif ($#warning >= 0) { + print "WARNING:"; + } else { + print "OK"; + } + + foreach $i (@critical) { + print " $i"; + } + + if (($#critical >= 0) && + ($#warning >= 0)) { + print " WARNING:"; + } + + foreach $i (@warning) { + print " $i"; + } + + print "\n"; + + return $exit; +} + + +# +sub get_running_procs { + + my($regex, $name, $process_list) = @_; + my $count = 0; + my $process; + + $count = 0; + + if ($regex) { + + foreach $process (keys %{$process_list}) { + + if ($process =~ /$name/) { + $count += $$process_list{$process}; + } + } + + + } else { + + if (!defined($count = $$process_list{$name})) { + $count = 0; + } + } + + return $count; +} + + +# +sub get_process_list { + + my($verbose, $host, $username, $privpassword, $authprotocol, $authpassword, $community, $port, $oidname, $snmp_version) = @_; + my(%process_list, %process_pid_list, $result); + my $process_list_longest = 1, $not_done = 1; + my(@args, @oids, $oid, $name); + + ($session, $error) = Net::SNMP->session( + -hostname => $host, + -community => $community, + -port => $port, + -version => $snmp_version, + defined($privpassword) ? (-privpassword => $privpassword) : (), + defined($authpassword) ? (-authpassword => $authpassword) : (), + defined($authprotocol) ? (-authprotocol => $authprotocol) : (), + defined($username) ? (-username => $username) : ()); + + if (!defined($session)) { + print ("UNKNOWN: $error\n"); + exit $ERRORS{'UNKNOWN'}; + } + + @args = (-varbindlist => [$OIDS{$oidname}]); + + if ($session->version == SNMP_VERSION_1) { + + while (defined($session->get_next_request(@args))) { + + $oid = (keys(%{$session->var_bind_list}))[0]; + + last if (!oid_base_match($OIDS{$oidname}, $oid)); + + $name = $session->var_bind_list->{$oid}; + $process_list{$name}++; + + if ($verbose && ($process_list_longest < length($name))) { + $process_list_longest = length($name); + } + + @args = (-varbindlist => [$oid]); + } + + } else { + + push(@args, -maxrepetitions => 25); + + while ($not_done && defined($session->get_bulk_request(@args))) { + + @oids = oid_lex_sort(keys(%{$session->var_bind_list})); + + foreach $oid (@oids) { + if (!oid_base_match($OIDS{$oidname}, $oid)) { + + $not_done = 0; + + } else { + + $name = $session->var_bind_list->{$oid}; + $process_list{$name}++; + + if ($verbose && ($process_list_longest < length($name))) { + $process_list_longest = length($name); + } + + if ($session->var_bind_list->{$oid} eq 'endOfMibView') { + $not_done = 0; + } + } + } + + if ($not_done) { + @args = (-maxrepetitions => 25, -varbindlist => [pop(@oids)]); + } + } + } + + if ($session->error() ne '') { + print ("UNKNOWN: " . $session->error() . "\n"); + exit $ERRORS{'UNKNOWN'}; + } + + $session->close; + + return($process_list_longest, %process_list); +} + + +# +sub parse_wanted_procs { + + my($verbose, $wanted_procs, $warning, $critical) = @_; + + my(@procs, $process, $i, $critical_low, $critical_high, $warn_low, $warn_high, $process_name, $process_min); + my(@process_array, @warn_array, @critical_array); + my $exit = 0; + my $longest_name = 1; + + if (defined($wanted_procs)) { + @process_array = split(/,/, $wanted_procs); + } + + if (defined($warning)) { + @warn_array = split(/,/, $warning); + } + + if (defined($critical)) { + @critical_array = split(/,/, $critical); + } + + if( defined($warning) && $#process_array != $#warn_array ) { + + print "Error: Number of entries in process list($#process_array) and warn list($#warn_array) don't match\n"; + exit $ERRORS{'UNKNOWN'}; + } + + if( defined($critical) && $#process_array != $#critical_array ) { + + print "Error: Number of entries in process list and critical list don't match\n"; + exit $ERRORS{'UNKNOWN'}; + } + + for ($i = 0; $i <= $#process_array; $i++) { + + if ((($process_name, $process_min) = split(/:/, $process_array[$i])) != 2) { + + $process_min = 1; + } + + if ($verbose && ($longest_name < length($process_name))) { + + $longest_name = length($process_name); + } + + if (defined($critical_array[$i])) { + if ((($critical_low, $critical_high) = split(/:/, $critical_array[$i])) != 2) { + + $critical_high = $critical_low; + + } else { + + if ($critical_high eq "") { + $critical_high = $max_no_processes; + } + + if ($critical_low eq "") { + $critical_low = 0; + } + } + } else { + + $critical_low = -1; + $critical_high = -1; + } + + if (defined($warn_array[$i])) { + if ((($warn_low, $warn_high) = split(/:/, $warn_array[$i])) != 2) { + + $warn_high = $warn_low; + + } else { + + if ($warn_high eq "") { + $warn_high = $max_no_processes; + } + + if ($warn_low eq "") { + $warn_low = 0; + } + } + } else { + + $warn_low = -1; + $warn_high = -1; + } + + if ($critical_low > $critical_high) { + print "Error: $process_name critical low($critical_low) is larger than high($critical_high)\n"; + $exit = 1; + } + + if ($warn_low > $warn_high) { + print "Error: $process_name warn low($warn_low) is larger than high($warn_high)\n"; + $exit = 1; + } + + if (@critical_array && + ($process_min > $critical_low)) { + print "Error: $process_name minimum($process_min) is larger than critical low($critical_low)\n"; + $exit = 1; + } + + if (@warn_array && + ($process_min > $warn_low)) { + print "Error: $process_name minimum($process_min) is larger than warn low($warn_low)\n"; + $exit = 1; + } + + if (@warn_array && @critical_array && + ((($warn_low >= $critical_low) && ($warn_low <= $critical_high)) || + (($warn_high >= $critical_low) && ($warn_high <= $critical_high)))) { + + print "Error: $process_name warn levels($warn_low:$warn_high) overlap with critical levels($critical_low:$critical_high)\n"; + $exit = 1; + } + + push(@procs,{ + name => $process_name, + critical => defined($critical), + critical_low => $critical_low, + critical_high => $critical_high, + minimum => $process_min, + warning => defined($warning), + warn_low => $warn_low, + warn_high => $warn_high}); + } + + if ($exit) { + exit $ERRORS{'UNKNOWN'}; + } + + return($longest_name, @procs); +} + + +# +sub print_info { + + my ($longest_current, $current_process_list, $longest_wanted, @wanted_procs) = @_; + + if ($longest_wanted < 7) { + $longest_wanted = 7; + } else { + $longest_wanted++; + } + + printf("%s---------------------------------------------\n", "-" x $longest_wanted); + printf("|%-" . $longest_wanted . "s | | Min | Warn | Critical |\n", "Process"); + printf("|%-" . $longest_wanted . "s | Qty | Procs| Low | High | Low | High |\n", "Name"); + printf("%s---------------------------------------------\n", "-" x $longest_wanted); + + for (my $temp=0; $temp <= $#wanted_procs; $temp++) { + + printf("|%-" . $longest_wanted . "s |%6d|%6d|%6d|%6d|%6d|%6d|\n", + $wanted_procs[$temp]{name}, + $wanted_procs[$temp]{no_matches}, + $wanted_procs[$temp]{minimum}, + $wanted_procs[$temp]{critical_low}, + $wanted_procs[$temp]{critical_high}, + $wanted_procs[$temp]{warn_low}, + $wanted_procs[$temp]{warn_high}); + } + + printf("%s---------------------------------------------\n\n", "-" x $longest_wanted); + + if ($longest_current < 7) { + $longest_current = 7; + } else { + $longest_current++; + } + + printf("%s----------\n", "-" x $longest_current); + printf("|%-" . $longest_current . "s | Qty |\n", "Process"); + printf("%s----------\n", "-" x $longest_current); + + foreach my $result (sort keys %{$current_process_list}) { + + printf("|%-" . $longest_current . "s |%6d|\n", $result, + $current_process_list{$result}); + } + printf("%s----------\n", "-" x $longest_current); + + return; +} + + +# +sub print_usage { + print "Usage: + $PROGNAME -H <host> [-r] [-v] + -N <processname>[:minimum][,<processname>[:minimum] ...] + [-a <authprotocol>] [-A <authpassword>] + [-U <username>] [-P <password>] + [-o <oidname>] [ -S <snmpversion> ] + [-C <snmp_community>] [-p <port>] [-t <timeout>] + [-w <low>:<high>[,<low>:<high> ...] + [-c <low>:<high>[,<low>:<high> ...] + $PROGNAME (-h | --help) for detailed help + $PROGNAME (-V | --version) for version information\n"; +} + + +# +sub print_help { + print_revision($PROGNAME, "\$Revision$REVISION \$"); + print "Copyright (c) 2003 David Alden + +Check if processes are running on a host via snmp + +"; + + print_usage(); + + print " +-a, --authprotocol=<authprotocol> + Set the authentication protocol used for authenticated SNMPv3 messages +-A, --authpassword=<authpassword> + Set the authentication pass phrase used for authenticated SNMPv3 messages +-c, --critical=<low>:<high>[,<low>:<high> ...] + exit with CRITICAL status if number of processes is between <low> and <high> +-C, --community=<snmp_community> + SNMP read community (default: $opt_community) +-h, --help + Show this help screen +-H, --host=<host> + Check processes on the indiciated host +-o, --oidname=<oidname> + Which oid tree to search, hrSWRunName or hrSWRunPath (default: $opt_oidname) +-p, --port=<port> + Make connection on the indicated port (default: $opt_port) +-N, --names=<processname>[:<minimum>][,<processname>[:<minimum>] ...] + Process names to check, (optional) minimum number of processes (default: 1) +-P, --password=<privpassword> + Set the privacy pass phrase used for encrypted SNMPv3 messages +-r, --regex + Use regular expression match for <process> +-S, --snmpversion + Use snmp version specified (values: 1|2c|3, default: $opt_snmp_version) +-t, --timeout + Plugin time out in seconds (default: $opt_timeout) +-U, --username=<securityname> + Set the securityname used for encrypted SNMPv3 messages +-v, --verbose + Print some extra debugging information (not advised for normal operation) +-V, --version + Show version and license information +-w, --warning=<low>:<high>[,<low>:<high> ...] + exit with WARNING status if number of processes is between <low> and <high> + + +A CRITICAL error will be indicated unless there are at least <minimum> number +of processes running (unless <minimum> is set to 0 -- useful if you don't +mind that there are none of the processes running). + +If no processes are specified, the program will still connect to the remote +host and download the current list of running processes. It will then exit +with an OK (unless it wasn't able to connect) -- useful if you want to make +sure that the remote snmpd process is running and returning a list of procs. + + +"; + support(); +} |