Annotation of nagios/check_hw_sensors/check_hw_sensors, Revision 1.2
1.2 ! andrew 1: #!/usr/bin/perl
! 2: # $RedRiver: check_sensors,v 1.1 2006/05/01 18:11:23 andrew Exp $
! 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(
! 43: "V" => \$opt_V, "version" => \$opt_V,
! 44: "h" => \$opt_h, "help" => \$opt_h,
! 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>