[BACK]Return to check_hw_sensors CVS log [TXT][DIR] Up to [local] / nagios / check_hw_sensors

Diff for /nagios/check_hw_sensors/check_hw_sensors between version 1.6 and 1.22

version 1.6, 2006/05/02 20:59:47 version 1.22, 2007/01/06 03:16:41
Line 1 
Line 1 
 #!/usr/bin/perl  #!/usr/bin/perl -T
 # $RedRiver: check_hw_sensors,v 1.5 2006/05/02 19:49:29 andrew Exp $  # $RedRiver: check_hw_sensors,v 1.21 2006/12/05 16:26:27 andrew Exp $
 ########################################################################  ########################################################################
 # check_hw_sensors *** A nagios check for OpenBSD hw.sensors  # check_hw_sensors *** A nagios check for OpenBSD hw.sensors
 #  #
 # 2006.05.01 #*#*# andrew fresh <andrew@mad-techies.org>  # 2006.05.01 #*#*# andrew fresh <andrew@mad-techies.org>
 ########################################################################  ########################################################################
 # TODO:  # TODO:
 #   Really need to fix the documentation issue.  #   Really need real documentation.
 #  
 #   I want the ability to just check the "status" entry that is in some output.  For example the OK here:  
 #     hw.sensors.1=esm0, CPU 1, OK, temp, 31.00 degC / 87.80 degF  
 ########################################################################  ########################################################################
 use strict;  use strict;
 use warnings;  use warnings;
   
 #use Data::Dumper;  %ENV = ();
   
 use constant NAGIOS_OUTPUT => 1;  use constant NAGIOS_OUTPUT => 0;
   
 use POSIX;  use POSIX;
   use Config;
 use lib "/usr/local/libexec/nagios";  use lib "/usr/local/libexec/nagios";
 #use lib $ENV{'HOME'};  
 use utils qw($TIMEOUT %ERRORS &print_revision &support);  use utils qw($TIMEOUT %ERRORS &print_revision &support);
   
 use Getopt::Long;  use Getopt::Long;
Line 32 
Line 29 
 my $GETCAP = '/usr/bin/getcap';  my $GETCAP = '/usr/bin/getcap';
 my $BASE   = 'hw.sensors';  my $BASE   = 'hw.sensors';
 my $DEFAULT_CONFIG = '/etc/sensorsd.conf';  my $DEFAULT_CONFIG = '/etc/sensorsd.conf';
   my $OSVer = $Config{'osvers'} || 0;
   
 my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK  my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK
 my %states; # This stores the count of states;  my %states; # This stores the count of states;
 my $filename;  my $filename;
   my $ignore_status;
 my $sensor;  my $sensor;
 my $warning;  my $warning;
 my $critical;  my $critical;
 my $opt_h ;  my $opt_h;
 my $opt_V ;  my $opt_V;
   
 my $CHECK_SENSOR = $BASE;  my $CHECK_SENSOR = $BASE;
 my %CHECKS;  my %CHECKS;
