[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.14

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

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