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

Annotation of nagios/check_hw_sensors/check_hw_sensors, Revision 1.3

1.2       andrew      1: #!/usr/bin/perl
1.3     ! andrew      2: # $RedRiver: check_hw_sensors,v 1.2 2006/05/02 01:29:33 andrew Exp $
1.2       andrew      3: ########################################################################
                      4: # check_hw_sensors *** A nagios check for OpenBSD hw.sensors
                      5: #
                      6: # 2006.05.01 #*#*# andrew fresh <andrew@mad-techies.org>
                      7: ########################################################################
                      8: use strict;
                      9: use warnings;
                     10:
                     11: #use Data::Dumper;
                     12:
                     13: use POSIX;
                     14: #use lib "/usr/local/libexec/nagios";
                     15: use lib $ENV{'HOME'};
                     16: use utils qw($TIMEOUT %ERRORS &print_revision &support);
                     17:
                     18: use Getopt::Long;
                     19: Getopt::Long::Configure('bundling');
                     20:
                     21: my $PROGNAME = "check_hw_sensors";
                     22:
                     23: my $SYSCTL = 'sysctl';
                     24: my $GETCAP = 'getcap';
                     25: my $BASE   = 'hw.sensors';
                     26:
                     27: my $CHECK_SENSOR = $BASE;
                     28: my %CHECKS;
                     29: my %SENSORS;
                     30:
                     31: my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK
                     32: my %states; # This stores the count of states;
                     33: my $filename;
                     34: my $sensor;
                     35: my $warning;
                     36: my $critical;
                     37: my $opt_h ;
                     38: my $opt_V ;
                     39:
                     40:
                     41: #Option checking
                     42: my $status = GetOptions(
1.3     ! andrew     43:        "version|V"    => \$opt_V,
        !            44:        "help|h"       => \$opt_h,
1.2       andrew     45:        "filename|f:s" => \$filename,
                     46:        "sensor|s=s"   => \$sensor,
                     47:        "warning|w=s"  => \$warning,
                     48:        "critical|c=s" => \$critical,
                     49: );
                     50:
                     51: # set the default this way so it only happens if someone typed -f or --filename
                     52: $filename = '/etc/sensorsd.conf' if (defined $filename && $filename eq '');
                     53:
                     54: if ($status == 0) {
                     55:        print_help() ;
                     56:        exit $ERRORS{'OK'};
                     57: }
                     58:
                     59: if ($opt_V) {
                     60:        print_revision($PROGNAME,'$Revision: 1.2 $ ');
                     61:        exit $ERRORS{'OK'};
                     62: }
                     63:
                     64: if ($opt_h) {
                     65:        print_help();
                     66:        exit $ERRORS{'OK'};
                     67: }
                     68:
                     69: unless ( (
                     70:                defined $filename ||
                     71:                (defined $sensor && ($warning || $critical))
                     72:         ) &&
                     73:                ( (!defined $filename) || (!defined $sensor) )
                     74: ) {
                     75:        print_help();
                     76:        exit $ERRORS{'OK'};
                     77: }
                     78:
                     79:
                     80: if (defined $sensor) {
                     81:        if ($sensor !~ /^$BASE/) {
                     82:                $sensor = $BASE . '.' . $sensor;
                     83:        }
                     84:        $CHECK_SENSOR = $sensor;
                     85:
                     86:        $CHECKS{$sensor} = {
                     87:                'warning'  => $warning,
                     88:                'critical' => $critical,
                     89:        };
                     90: } elsif (defined $filename) {
                     91:        %CHECKS = parse_file($filename);
                     92: }
                     93:
                     94: open my $sysctl, "-|", $SYSCTL, $CHECK_SENSOR
                     95:     or die "Couldn't open sysctl: $!";
                     96: while (<$sysctl>) {
                     97: #while (<>) {
                     98:        chomp;
                     99:        my ($id, $output) = split /=/;
                    100:        my @o = split /,\s*/, $output;
                    101:
                    102:        my $source = $o[0];
                    103:        my $descr  = $o[1];
                    104:        my $status = $o[2] if @o == 5;
                    105:        my $type   = $o[-2];
                    106:        my $data   = $o[-1];
                    107:
                    108:        $SENSORS{$id} = {
                    109:                id          => $id,
                    110:                output      => $output,
                    111:                source      => $source,
                    112:                description => $descr,
                    113:                status      => $status,
                    114:                type        => $type,
                    115:                data        => $data,
                    116:        };
                    117:
                    118: }
                    119: close $sysctl;
                    120:
                    121: sub as_if_numeric {
                    122:        my $_a = $a;
                    123:        my $_b = $b;
                    124:        $_a =~ s/\D//g;
                    125:        $_b =~ s/\D//g;
                    126:        $_a <=> $_b;
                    127: }
                    128:
                    129: foreach my $check (sort as_if_numeric keys %CHECKS) {
                    130:        if (exists $SENSORS{$check}) {
                    131:                my $r = check_sensor($CHECKS{$check}, $SENSORS{$check});
                    132:                push @{ $states{ $r } },
                    133:                        $check . '=' . $SENSORS{$check}{'output'};
                    134:        } else {
                    135:                # XXX Error missing sensor
                    136:                push @{ $states{'UNKNOWN'} }, $check . '=No sensor with this id';
                    137:        }
                    138: }
                    139:
                    140: #print Dumper \%states;
                    141:
                    142: $state = 'OK';
                    143: foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) {
                    144:        if (exists $states{$error}) {
                    145:                $state = $error;
                    146:                print "$error (" . scalar(@{ $states{ $error } }) . "):\n";
                    147:                foreach (@{ $states{ $error } }) {
                    148:                        print "   $_\n";
                    149:                }
                    150:        }
                    151: }
                    152: exit $ERRORS{$state};
                    153:
                    154:
                    155: sub parse_file {
                    156:        my $filename = shift;
                    157:        my %contents;
                    158:
                    159:        open my $fh, '-|', $GETCAP, '-a', '-f', $filename
                    160:                or die "Couldn't open FILE '$GETCAP -a -f $filename': $!";
                    161:        while (<$fh>) {
                    162:                chomp;
                    163:                my ($key, @c) = split /\:/;
                    164:                foreach (@c) {
                    165:                        my ($k, $v) = split /\=/;
                    166:                        $contents{$key}{$k} = $v;
                    167:                }
                    168:        }
                    169:        close $fh;
                    170:
                    171:        return %contents;
                    172: }
                    173:
                    174: sub parse_check {
                    175:        my $type  = shift;
                    176:        my $check = shift;
                    177:
                    178:        $check->{'warn'} = $check->{'warning'}  if (!defined $check->{'warn'});
                    179:        $check->{'crit'} = $check->{'critical'} if (!defined $check->{'crit'});
                    180:
                    181:        if (defined $check->{'warn'} && $check->{'warn'} =~ /:/) {
                    182:                if (my ($low, $high) = split /:/, $check->{'warn'}) {
                    183:                        $check->{'warn.low'}  = $low;
                    184:                        $check->{'warn.high'} = $high;
                    185:                }
                    186:                delete $check->{'warn'};
                    187:        }
                    188:        if (defined $check->{'crit'} && $check->{'crit'} =~ /:/) {
                    189:                if (my ($low, $high) = split /:/, $check->{'crit'}) {
                    190:                        $check->{'crit.low'}  = $low;
                    191:                        $check->{'crit.high'} = $high;
                    192:                }
                    193:                delete $check->{'crit'};
                    194:        }
                    195:
                    196:        if (defined $check->{'low'}) {
                    197:                $check->{'warn.low'} = $check->{'low'}
                    198:                        unless defined $check->{'warn.low'};
                    199:                $check->{'crit.low'} = $check->{'low'}
                    200:                        unless defined $check->{'crit.low'};
                    201:        }
                    202:        if (defined $check->{'high'}) {
                    203:                $check->{'warn.high'} = $check->{'high'}
                    204:                        unless defined $check->{'warn.high'};
                    205:                $check->{'crit.high'} = $check->{'high'}
                    206:                        unless defined $check->{'crit.high'};
                    207:        }
                    208:
                    209:        no warnings 'uninitialized';
                    210:        $check->{'warn'} = [ split /,\s*/, $check->{'warn'} ];
                    211:        $check->{'crit'} = [ split /,\s*/, $check->{'crit'} ];
                    212:
                    213:        return $check;
                    214: }
                    215:
                    216: sub check_sensor {
                    217:        my $check  = shift;
                    218:        my $sensor = shift;
                    219:        my $result = 'UNKNOWN';
                    220:        my %errors = (
                    221:                'warn' => 'WARNING',
                    222:                'crit' => 'CRITICAL',
                    223:        );
                    224:
                    225:        return $result unless ref $sensor eq 'HASH';
                    226:
                    227:        $check = parse_check($sensor->{'type'}, $check);
                    228:        #print Dumper $check, $sensor;
                    229:
                    230:        $result = 'OK';
                    231:
                    232:        foreach my $code ('warn', 'crit') {
                    233:                if (
                    234:                        $sensor->{'type'} eq 'volts_dc' ||
                    235:                        $sensor->{'type'} eq 'fanrpm'   ||
                    236:                        $sensor->{'type'} eq 'raw'
                    237:                ) {
                    238:                        my $data = $sensor->{'data'};
                    239:                        $data =~ s/[^\d\.]//g;
                    240:                        unless (length $data) {
                    241:                                warn "INVALID DATA ($sensor->{'data'}) for '$sensor->{'id'}'";
                    242:                                next;
                    243:                        }
                    244:
                    245:                        if (
                    246:                                defined $check->{$code . ".low"} ||
                    247:                                defined $check->{$code . ".high"}
                    248:                        ) {
                    249:                                if (defined $check->{$code . ".low"}) {
                    250:                                        my $c =  $check->{$code . ".low"};
                    251:                                        $c =~ s/[^\d\.]//g;
                    252:
                    253:                                        unless (length $c) {
                    254:                                                warn "INVALID CHECK (" . $check->{$code . ".low"} .
                    255:                                                      ") for '$sensor->{'id'}:$code.low'";
                    256:                                                next;
                    257:                                        }
                    258:
                    259:                                        $result = $errors{$code}
                    260:                                                if ($c >= $data);
                    261:                                }
                    262:                                if (defined $check->{$code . ".high"}) {
                    263:                                        my $c =  $check->{$code . ".high"};
                    264:                                        $c =~ s/[^\d\.]//g;
                    265:                                        unless (length $c) {
                    266:                                                warn "INVALID CHECK (" . $check->{$code . ".high"} .
                    267:                                                      ") for '$sensor->{'id'}:$code.high'";
                    268:                                                next;
                    269:                                        }
                    270:
                    271:                                        $result = $errors{$code}
                    272:                                                if ($c <= $data);
                    273:                                }
                    274:                        } elsif (defined $check->{$code}) {
                    275:                                my $matched = 0;
                    276:                                foreach my $c (@{ $check->{$code} }) {
                    277:                                        $c =~ s/[^\d\.]//g;
                    278:                                        unless (length $c) {
                    279:                                                warn "INVALID CHECK (" . $check->{$code} .
                    280:                                                      ") for '$sensor->{'id'}:$code'";
                    281:                                                next;
                    282:                                        }
                    283:
                    284:                                        if ($_ eq $data) {
                    285:                                                $matched = 1;
                    286:                                                last;
                    287:                                        }
                    288:                                }
                    289:                                $result = $errors{$code} unless $matched;
                    290:                        }
                    291:
                    292:                } elsif ($sensor->{'type'} eq 'temp') {
                    293:                        my ($degC, $degF) = split /\//, $sensor->{'data'};
                    294:                        $degC =~ s/[^\d\.]//g;
                    295:                        $degF =~ s/[^\d\.]//g;
                    296:                        if (
                    297:                                defined $check->{$code . ".low"} ||
                    298:                                defined $check->{$code . ".high"}
                    299:                        ) {
                    300:                                if (defined $check->{$code . ".low"}) {
                    301:                                        my $c =  $check->{$code . ".low"};
                    302:                                        my $data = $degC;
                    303:
                    304:                                        $data = $degF if ($c =~ /F/i);
                    305:                                        unless (length $data) {
                    306:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    307:                                                          ") for '$sensor->{'id'}'";
                    308:                                                next;
                    309:                                        }
                    310:
                    311:                                        $c =~ s/[^\d\.]//g;
                    312:                                        unless (length $c) {
                    313:                                                warn "INVALID CHECK (" . $check->{$code . ".low"} .
                    314:                                                         ") for '$sensor->{'id'}':$code.low";
                    315:                                                next;
                    316:                                        }
                    317:
                    318:                                        $result = $errors{$code}
                    319:                                                if ($c >= $data);
                    320:                                }
                    321:                                if (defined $check->{$code . ".high"}) {
                    322:                                        my $c =  $check->{$code . ".high"};
                    323:
                    324:                                        my $data = $degC;
                    325:                                        $data = $degF if ($c =~ /F/i);
                    326:                                        unless (length $data) {
                    327:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    328:                                                          ") for '$sensor->{'id'}'";
                    329:                                                next;
                    330:                                        }
                    331:
                    332:                                        $c =~ s/[^\d\.]//g;
                    333:                                        unless (length $c) {
                    334:                                                warn "INVALID CHECK (" . $check->{$code . ".high"} .
                    335:                                                         ") for '$sensor->{'id'}:$code.high'";
                    336:                                                next;
                    337:                                        }
                    338:
                    339:                                        $result = $errors{$code}
                    340:                                                if ($c <= $data);
                    341:                                }
                    342:                        } elsif (defined $check->{$code}) {
                    343:
                    344:                                my $matched = 0;
                    345:                                foreach my $c (@{ $check->{$code} }) {
                    346:                                        my $data = $degC;
                    347:
                    348:                                        $data = $degF if ($c =~ /F/i);
                    349:                                        unless (length $data) {
                    350:                                                warn "INVALID DATA (" . $sensor->{'data'} .
                    351:                                                          ") for '$sensor->{'id'}'";
                    352:                                                next;
                    353:                                        }
                    354:
                    355:                                        $c =~ s/[^\d\.]//g;
                    356:                                        unless (length $c) {
                    357:                                                warn "INVALID CHECK (" . $check->{$code} .
                    358:                                                         ") for '$sensor->{'id'}':$code";
                    359:                                                next;
                    360:                                        }
                    361:
                    362:                                        if ($_ eq $data) {
                    363:                                                $matched = 1;
                    364:                                                last;
                    365:                                        }
                    366:                                }
                    367:                                $result = $errors{$code} unless $matched;
                    368:                        }
                    369:
                    370:                } elsif (
                    371:                        $sensor->{'type'} eq 'drive' ||
                    372:                        $sensor->{'type'} eq 'indicator'
                    373:                ) {
                    374:                        if (defined $check->{$code}) {
                    375:                                my $matched = 0;
                    376:                                foreach (@{ $check->{$code} }) {
                    377:                                        if ($_ eq $sensor->{'data'}) {
                    378:                                                $matched = 1;
                    379:                                                last;
                    380:                                        }
                    381:                                }
                    382:                                $result = $errors{$code} unless $matched;
                    383:                        }
                    384:
                    385:                } else {
                    386:                        $result = 'UNKNOWN';
                    387:                }
                    388:
                    389:        }
                    390:
                    391:        return $result;
                    392: }
                    393:
                    394: sub print_help {
                    395:        print <<EOL;
                    396: $PROGNAME plugin for Nagios monitors sysctl hw.sensors on OpenBSD
                    397:        $PROGNAME (-f [<FILENAME>]|(-s <hw.sensors id> -w limit -c limit))
                    398:
                    399: Usage:
                    400:        -f, --filename=FILE
                    401:                FILE to load checks from (defaults to /etc/sensorsd.conf)
                    402:        -s, --sensor=ID
                    403:                ID of a single sensor.  "-s 0" means hw.sensors.0.
                    404:        -w, --warning=RANGE or single ENTRY
                    405:                Exit with WARNING status if outside of RANGE or if != ENTRY
                    406:        -c, --critical=INTEGER
                    407:                Exit with CRITICAL status if outside of RANGE or if != ENTRY
                    408:
                    409:        -h (--help)       usage help
                    410:
                    411: 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:
                    412:        low, high, crit, warn, crit.low, crit.high, warn.low, warn.high
                    413:
                    414: An ENTRY depends on the type.  The descriptions in sensorsd.conf(5) can be used when appropriate, or you can use the following:
                    415:        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.
                    416:        temp - Can be as above, but if the entry has an F in it, it compares farenheit, otherwise it uses celcius.
                    417:        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.
                    418:
                    419: 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.
                    420:
                    421: A RANGE is a low ENTRY and a high ENTRY separated by a colon (:).
                    422:
                    423: EOL
                    424:
                    425:        print_revision($PROGNAME, '$Revision: 1.2 $');
                    426: }
                    427:

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