Line 48 
Line 47 
   
 #Option checking  #Option checking
 my $status = GetOptions(  my $status = GetOptions(
         "version|V"    => \$opt_V,          "version|V"       => \$opt_V,
         "help|h"       => \$opt_h,          "filename|f:s"    => \$filename,
         "filename|f:s" => \$filename,          "ignore-status|i" => \$ignore_status,
         "sensor|s=s"   => \$sensor,          "sensor|s=s"      => \$sensor,
         "warning|w=s"  => \$warning,          "warning|w=s"     => \$warning,
         "critical|c=s" => \$critical,          "critical|c=s"    => \$critical,
 );  );
   
 # set the default this way so it only happens if someone typed -f or --filename  # set the default this way so it only happens if someone typed -f or --filename
 $filename = $DEFAULT_CONFIG if (defined $filename && $filename eq '');  $filename = $DEFAULT_CONFIG if (defined $filename && $filename eq '');
   
   # Stuff is output in this file by print_sensor()
   # http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/sysctl/sysctl.c
   my @Type_Map = (
           {
                   type  => 'temp',
                   regex => qr/\sdegC$/,
           },
           {
                   type  => 'fanrpm',
                   regex => qr/\sRPM$/,
           },
           {
                   type  => 'volts_dc',
                   regex => qr/\sV\sDC$/,
           },
           {
                   type  => 'amps',
                   regex => qr/\sA$/,
           },
           {
                   type  => 'watthour',
                   regex => qr/\sWh$/,
           },
           {
                   type  => 'amphour',
                   regex => qr/\sAh$/,
           },
           {
                   type  => 'indicator',
                   regex => qr/^(On|Off)$/,
           },
           {
                   type  => 'integer',
                   regex => qr/\sraw$/,
           },
           {
                   type  => 'percent',
                   regex => qr/\s\%$/,
           },
           {
                   type  => 'lux',
                   regex => qr/\slx$/,
           },
           {
                   type  => 'drive',
                   regex => qr/^drive\s/,
           },
           {
                   type  => 'timedelta',
                   regex => qr/\ssecs$/,
           },
   );
   
 if ($status == 0) {  if ($status == 0) {
         print_help() ;          print_help() ;
         exit $ERRORS{'OK'};          exit $ERRORS{'OK'};
Line 69 
Line 121 
         exit $ERRORS{'OK'};          exit $ERRORS{'OK'};
 }  }
   
 if ($opt_h) {  unless (
         print_help();          (
         exit $ERRORS{'OK'};                  defined $filename ||
 }                  (not defined $ignore_status) ||
                   (defined $sensor && ($warning || $critical))
 unless ( (           ) &&
                 defined $filename ||           ( (!defined $filename) || (!defined $sensor) )
                 (defined $sensor && ($warning || $critical))  
          ) &&  
                 ( (!defined $filename) || (!defined $sensor) )  
 ) {  ) {
         print_help();          print_help();
         exit $ERRORS{'OK'};          exit $ERRORS{'OK'};
Line 91 
Line 140 
         }          }
         $CHECK_SENSOR = $sensor;          $CHECK_SENSOR = $sensor;
   
         $CHECKS{$sensor} = {          $CHECKS{$sensor}{'warn'} = $warning  if defined $warning;
                 'warn' => $warning,          $CHECKS{$sensor}{'crit'} = $critical if defined $critical;
                 'crit' => $critical,  
         };  
 } elsif (defined $filename) {  } elsif (defined $filename) {
         %CHECKS = parse_file($filename);          %CHECKS = parse_file($filename);
 }  }
