Code

new plugins contrib
[nagiosplug.git] / contrib / check_snmp_process_monitor.pl
1 #!/usr/local/bin/perl
2 # author: Al Tobey <albert.tobey@priority-health.com>
3 # what:   monitor a process using the host-resources mib
4 # license: GPL - http://www.fsf.org/licenses/gpl.txt
5 #
6 # Todo:
7 # * implement memory and cpu utilization checks
8 # * maybe cache pids in DBM files if snmp agents get overworked
9 ###############################################################################
10 # to get a list of processes over snmp try this command:
11 # snmptable -v2c -c public hostname hrSWRunTable
12 # for just a list of valid arguments for the '-e' option:
13 # snmpwalk -v2c -c public hostname hrSWRunName |perl -pe 's:.*/::'
14 ###############################################################################
16 use strict;
17 require 5.6.0;
18 use lib qw( /opt/nagios/libexec /usr/local/libexec );
19 use utils qw(%ERRORS $TIMEOUT &print_revision &support &usage);
20 use SNMP 5.0;
21 use Getopt::Long;
22 use vars qw( $exit $opt_version $opt_timeout $opt_help $opt_command $opt_host $opt_community $opt_verbose $opt_warning $opt_critical $opt_memory $opt_cpu $opt_port $opt_regex $opt_stats %processes $snmp_session $PROGNAME $TIMEOUT );
24 $PROGNAME      = "snmp_process_monitor.pl";
25 $opt_verbose   = undef;
26 $opt_host      = undef;
27 $opt_community = 'public';
28 $opt_command   = undef;
29 $opt_warning   = [ 1, -1 ];
30 $opt_critical  = [ 1, -1 ];
31 $opt_memory    = undef;
32 $opt_cpu       = undef;
33 $opt_port      = 161;
34 %processes     = ();
35 $exit          = 'OK';
37 sub process_options {
38     my( $opt_crit, $opt_warn ) = ();
39     Getopt::Long::Configure( 'bundling' );
40     GetOptions(
41         'V'     => \$opt_version,       'version'     => \$opt_version,
42         'v'     => \$opt_verbose,       'verbose'     => \$opt_verbose,
43         'h'     => \$opt_help,          'help'        => \$opt_help,
44         's'     => \$opt_stats,         'statistics'  => \$opt_stats,
45         'H:s'   => \$opt_host,          'hostname:s'  => \$opt_host,
46         'p:i'   => \$opt_port,          'port:i'      => \$opt_port,
47         'C:s'   => \$opt_community,     'community:s' => \$opt_community,
48         'c:s'   => \$opt_crit,          'critical:s'  => \$opt_crit,
49         'w:s'   => \$opt_warn,          'warning:s'   => \$opt_warn,
50         't:i'   => \$TIMEOUT,           'timeout:i'   => \$TIMEOUT,    
51         'e:s'   => \$opt_command,       'command:s'   => \$opt_command,
52         'r:s'   => \$opt_regex,         'regex:s'     => \$opt_regex,
53         'cpu:i' => \$opt_cpu,           'memory:i'    => \$opt_memory,
54     );
55     if ( defined($opt_version) ) { local_print_revision(); }
56     if ( defined($opt_verbose) ) { $SNMP::debugging = 1; }
57     if ( !defined($opt_host) || defined($opt_help) || (!defined($opt_command) && !defined($opt_regex)) ) {
58         print_help();
59         exit $ERRORS{UNKNOWN};
60     }
62     if ( defined($opt_crit) ) {
63         if ( $opt_crit =~ /,/ ) {
64             $opt_critical = [ split(',', $opt_crit) ];
65         }
66         else {
67             $opt_critical = [ $opt_crit, -1 ];
68         }
69     }
70     if ( defined($opt_warn) ) {
71         if ( $opt_warn =~ /,/ ) {
72             $opt_warning = [ split(',', $opt_warn) ];
73         }
74         else {
75             $opt_warning = [ $opt_crit, -1 ];
76         }
77     }
78 }
80 sub local_print_revision {
81         print_revision( $PROGNAME, '$Revision$ ' )
82 }
84 sub print_usage {
85     print "Usage: $PROGNAME -H <host> -C <snmp_community> -e <command> [-w <low>,<high>] [-c <low>,<high>] [-t <timeout>]\n";
86 }
88 sub print_help {
89     local_print_revision();
90     print "Copyright (c) 2002 Al Tobey <albert.tobey\@priority-health.com>\n\n",
91           "SNMP Process Monitor plugin for Nagios\n\n";
92     print_usage();
93     print <<EOT;
94 -v, --verbose
95    print extra debugging information
96 -h, --help
97    print this help message
98 -H, --hostname=HOST
99    name or IP address of host to check
100 -C, --community=COMMUNITY NAME
101    community name for the host's SNMP agent
102 -e, --command=COMMAND NAME (ps -e style)
103    what command should be monitored?
104 -r, --regex=Perl RE
105    use a perl regular expression to find your process
106 -w, --warning=INTEGER[,INTEGER]
107    minimum and maximum number of processes before a warning is issued (Default 1,-1)
108 -c, --critical=INTEGER[,INTEGER]
109    minimum and maximum number of processes before a critical is issued (Default 1,-1)
110 EOT
113 sub verbose (@) {
114     return if ( !defined($opt_verbose) );
115     print @_;
118 sub check_for_errors {
119     if ( $snmp_session->{ErrorNum} ) {
120         print "UNKNOWN - error retrieving SNMP data: $snmp_session->{ErrorStr}\n";
121         exit $ERRORS{UNKNOWN};
122     }
125 # =========================================================================== #
126 # =====> MAIN
127 # =========================================================================== #
128 process_options();
130 alarm( $TIMEOUT ); # make sure we don't hang Nagios
132 $snmp_session = new SNMP::Session(
133     DestHost => $opt_host,
134     Community => $opt_community,
135     RemotePort => $opt_port,
136     Version   => '2c'
137 );
139 my $process_count = SNMP::Varbind->new( ['hrSystemProcesses', 0] );
140 $snmp_session->get( $process_count ); 
141 check_for_errors();
143 # retrieve the data from the remote host
144 my( $names, $index ) = $snmp_session->bulkwalk( 0, $process_count->val, [['hrSWRunName'], ['hrSWRunIndex']] );
145 check_for_errors();
147 alarm( 0 ); # all done with the network connection
149 my %namecount = ();
150 foreach my $row ( @$names ) {
151     $processes{$row->iid}->{name} = $row->val;
152     $processes{$row->iid}->{name} =~ s#.*/##; # strip path
154     if ( defined($opt_regex) ||
155         ($row->val =~ /(perl|\/usr\/bin\/sh|\/bin\/bash|\/bin\/sh)$/
156         && $opt_command !~ /(perl|\/usr\/bin\/sh|\/bin\/bash|\/bin\/sh)$/) ) {
158         # fetch the runtime parameters of the process
159         my $parm_var = SNMP::Varbind->new( ['hrSWRunParameters', $row->iid] );
160         $snmp_session->get( $parm_var );
161         check_for_errors();
163         # only strip if we're looking for a specific command
164         if ( defined($opt_command) ) {
165             verbose "process ",$row->iid," uses $1 as an interpreter - getting parameters\n";
166             $processes{$row->iid}->{name} = $parm_var->val;
167             # strip path name off the front
168             $processes{$row->iid}->{name} =~ s#.*/##;
169             # strip everything from the first space to the end
170             $processes{$row->iid}->{name} =~ s/\s+.*$//;
171         }
172         else {
173             # get the longer full-path style listing
174             my $path_var = SNMP::Varbind->new( ['hrSWRunPath', $row->iid] );
175             $snmp_session->get( $path_var );
176             check_for_errors();
178             # use the full 'ps -efl' style listing for regular expression matching
179             $processes{$row->iid}->{name} = $path_var->val.' '.$parm_var->val;
180         }
181     }
183 foreach my $row ( @$index ) {
184     $processes{$row->iid}->{pid}  = $row->val;
187 my @pids    = ();
188 my @matches = ();
189 foreach my $key ( keys(%processes) ) {
190     if ( defined($opt_command) && $processes{$key}->{name} eq $opt_command ) {
191         push( @matches, $processes{$key} );
192         push( @pids, $processes{$key}->{pid} );
193         verbose "process '$processes{$key}->{name}' has pid ",
194             "$processes{$key}->{pid} and index $key\n";
195     }
196     elsif ( defined($opt_regex) && $processes{$key}->{name} =~ /$opt_regex/o ) {
197         push( @matches, $processes{$key} );
198         push( @pids, $processes{$key}->{pid} );
199         verbose "process '$processes{$key}->{name}' has pid ",
200             "$processes{$key}->{pid} and index $key\n";
201     }
203 my $count = @matches;
205 # warning, critical
206 if ( ($opt_warning->[0] > 0 && $opt_warning->[0]  >  $count)
207   || ($opt_warning->[1] > 0 && $opt_warning->[1]  <= $count) ) {
208     $exit = 'WARNING';
210 if ( ($opt_critical->[0] > 0 && $opt_critical->[0]  >  $count)
211   || ($opt_critical->[1] > 0 && $opt_critical->[1]  <= $count) ) {
212     $exit = 'CRITICAL';
215 print "$exit - $count processes with pid(s) ",join(',',@pids);
217 # print the number of processes if statistics are requested
218 if ( defined($opt_stats) ) {
219     print "|count:$count\n";
221 else {
222     print "\n";
225 exit $ERRORS{$exit};