Let check_ntp_peer check the number of truechimers
[monitoring-plugins.git] / contrib / check_snmp_procs.pl
blob4d19ff17154765b724c335af43b569ab71111f9f
1 #!/usr/bin/perl -w
3 # check_snmp_procs.pl
4 # Nagios script to check processes on remote host via snmp
6 #
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.
24 # History
25 # -------
26 # 02-25-2003 - Dave Alden <alden@math.ohio-state.edu>
27 # Initial creation
30 # TODO
31 # ----
32 # make it work with snmp version 3
33 # Suggestions???
35 #use strict;
36 use Getopt::Long;
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";
42 my $REVISION="1.0";
45 my $opt_authprotocol;
46 my $opt_authpassword;
47 my $opt_community = 'ma4read';
48 my $opt_critical;
49 my $opt_help;
50 my $opt_host = 'euler';
51 my $opt_oidname = 'hrSWRunName';
52 my $opt_port = 161;
53 my $opt_privpassword;
54 my $opt_regexp = 0;
55 my $opt_snmp_version = '2c';
56 my $opt_timeout = $utils::TIMEOUT;
57 my $opt_username;
58 my $opt_verbose;
59 my $opt_version;
60 my $opt_wanted_procs;
61 my $opt_warning;
64 my $max_no_processes = 999999;
65 my $session;
66 my $error;
67 my $no_procs;
68 my $exit_status;
71 my @wanted_procs;
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}));
82 $ENV{'PATH'}='';
83 $ENV{'BASH_ENV'}='';
84 $ENV{'ENV'}='';
87 Getopt::Long::Configure('bundling');
88 if (GetOptions(
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)
106 == 0) {
107 print_usage();
108 exit $ERRORS{'UNKNOWN'};
111 if ($opt_version) {
112 print_revision($PROGNAME, "\$Revision: 1771 $REVISION \$");
113 exit $ERRORS{'OK'};
116 if ($opt_help) {
117 print_help();
118 exit $ERRORS{'OK'};
121 if (! utils::is_hostname($opt_host)){
122 usage();
123 exit $ERRORS{'UNKNOWN'};
126 ($longest_wanted, @wanted_procs) = parse_wanted_procs($opt_verbose, $opt_wanted_procs, $opt_warning, $opt_critical);
128 $SIG{'ALRM'} = sub {
129 print "Timeout: No Answer from Client\n";
130 exit $ERRORS{'UNKNOWN'};
132 alarm($opt_timeout);
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);
138 if ($opt_verbose) {
139 print_info($longest_current, \%current_process_list, $longest_wanted, @wanted_procs);
142 exit($exit_status);
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'};
179 print "SNMPPROC ";
181 if ($#critical >= 0) {
182 print "CRITICAL:";
183 } elsif ($#warning >= 0) {
184 print "WARNING:";
185 } else {
186 print "OK";
189 foreach $i (@critical) {
190 print " $i";
193 if (($#critical >= 0) &&
194 ($#warning >= 0)) {
195 print " WARNING:";
198 foreach $i (@warning) {
199 print " $i";
202 print "\n";
204 return $exit;
209 sub get_running_procs {
211 my($regex, $name, $process_list) = @_;
212 my $count = 0;
213 my $process;
215 $count = 0;
217 if ($regex) {
219 foreach $process (keys %{$process_list}) {
221 if ($process =~ /$name/) {
222 $count += $$process_list{$process};
227 } else {
229 if (!defined($count = $$process_list{$name})) {
230 $count = 0;
234 return $count;
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(
247 -hostname => $host,
248 -community => $community,
249 -port => $port,
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]);
281 } else {
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)) {
292 $not_done = 0;
294 } else {
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') {
304 $not_done = 0;
309 if ($not_done) {
310 @args = (-maxrepetitions => 25, -varbindlist => [pop(@oids)]);
315 if ($session->error() ne '') {
316 print ("UNKNOWN: " . $session->error() . "\n");
317 exit $ERRORS{'UNKNOWN'};
320 $session->close;
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);
333 my $exit = 0;
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) {
364 $process_min = 1;
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;
377 } else {
379 if ($critical_high eq "") {
380 $critical_high = $max_no_processes;
383 if ($critical_low eq "") {
384 $critical_low = 0;
387 } else {
389 $critical_low = -1;
390 $critical_high = -1;
393 if (defined($warn_array[$i])) {
394 if ((($warn_low, $warn_high) = split(/:/, $warn_array[$i])) != 2) {
396 $warn_high = $warn_low;
398 } else {
400 if ($warn_high eq "") {
401 $warn_high = $max_no_processes;
404 if ($warn_low eq "") {
405 $warn_low = 0;
408 } else {
410 $warn_low = -1;
411 $warn_high = -1;
414 if ($critical_low > $critical_high) {
415 print "Error: $process_name critical low($critical_low) is larger than high($critical_high)\n";
416 $exit = 1;
419 if ($warn_low > $warn_high) {
420 print "Error: $process_name warn low($warn_low) is larger than high($warn_high)\n";
421 $exit = 1;
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";
427 $exit = 1;
430 if (@warn_array &&
431 ($process_min > $warn_low)) {
432 print "Error: $process_name minimum($process_min) is larger than warn low($warn_low)\n";
433 $exit = 1;
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";
441 $exit = 1;
444 push(@procs,{
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});
455 if ($exit) {
456 exit $ERRORS{'UNKNOWN'};
459 return($longest_name, @procs);
464 sub print_info {
466 my ($longest_current, $current_process_list, $longest_wanted, @wanted_procs) = @_;
468 if ($longest_wanted < 7) {
469 $longest_wanted = 7;
470 } else {
471 $longest_wanted++;
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;
495 } else {
496 $longest_current++;
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);
510 return;
515 sub print_usage {
516 print "Usage:
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";
531 sub print_help {
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
539 print_usage();
541 print "
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)
550 -h, --help
551 Show this help screen
552 -H, --host=<host>
553 Check processes on the indiciated host
554 -o, --oidname=<oidname>
555 Which oid tree to search, hrSWRunName or hrSWRunPath (default: $opt_oidname)
556 -p, --port=<port>
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
562 -r, --regex
563 Use regular expression match for <process>
564 -S, --snmpversion
565 Use snmp version specified (values: 1|2c|3, default: $opt_snmp_version)
566 -t, --timeout
567 Plugin time out in seconds (default: $opt_timeout)
568 -U, --username=<securityname>
569 Set the securityname used for encrypted SNMPv3 messages
570 -v, --verbose
571 Print some extra debugging information (not advised for normal operation)
572 -V, --version
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.
589 support();