Line 105 
Line 153 
 #while (<>) {  #while (<>) {
         chomp;          chomp;
         my ($id, $output) = split /=/;          my ($id, $output) = split /=/;
           my @s = split /\./, $id;
         my @o = split /,\s*/, $output;          my @o = split /,\s*/, $output;
   
         my $source = $o[0];          my ($type, $source, $descr, $data, $status);
         my $descr  = $o[1];  
         my $status = $o[2] if @o == 5;  
         my $type   = $o[-2];  
         my $data   = $o[-1];  
   
           $source = $o[0];
           $descr  = $o[1];
   
           if (@s == 4) { # XXX This mebbe needs to end up $OSVer >= 4.1
                   $data   = $o[0];
                   $descr =~ s/^\(|\)$//g;
                   $status = $o[2];
                   ($source, $type) = $id =~ /([^\.]+)\.([^\.]+)\d+$/;
           } elsif ($OSVer >= 4.0) {
                   $data   = $o[2];
                   $status = $o[3];
                   foreach my $t (@Type_Map) {
                           if ($data =~ /$t->{'regex'}/) {
                                   $type = $t->{'type'};
                                   last;
                           }
                   }
           }  else {
                   $data   = $o[-1];
                   $status = $o[2] if @o == 5;
                   $type   = $o[-2];
           }
   
           $type ||= 'unknown';
   
         $SENSORS{$id} = {          $SENSORS{$id} = {
                 id          => $id,                  id          => $id,
                 output      => $output,                  output      => $output,
Line 134 
Line 204 
         $_a <=> $_b;          $_a <=> $_b;
 }  }
   
 foreach my $check (sort as_if_numeric keys %CHECKS) {  foreach my $s (sort as_if_numeric keys %SENSORS) {
         if (exists $SENSORS{$check}) {          my ($r, $data);
                 my $r = check_sensor($CHECKS{$check}, $SENSORS{$check});          if (exists $CHECKS{$s}) {
                 push @{ $states{ $r } },                  $r    = check_sensor($SENSORS{$s}, $CHECKS{$s});
                         $check . '=' . $SENSORS{$check}{'output'};                  $data = $s . '=' . $SENSORS{$s}{'output'};
           } elsif (not $ignore_status) {
                   $r = check_sensor($SENSORS{$s});
                   $data = $s . '=' . $SENSORS{$s}{'output'};
         } else {          } else {
                 # XXX Error missing sensor                  # ignore this sensor
                 push @{ $states{'UNKNOWN'} }, $check . '=No sensor with this id';  
         }          }
           next unless defined $r;
           push @{ $states{ $r } }, $data;
 }  }
   
 #print Dumper \%states;  
   
 $state = 'OK';  $state = 'OK';
 my $have_results = 0;  my $have_results = 0;
 foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) {  foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) {
Line 155 
Line 227 
                 $state = $error;                  $state = $error;
         }          }
 }  }
 if (NAGIOS_OUTPUT && $have_results) {  
         print '<ul>';  
 }  
 foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) {  foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) {
         if (exists $states{$error}) {          if (exists $states{$error}) {
                 if (NAGIOS_OUTPUT) {                  if (NAGIOS_OUTPUT) {
                         print "<li>$error (" . scalar(@{ $states{ $error } }) . ")";                          print "$error (" . scalar(@{ $states{ $error } }) . ")";
                         unless ($error eq 'OK') {                          unless ($error eq 'OK') {
                                 print '<ul>';                                  print '<br>';
                                 foreach (@{ $states{ $error } }) {                                  print map {" - $_<br>"} @{ $states{ $error } };
                                         print "<li>$_</li>";  
                                 }  
                                 print '</ul>';  
                         }                          }
                         print "</li>"  
                 } else {                  } else {
                         print "$error (" . scalar(@{ $states{ $error } }) . "):\n";                          print "$error (" . scalar(@{ $states{ $error } }) . "):\n";
                         foreach (@{ $states{ $error } }) {                          foreach (@{ $states{ $error } }) {
Line 181 
Line 246 
 if ($have_results == 0) {  if ($have_results == 0) {
         print "No results found\n";          print "No results found\n";
 }  }
 if (NAGIOS_OUTPUT && $have_results) {  
         print '</ul>' . "\n";  
 }  
 exit $ERRORS{$state};  exit $ERRORS{$state};
   
   
 sub parse_file {  sub parse_file {
         my $filename = shift;          my $filename = shift;
         my %contents;          my %contents;
   
           die "file '$filename' does not exist." unless -e $filename;
   
         open my $fh, '-|', $GETCAP, '-a', '-f', $filename          open my $fh, '-|', $GETCAP, '-a', '-f', $filename
                 or die "Couldn't open FILE '$GETCAP -a -f $filename': $!";                  or die "Couldn't open FILE '$GETCAP -a -f $filename': $!";
         while (<$fh>) {          LINE: while (<$fh>) {
                 chomp;                  chomp;
                 my ($key, @c) = split /\:/;                  my ($key, @c) = split /\:/;
                 foreach (@c) {                  foreach (@c) {
                         my ($k, $v) = split /\=/;                          my ($k, $v) = split /\=/;
                         $contents{$key}{$k} = $v;                          if (lc($k) eq 'ignore') {
                                   $contents{$key}{'IGNORE'} = 1;
                           } elsif (lc($k) eq 'status') {
                                   $contents{$key}{'STATUS'} = 1;
                           } else {
                                   $contents{$key}{$k} = $v;
                           }
                 }                  }
         }          }
         close $fh;          close $fh;
Line 210 
Line 280 
         my $type  = shift;          my $type  = shift;
         my $check = shift;          my $check = shift;
   
         if (defined $check->{'warn'} && $check->{'warn'} =~ /:/) {          return undef unless $check;
                 if (my ($low, $high) = split /:/, $check->{'warn'}) {          return undef    if $check->{'STATUS'};
                         $check->{'warn.low'}  = $low;          return 'IGNORE' if $check->{'IGNORE'};
                         $check->{'warn.high'} = $high;  
           foreach my $code ('crit', 'warn') {
                   if (defined $check->{$code} && $check->{$code} =~ /:/) {
                           if (my ($low, $high) = split /:/, $check->{$code}) {
                                   $check->{$code . '.low'}  = $low;
                                   $check->{$code . '.high'} = $high;
                           }
                           delete $check->{$code};
                 }                  }
                 delete $check->{'warn'};  
         }                  foreach my $severity ('low', 'high') {
         if (defined $check->{'crit'} && $check->{'crit'} =~ /:/) {                          if (defined $check->{$severity}) {
                 if (my ($low, $high) = split /:/, $check->{'crit'}) {                                  $check->{ $code . '.' . $severity } = $check->{$severity}
                         $check->{'crit.low'}  = $low;                                          unless defined $check->{ $code . '.' . $severity };
                         $check->{'crit.high'} = $high;                          }
                 }                  }
                 delete $check->{'crit'};                  no warnings 'uninitialized';
                   $check->{$code} = [ split /,\s*/, $check->{$code} ];
         }          }
   
         if (defined $check->{'low'}) {  
                 $check->{'warn.low'} = $check->{'low'}  
                         unless defined $check->{'warn.low'};  
                 $check->{'crit.low'} = $check->{'low'}  
                         unless defined $check->{'crit.low'};  
         }  
         if (defined $check->{'high'}) {  
                 $check->{'warn.high'} = $check->{'high'}  
                         unless defined $check->{'warn.high'};  
                 $check->{'crit.high'} = $check->{'high'}  
                         unless defined $check->{'crit.high'};  
         }  
   
         no warnings 'uninitialized';  
         $check->{'warn'} = [ split /,\s*/, $check->{'warn'} ];  
         $check->{'crit'} = [ split /,\s*/, $check->{'crit'} ];  
   
         return $check;          return $check;
 }  }
   
 sub check_sensor {  sub check_sensor {
         my $check  = shift;  
         my $sensor = shift;          my $sensor = shift;
           my $check  = shift;
         my $result = 'UNKNOWN';          my $result = 'UNKNOWN';
         my %errors = (          my %errors = (
                 'warn' => 'WARNING',                  'warn' => 'WARNING',
Line 255 
Line 316 
         );          );
   
         return $result unless ref $sensor eq 'HASH';          return $result unless ref $sensor eq 'HASH';
           $check = parse_check($sensor->{'type'}, $check) if $check;
   
         $check = parse_check($sensor->{'type'}, $check);          # It looks like doing this should be safe, from
         #print Dumper $check, $sensor;          # src/sbin/sysctl/sysctl.c
           return $sensor->{'status'} unless $check;
   
         $result = 'OK';          return undef if $check eq 'IGNORE';
   
           $result = 'OK';
         foreach my $code ('warn', 'crit') {          foreach my $code ('warn', 'crit') {
                 if (                  if (
                         $sensor->{'type'} eq 'volts_dc' ||  
                         $sensor->{'type'} eq 'fanrpm'   ||                          $sensor->{'type'} eq 'fanrpm'   ||
                         $sensor->{'type'} eq 'raw'                          $sensor->{'type'} eq 'volt'     ||
                           $sensor->{'type'} eq 'volts_dc' ||
                           $sensor->{'type'} eq 'amps'     ||
                           $sensor->{'type'} eq 'watthour' ||
                           $sensor->{'type'} eq 'amphour'  ||
                           $sensor->{'type'} eq 'integer'  ||
                           $sensor->{'type'} eq 'raw'      ||
                           $sensor->{'type'} eq 'percent'  ||
                           $sensor->{'type'} eq 'lux'      ||
                           $sensor->{'type'} eq 'timedelta'
                 ) {                  ) {
                         my $data = $sensor->{'data'};                          my $data = $sensor->{'data'};
                         $data =~ s/[^\d\.]//g;                          $data =~ s/[^\d\.]//g;
Line 303 
Line 375 
                                         $result = $errors{$code}                                          $result = $errors{$code}
                                                 if ($c <= $data);                                                  if ($c <= $data);
                                 }                                  }
                         } elsif (defined $check->{$code}) {                          } elsif (@{ $check->{$code} }) {
                                 my $matched = 0;                                  my $matched = 0;
                                 foreach my $c (@{ $check->{$code} }) {                                  foreach my $c (@{ $check->{$code} }) {
                                         $c =~ s/[^\d\.]//g;                                          $c =~ s/[^\d\.]//g;
                                         unless (length $c) {                                          unless (length $c) {
                                                 warn "INVALID CHECK (" . $check->{$code} .                                                  warn "INVALID CHECK (" . $c .
                                                       ") for '$sensor->{'id'}:$code'";                                                        ") for '$sensor->{'id'}:$code'";
                                                 next;                                                  next;
                                         }                                          }
   
                                         if ($_ eq $data) {                                          if ($c eq $data) {
                                                 $matched = 1;                                                  $matched = 1;
                                                 last;                                                  last;
                                         }                                          }
Line 324 
Line 396 
                 } elsif ($sensor->{'type'} eq 'temp') {                  } elsif ($sensor->{'type'} eq 'temp') {
                         my ($degC, $degF) = split /\//, $sensor->{'data'};                          my ($degC, $degF) = split /\//, $sensor->{'data'};
                         $degC =~ s/[^\d\.]//g;                          $degC =~ s/[^\d\.]//g;
                           $degF ||= $degC * 9 / 5 + 32;
                         $degF =~ s/[^\d\.]//g;                          $degF =~ s/[^\d\.]//g;
                         if (                          if (
                                 defined $check->{$code . ".low"} ||                                  defined $check->{$code . ".low"} ||
Line 371 
Line 444 
                                         $result = $errors{$code}                                          $result = $errors{$code}
                                                 if ($c <= $data);                                                  if ($c <= $data);
                                 }                                  }
                         } elsif (defined $check->{$code}) {                          } elsif (@{ $check->{$code} }) {
   
                                 my $matched = 0;                                  my $matched = 0;
                                 foreach my $c (@{ $check->{$code} }) {                                  foreach my $c (@{ $check->{$code} }) {
Line 386 
Line 459 
   
                                         $c =~ s/[^\d\.]//g;                                          $c =~ s/[^\d\.]//g;
                                         unless (length $c) {                                          unless (length $c) {
                                                 warn "INVALID CHECK (" . $check->{$code} .                                                  warn "INVALID CHECK (" . $c .
                                                          ") for '$sensor->{'id'}':$code";                                                           ") for '$sensor->{'id'}':$code";
                                                 next;                                                  next;
                                         }                                          }
   
                                         if ($_ eq $data) {                                          if ($c eq $data) {
                                                 $matched = 1;                                                  $matched = 1;
                                                 last;                                                  last;
                                         }                                          }
Line 403 
Line 476 
                         $sensor->{'type'} eq 'drive' ||                          $sensor->{'type'} eq 'drive' ||
                         $sensor->{'type'} eq 'indicator'                          $sensor->{'type'} eq 'indicator'
                 ) {                  ) {
                         if (defined $check->{$code}) {                          $sensor->{'data'} =~ s/^drive\s+//;
                           if (@{ $check->{$code} }) {
                                 my $matched = 0;                                  my $matched = 0;
                                 foreach (@{ $check->{$code} }) {                                  foreach (@{ $check->{$code} }) {
                                         if ($_ eq $sensor->{'data'}) {                                          if ($_ eq $sensor->{'data'}) {
Line 415 
Line 489 
                         }                          }
   
                 } else {                  } else {
                           print STDERR 'Unknown Sensor Type: ',
                               $sensor->{'id'},
                               '=',
                               $sensor->{'type'},
                               "\n";
                         $result = 'UNKNOWN';                          $result = 'UNKNOWN';
                 }                  }
   
Line 426 
Line 505 
 sub print_help {  sub print_help {
         print <<EOL;          print <<EOL;
 $PROGNAME plugin for Nagios monitors sysctl hw.sensors on OpenBSD  $PROGNAME plugin for Nagios monitors sysctl hw.sensors on OpenBSD
         $PROGNAME (-f [<FILENAME>]|(-s <hw.sensors id> -w limit -c limit))      $PROGNAME [-i] (-f [<FILENAME>]|(-s <hw.sensors id> [-w limit] [-c limit]))
   
 Usage:  Usage:
         -f, --filename=FILE      -i, --ignore-status
                 FILE to load checks from (defaults to /etc/sensorsd.conf)          Don't check the status of sensors that report it.
         -s, --sensor=ID      -f, --filename=FILE
                 ID of a single sensor.  "-s 0" means hw.sensors.0.          FILE to load checks from (defaults to /etc/sensorsd.conf)
         -w, --warning=RANGE or single ENTRY      -s, --sensor=ID
                 Exit with WARNING status if outside of RANGE or if != ENTRY          ID of a single sensor.  "-s 0" means hw.sensors.0.
         -c, --critical=INTEGER      -w, --warning=RANGE or single ENTRY
                 Exit with CRITICAL status if outside of RANGE or if != ENTRY          Exit with WARNING status if outside of RANGE or if != ENTRY
       -c, --critical=RANGE or single ENTRY
           Exit with CRITICAL status if outside of RANGE or if != ENTRY
   
         -h (--help)       usage help  FILE is in the same format as sensorsd.conf(5) plus some additional
   entries.  These additional entries in the file are ignored by
   sensorsd(8).
   
 FILE is in the same format as sensorsd.conf(5).  These additional entries in the file are ignored by sensorsd(8).  $PROGNAME understands the following entries:  $PROGNAME understands the following entries:
         low, high, crit, warn, crit.low, crit.high, warn.low, warn.high  
   
 An ENTRY depends on the type.  The descriptions in sensorsd.conf(5) can be used when appropriate, or you can use the following:      low, high, crit, warn, crit.low, crit.high, warn.low, warn.high,
         volts_dc, fanrpm or raw - Anything that includes digits.  Anything that isn't a digit or period is stripped from the entry and the sensor output and they are compared.      ignore, status
         temp - Can be as above, but if the entry has an F in it, it compares farenheit, otherwise it uses celcius.  
         indicator or drive - does a case sensitive match of each entry in the comma separated list and if it does not match any of the entries, it matches the status.  
   
 The entries 'crit' or 'warn' (or the -c or -w on the command line) may be a RANGE or a comma separated list of acceptable values.  The comma separated list of values contains a list of things that will NOT cause the status.  This is possibly counterintuitive, but you are more likely to know good values than bad values.  An ENTRY depends on the type.  The descriptions in sensorsd.conf(5)
   can be used when appropriate, or you can use the following:
   
 A RANGE is a low ENTRY and a high ENTRY separated by a colon (:).      fanrpm, volts_dc, amps, watthour, amphour, integer (raw), percent,
       lux or timedelta - Anything that includes digits.  Both the value of
       the check and the value of the sensor response that are not either a
       digit or period are stripped and then the two resultant values are
       compared.
   
       temp - Can be as above, but if the entry has an F in it,
       it compares farenheit, otherwise it uses celcius.
   
       indicator or drive - does a case sensitive match of each
       entry in the comma separated list and if it does not match
       any of the entries, it sets the status.
   
   The entries 'crit' or 'warn' (or the -c or -w on the command line)
   may be a RANGE or a comma separated list of acceptable values.
   The comma separated list of values contains a list of things that
   will NOT cause the status.  This is possibly counterintuitive, but
   you are more likely to know good values than bad values.
   
   A RANGE is a low ENTRY and a high ENTRY separated by a colon (:).
   It can also be low: or :high with the other side left blank to only
   make the single check..
   
   An entry marked "ignore" will cause that sensor to be skipped.
   Generally used with state checking of all sensors to ignore sensors you
   don't care about or that report incorrectly.
   
   If you are using --ignore-status, you can still check the status of
   individual sensors with a status entry.
   
 EOL  EOL
   
         print_revision($PROGNAME, '$Revision$');          print_revision($PROGNAME, '$Revision$');
 }  }
   

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.22

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>