4 # Nagios script to check processes on remote host via snmp
7 # Copyright (c) 2003 David Alden
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation; either version 2
12 # of the License, or (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program; if not, write to the Free Software
21 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 # 02-25-2003 - Dave Alden <alden@math.ohio-state.edu>
32 # make it work with snmp version 3
37 use Net
::SNMP qw
(oid_lex_sort oid_base_match SNMP_VERSION_1
);
38 use lib
"/usr/local/nagios/libexec";
39 use utils
qw(%ERRORS &print_revision &support &usage);
41 my $PROGNAME="check_snmp_procs";
47 my $opt_community = 'ma4read';
50 my $opt_host = 'euler';
51 my $opt_oidname = 'hrSWRunName';
55 my $opt_snmp_version = '2c';
56 my $opt_timeout = $utils::TIMEOUT;
64 my $max_no_processes = 999999;
72 my %current_process_list;
75 my %OIDS = (hrSWRunName => '1.3.6.1.2.1.25.4.2.1.2',
76 hrSWRunPath => '1.3.6.1.2.1.25.4.2.1.4');
78 my %OIDS_L = (hrSWRunName => length($OIDS{hrSWRunName}),
79 hrSWRunPath => length($OIDS{hrSWRunPath}));
87 Getopt::Long::Configure('bundling');
89 "a:s" => \$opt_authprotocol, "authprotocol:s" => \$opt_authprotocol,
90 "A:s" => \$opt_authpassword, "authpassword:s" => \$opt_authpassword,
91 "C:s" => \$opt_community, "community:s" => \$opt_community,
92 "c:s" => \$opt_critical, "critical:s" => \$opt_critical,
93 "h" => \$opt_help, "help" => \$opt_help,
94 "H:s" => \$opt_host, "hostname:s" => \$opt_host,
95 "o:s" => \$opt_oidname, "oidname:s" => \$opt_oidname,
96 "P=s" => \$opt_password, "password=s" => \$opt_password,
97 "p=i" => \$opt_port, "port=i" => \$opt_port,
98 "r" => \$opt_regexp, "regexp" => \$opt_regexp,
99 "S" => \$opt_snmp_version, "snmpversion" => \$opt_snmp_version,
100 "t=i" => \$opt_timeout, "timeout=i" => \$opt_timeout,
101 "U=s" => \$opt_username, "username=s" => \$opt_username,
102 "v" => \$opt_verbose, "verbose" => \$opt_verbose,
103 "V" => \$opt_version, "version" => \$opt_version,
104 "N=s" => \$opt_wanted_procs, "names=s" => \$opt_wanted_procs,
105 "w:s" => \$opt_warning, "warning:s" => \$opt_warning)
108 exit $ERRORS{'UNKNOWN'};
112 print_revision($PROGNAME, "\$Revision: 1771 $REVISION \$");
121 if (! utils::is_hostname($opt_host)){
123 exit $ERRORS{'UNKNOWN'};
126 ($longest_wanted, @wanted_procs) = parse_wanted_procs($opt_verbose, $opt_wanted_procs, $opt_warning, $opt_critical);
129 print "Timeout: No Answer from Client\n";
130 exit $ERRORS{'UNKNOWN'};
134 ($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);
136 $exit_status = compare_process_list($opt_regexp, \%current_process_list, @wanted_procs);
139 print_info($longest_current, \%current_process_list, $longest_wanted, @wanted_procs);
146 sub compare_process_list {
148 my($regexp, $current_process_list, @wanted_procs) = @_;
149 my($proc, $i, $no_running_procs, @warning, @critical);
150 my $exit = $ERRORS{'OK'};
152 for ($i = 0; $i <= $#wanted_procs; $i++) {
154 $proc = $wanted_procs[$i];
156 $no_running_procs = get_running_procs($regexp, $$proc{name}, $current_process_list);
158 $$proc{no_matches} += $no_running_procs;
160 if (($no_running_procs >= $$proc{warn_low}) &&
161 ($no_running_procs <= $$proc{warn_high})) {
163 push(@warning, $$proc{name} . "($no_running_procs)");
165 if ($exit != $ERRORS{'CRITICAL'}) {
166 $exit = $ERRORS{'WARNING'};
169 } elsif (($no_running_procs < $$proc{minimum}) ||
170 ($no_running_procs >= $$proc{critical_low}) &&
171 ($no_running_procs <= $$proc{critical_high})) {
173 push(@critical, $$proc{name} . "($no_running_procs)");
175 $exit = $ERRORS{'CRITICAL'};
181 if ($#critical >= 0) {
183 } elsif ($#warning >= 0) {
189 foreach $i (@critical) {
193 if (($#critical >= 0) &&
198 foreach $i (@warning) {
209 sub get_running_procs {
211 my($regex, $name, $process_list) = @_;
219 foreach $process (keys %{$process_list}) {
221 if ($process =~ /$name/) {
222 $count += $$process_list{$process};
229 if (!defined($count = $$process_list{$name})) {
239 sub get_process_list {
241 my($verbose, $host, $username, $privpassword, $authprotocol, $authpassword, $community, $port, $oidname, $snmp_version) = @_;
242 my(%process_list, %process_pid_list, $result);
243 my $process_list_longest = 1, $not_done = 1;
244 my(@args, @oids, $oid, $name);
246 ($session, $error) = Net::SNMP->session(
248 -community => $community,
250 -version => $snmp_version,
251 defined($privpassword) ? (-privpassword => $privpassword) : (),
252 defined($authpassword) ? (-authpassword => $authpassword) : (),
253 defined($authprotocol) ? (-authprotocol => $authprotocol) : (),
254 defined($username) ? (-username => $username) : ());
256 if (!defined($session)) {
257 print ("UNKNOWN: $error\n");
258 exit $ERRORS{'UNKNOWN'};
261 @args = (-varbindlist => [$OIDS{$oidname}]);
263 if ($session->version == SNMP_VERSION_1) {
265 while (defined($session->get_next_request(@args))) {
267 $oid = (keys(%{$session->var_bind_list}))[0];
269 last if (!oid_base_match($OIDS{$oidname}, $oid));
271 $name = $session->var_bind_list->{$oid};
272 $process_list{$name}++;
274 if ($verbose && ($process_list_longest < length($name))) {
275 $process_list_longest = length($name);
278 @args = (-varbindlist => [$oid]);
283 push(@args, -maxrepetitions => 25);
285 while ($not_done && defined($session->get_bulk_request(@args))) {
287 @oids = oid_lex_sort(keys(%{$session->var_bind_list}));
289 foreach $oid (@oids) {
290 if (!oid_base_match($OIDS{$oidname}, $oid)) {
296 $name = $session->var_bind_list->{$oid};
297 $process_list{$name}++;
299 if ($verbose && ($process_list_longest < length($name))) {
300 $process_list_longest = length($name);
303 if ($session->var_bind_list->{$oid} eq 'endOfMibView') {
310 @args = (-maxrepetitions => 25, -varbindlist => [pop(@oids)]);
315 if ($session->error() ne '') {
316 print ("UNKNOWN: " . $session->error() . "\n");
317 exit $ERRORS{'UNKNOWN'};
322 return($process_list_longest, %process_list);
327 sub parse_wanted_procs {
329 my($verbose, $wanted_procs, $warning, $critical) = @_;
331 my(@procs, $process, $i, $critical_low, $critical_high, $warn_low, $warn_high, $process_name, $process_min);
332 my(@process_array, @warn_array, @critical_array);
334 my $longest_name = 1;
336 if (defined($wanted_procs)) {
337 @process_array = split(/,/, $wanted_procs);
340 if (defined($warning)) {
341 @warn_array = split(/,/, $warning);
344 if (defined($critical)) {
345 @critical_array = split(/,/, $critical);
348 if( defined($warning) && $#process_array != $#warn_array ) {
350 print "Error: Number of entries in process list($#process_array) and warn list($#warn_array) don't match\n";
351 exit $ERRORS{'UNKNOWN'};
354 if( defined($critical) && $#process_array != $#critical_array ) {
356 print "Error: Number of entries in process list and critical list don't match\n";
357 exit $ERRORS{'UNKNOWN'};
360 for ($i = 0; $i <= $#process_array; $i++) {
362 if ((($process_name, $process_min) = split(/:/, $process_array[$i])) != 2) {
367 if ($verbose && ($longest_name < length($process_name))) {
369 $longest_name = length($process_name);
372 if (defined($critical_array[$i])) {
373 if ((($critical_low, $critical_high) = split(/:/, $critical_array[$i])) != 2) {
375 $critical_high = $critical_low;
379 if ($critical_high eq "") {
380 $critical_high = $max_no_processes;
383 if ($critical_low eq "") {
393 if (defined($warn_array[$i])) {
394 if ((($warn_low, $warn_high) = split(/:/, $warn_array[$i])) != 2) {
396 $warn_high = $warn_low;
400 if ($warn_high eq "") {
401 $warn_high = $max_no_processes;
404 if ($warn_low eq "") {
414 if ($critical_low > $critical_high) {
415 print "Error: $process_name critical low($critical_low) is larger than high($critical_high)\n";
419 if ($warn_low > $warn_high) {
420 print "Error: $process_name warn low($warn_low) is larger than high($warn_high)\n";
424 if (@critical_array &&
425 ($process_min > $critical_low)) {
426 print "Error: $process_name minimum($process_min) is larger than critical low($critical_low)\n";
431 ($process_min > $warn_low)) {
432 print "Error: $process_name minimum($process_min) is larger than warn low($warn_low)\n";
436 if (@warn_array && @critical_array &&
437 ((($warn_low >= $critical_low) && ($warn_low <= $critical_high)) ||
438 (($warn_high >= $critical_low) && ($warn_high <= $critical_high)))) {
440 print "Error: $process_name warn levels($warn_low:$warn_high) overlap with critical levels($critical_low:$critical_high)\n";
445 name => $process_name,
446 critical => defined($critical),
447 critical_low => $critical_low,
448 critical_high => $critical_high,
449 minimum => $process_min,
450 warning => defined($warning),
451 warn_low => $warn_low,
452 warn_high => $warn_high});
456 exit $ERRORS{'UNKNOWN'};
459 return($longest_name, @procs);
466 my ($longest_current, $current_process_list, $longest_wanted, @wanted_procs) = @_;
468 if ($longest_wanted < 7) {
474 printf("%s---------------------------------------------\n", "-" x $longest_wanted);
475 printf("|%-" . $longest_wanted . "s | | Min | Warn | Critical |\n", "Process");
476 printf("|%-" . $longest_wanted . "s | Qty | Procs| Low | High | Low | High |\n", "Name");
477 printf("%s---------------------------------------------\n", "-" x $longest_wanted);
479 for (my $temp=0; $temp <= $#wanted_procs; $temp++) {
481 printf("|%-" . $longest_wanted . "s |%6d|%6d|%6d|%6d|%6d|%6d|\n",
482 $wanted_procs[$temp]{name},
483 $wanted_procs[$temp]{no_matches},
484 $wanted_procs[$temp]{minimum},
485 $wanted_procs[$temp]{critical_low},
486 $wanted_procs[$temp]{critical_high},
487 $wanted_procs[$temp]{warn_low},
488 $wanted_procs[$temp]{warn_high});
491 printf("%s---------------------------------------------\n\n", "-" x $longest_wanted);
493 if ($longest_current < 7) {
494 $longest_current = 7;
499 printf("%s----------\n", "-" x $longest_current);
500 printf("|%-" . $longest_current . "s | Qty |\n", "Process");
501 printf("%s----------\n", "-" x $longest_current);
503 foreach my $result (sort keys %{$current_process_list}) {
505 printf("|%-" . $longest_current . "s |%6d|\n", $result,
506 $current_process_list{$result});
508 printf("%s----------\n", "-" x $longest_current);
517 $PROGNAME -H <host> [-r] [-v]
518 -N <processname>[:minimum][,<processname>[:minimum] ...]
519 [-a <authprotocol>] [-A <authpassword>]
520 [-U <username>] [-P <password>]
521 [-o <oidname>] [ -S <snmpversion> ]
522 [-C <snmp_community>] [-p <port>] [-t <timeout>]
523 [-w <low>:<high>[,<low>:<high> ...]
524 [-c <low>:<high>[,<low>:<high> ...]
525 $PROGNAME (-h | --help) for detailed help
526 $PROGNAME (-V | --version) for version information\n";
532 print_revision($PROGNAME, "\$Revision: 1771 $REVISION \$");
533 print "Copyright (c) 2003 David Alden
535 Check if processes are running on a host via snmp
542 -a, --authprotocol=<authprotocol>
543 Set the authentication protocol used for authenticated SNMPv3 messages
544 -A, --authpassword=<authpassword>
545 Set the authentication pass phrase used for authenticated SNMPv3 messages
546 -c, --critical=<low>:<high>[,<low>:<high> ...]
547 exit with CRITICAL status if number of processes is between <low> and <high>
548 -C, --community=<snmp_community>
549 SNMP read community (default: $opt_community)
551 Show this help screen
553 Check processes on the indiciated host
554 -o, --oidname=<oidname>
555 Which oid tree to search, hrSWRunName or hrSWRunPath (default: $opt_oidname)
557 Make connection on the indicated port (default: $opt_port)
558 -N, --names=<processname>[:<minimum>][,<processname>[:<minimum>] ...]
559 Process names to check, (optional) minimum number of processes (default: 1)
560 -P, --password=<privpassword>
561 Set the privacy pass phrase used for encrypted SNMPv3 messages
563 Use regular expression match for <process>
565 Use snmp version specified (values: 1|2c|3, default: $opt_snmp_version)
567 Plugin time out in seconds (default: $opt_timeout)
568 -U, --username=<securityname>
569 Set the securityname used for encrypted SNMPv3 messages
571 Print some extra debugging information (not advised for normal operation)
573 Show version and license information
574 -w, --warning=<low>:<high>[,<low>:<high> ...]
575 exit with WARNING status if number of processes is between <low> and <high>
578 A CRITICAL error will be indicated unless there are at least <minimum> number
579 of processes running (unless <minimum> is set to 0 -- useful if you don't
580 mind that there are none of the processes running).
582 If no processes are specified, the program will still connect to the remote
583 host and download the current list of running processes. It will then exit
584 with an OK (unless it wasn't able to connect) -- useful if you want to make
585 sure that the remote snmpd process is running and returning a list of procs.