version 1.3, 2006/11/10 22:58:37 |
version 1.4, 2007/01/10 00:47:53 |
|
|
#!/usr/bin/perl -T |
#!/usr/bin/perl -T |
# $RedRiver: check_rrd,v 1.2 2006/11/07 20:23:03 andrew Exp $ |
# $RedRiver: check_rrd,v 1.3 2006/11/10 22:58:37 andrew Exp $ |
######################################################################## |
######################################################################## |
# check_rrd *** A nagios check for changing averages in rrds |
# check_rrd *** A nagios check for changing averages in rrds |
# |
# |
|
|
|
|
%ENV = (); |
%ENV = (); |
|
|
|
use constant NAGIOS_OUTPUT => 0; |
|
|
use POSIX; |
use POSIX; |
use lib "/usr/local/libexec/nagios"; |
use lib "/usr/local/libexec/nagios"; |
use utils qw($TIMEOUT %ERRORS &print_revision &support); |
use utils qw($TIMEOUT %ERRORS &print_revision &support); |
|
|
); |
); |
|
|
my %Checks = ( |
my %Checks = ( |
max => { |
default => { |
#warn => undef, |
abs => { |
#crit => undef, |
warn => { min => undef, max => undef, }, |
warn => -60, |
crit => { min => undef, max => undef, }, |
crit => -50, |
}, |
|
change => { |
|
warn => { max => 5 }, |
|
crit => { max => 10 }, |
|
}, |
|
time => { |
|
warn => 15 * 60, # 15 minutes |
|
crit => 60 * 60, # 1 hour |
|
}, |
}, |
}, |
min => { |
|
#warn => undef, |
|
#crit => undef, |
|
warn => -80, |
|
crit => -85, |
|
}, |
|
change => { |
|
warn => 5, |
|
crit => 10, |
|
}, |
|
time => { |
|
warn => 15 * 60, # 15 minutes |
|
crit => 60 * 60, # 1 hour |
|
}, |
|
); |
); |
|
|
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 @rras; |
my @rras; |
my $warning; |
my @warning; |
my $critical; |
my @critical; |
my $opt_V; |
my $opt_V; |
|
|
#Option checking |
#Option checking |
|
|
"version|V" => \$opt_V, |
"version|V" => \$opt_V, |
"filename|f=s" => \$filename, |
"filename|f=s" => \$filename, |
"rra|r=s" => \@rras, |
"rra|r=s" => \@rras, |
"warning|w=s" => \$warning, |
"warning|w=s" => \@warning, |
"critical|c=s" => \$critical, |
"critical|c=s" => \@critical, |
); |
); |
@rras = split(/,/,join(',',@rras)); |
@rras = split(/,/,join(',',@rras)); |
|
@critical = split(/,/,join(',',@critical)); |
|
@warning = split(/,/,join(',',@warning)); |
|
|
|
update_checks(\%Checks, 'crit', \@critical); |
|
update_checks(\%Checks, 'warn', \@warning); |
|
|
|
#print Dumper \%Checks; |
|
|
if ($status == 0) { |
if ($status == 0) { |
print_help() ; |
print_help() ; |
exit $ERRORS{'OK'}; |
exit $ERRORS{'OK'}; |
|
|
my $last = $info->{'last_update'}; |
my $last = $info->{'last_update'}; |
|
|
my $age = time - $last; |
my $age = time - $last; |
if ($age > $Checks{'time'}{'crit'}) { |
my $max_age_crit = $Checks{'time'}{'abs'}{'crit'} || |
|
$Checks{'default'}{'time'}{'crit'}; |
|
my $max_age_warn = $Checks{'time'}{'abs'}{'warn'} || |
|
$Checks{'default'}{'time'}{'warn'}; |
|
|
|
if ($age > $max_age_crit) { |
push @{ $states{'CRITICAL'} }, |
push @{ $states{'CRITICAL'} }, |
"Last check was too long ago"; |
"Last update was too long ago"; |
} elsif ($age > $Checks{'time'}{'warn'}) { |
} elsif ($age > $max_age_warn) { |
push @{ $states{'WARNING'} }, |
push @{ $states{'WARNING'} }, |
"Last check was too long ago"; |
"Last update was too long ago"; |
} else { |
} else { |
push @{ $states{'OK'} }, |
push @{ $states{'OK'} }, |
"Last check was within time limits"; |
"Last update was within time limits"; |
} |
} |
|
|
my $end = int($last / $resolution) * $resolution; |
my $end = int($last / $resolution) * $resolution; |
|
|
} |
} |
} |
} |
|
|
|
my %check_status; |
foreach my $key (keys %totals) { |
foreach my $key (keys %totals) { |
next if @rras and not grep { /^$key$/ } @rras; |
next if @rras and not grep { /^$key$/ } @rras; |
|
|
my $mins = $totals{$key}{'FIVE_MINUTES'}{'average'}; |
my %w; |
my $hour = $totals{$key}{'ONE_HOUR'}{'average'}; |
$w{'Minute'} = $totals{$key}{'FIVE_MINUTES'}{'average'}; |
my $day = $totals{$key}{'ONE_DAY'}{'average'}; |
$w{'Hour'} = $totals{$key}{'ONE_HOUR'}{'average'}; |
|
$w{'Day'} = $totals{$key}{'ONE_DAY'}{'average'}; |
|
|
|
|
my ($s, $m) = check_delta($day, $hour); |
TYPE: foreach my $type ('change', 'abs') { |
push @{ $states{$s} }, "$key: Hour $m"; |
foreach my $sev ('crit', 'warn', 'ok') { |
|
my $min = $Checks{$key}{$type}{$sev}{'min'} || |
|
$Checks{'default'}{$type}{$sev}{'min'}; |
|
my $max = $Checks{$key}{$type}{$sev}{'max'} || |
|
$Checks{'default'}{$type}{$sev}{'max'}; |
|
|
($s, $m) = check_delta($hour, $mins); |
my $res = 'UNKNOWN'; |
push @{ $states{$s} }, "$key: Minute $m"; |
if ($sev eq 'crit') { |
|
$res = 'CRITICAL'; |
|
} elsif ($sev eq 'warn') { |
|
$res = 'WARNING'; |
|
} elsif ($sev eq 'ok') { |
|
$res = 'OK'; |
|
} |
|
|
($s, $m) = check_max($day); |
if ($type eq 'change') { |
push @{ $states{$s} }, "$key: Day $m"; |
my %deltas = ( |
|
Hour => [ $w{'Day'}, $w{'Hour'} ], |
|
Minute => [ $w{'Hour'}, $w{'Minute'} ], |
|
); |
|
|
($s, $m) = check_min($day); |
foreach my $d (keys %deltas) { |
push @{ $states{$s} }, "$key: Day $m"; |
my $delta = calc_delta(@{ $deltas{$d} }); |
|
if ((not $check_status{$key}{$d . ' change'}) && |
|
( $res eq 'OK' || |
|
( not range_ok(abs($delta), $min, $max) ) |
|
)) { |
|
$check_status{$key}{$d . ' change'} = { |
|
status => $res, |
|
message => $delta . '%', |
|
}; |
|
} |
|
} |
|
|
($s, $m) = check_max($hour); |
} else { |
push @{ $states{$s} }, "$key: Hour $m"; |
foreach my $time ('Day', 'Hour', 'Minute') { |
|
if ((not $check_status{$key}{$time}) && |
|
( $res eq 'OK' || |
|
( not range_ok($w{$time}, $min, $max) ) |
|
)) { |
|
$check_status{$key}{$time} = { |
|
status => $res, |
|
message => $w{$time}, |
|
}; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
($s, $m) = check_min($hour); |
my $have_results = 0; |
push @{ $states{$s} }, "$key: Hour $m"; |
foreach my $DS (sort keys %check_status) { |
|
foreach my $s (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) { |
|
foreach my $key (sort keys %{ $check_status{$DS} }) { |
|
next unless $check_status{$DS}{$key}{'status'} eq $s;; |
|
$have_results++; |
|
$state = $s; |
|
push @{ $states{$s} }, |
|
"$key ($DS) " . $check_status{$DS}{$key}{'message'}; |
|
} |
|
} |
|
} |
|
|
($s, $m) = check_max($mins); |
#print Dumper \%check_status, \%states, $state; |
push @{ $states{$s} }, "$key: Minute $m"; |
|
|
|
($s, $m) = check_min($mins); |
foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) { |
push @{ $states{$s} }, "$key: Minute $m"; |
if (exists $states{$error}) { |
|
if (NAGIOS_OUTPUT) { |
print $key, ": "; |
print "$error (" . scalar(@{ $states{ $error } }) . ")"; |
print join ", ", |
unless ($error eq 'OK') { |
$totals{$key}{'ONE_DAY'}{'average'}, |
print '<br>'; |
$totals{$key}{'ONE_HOUR'}{'average'}, |
print map {" - $_<br>"} @{ $states{ $error } }; |
$totals{$key}{'FIVE_MINUTES'}{'average'}; |
} |
print "\n"; |
} else { |
|
print "$error (" . scalar(@{ $states{ $error } }) . "):\n"; |
|
foreach (@{ $states{ $error } }) { |
|
print " $_\n"; |
|
} |
|
} |
|
} |
} |
} |
|
if ($have_results == 0) { |
|
print "No results found\n"; |
|
} |
|
|
print Dumper \%states; |
|
|
|
exit $ERRORS{$state}; |
exit $ERRORS{$state}; |
|
|
|
|
|
|
print_revision($PROGNAME, '$Revision$'); |
print_revision($PROGNAME, '$Revision$'); |
} |
} |
|
|
sub check_max |
|
|
sub range_ok |
{ |
{ |
my ($num) = @_; |
my ($num, $min, $max) = @_; |
|
|
my $state = 'UNKNOWN'; |
if (defined $min && defined $max && |
my $message = 'unknown status'; |
length $min && length $max) { |
|
if ($num < $min || $num > $max) { |
if (defined $Checks{'max'}{'crit'} && $num > $Checks{'max'}{'crit'}) { |
return 0; |
$state = 'CRITICAL'; |
} |
$message = "actual value is ($num) greater than allowed"; |
} elsif (defined $min && length $min) { |
} elsif (defined $Checks{'max'}{'warn'} && $num > $Checks{'max'}{'warn'}) { |
if ($num < $min) { |
$state = 'WARNING'; |
return 0; |
$message = "actual value ($num) is greater than allowed"; |
} |
} elsif (defined $Checks{'max'}{'crit'} && defined $Checks{'max'}{'warn'}) { |
} elsif (defined $max && length $max) { |
$state = 'OK'; |
if ($num > $max) { |
$message = "actual value ($num) is OK"; |
return 0; |
|
} |
} |
} |
|
|
return $state, $message; |
return 1; |
} |
} |
|
|
sub check_min |
sub calc_delta |
{ |
{ |
my ($num) = @_; |
my ($primary, $secondary) = @_; |
|
|
my $state = 'UNKNOWN'; |
my $delta = 0; |
my $message = 'unknown status'; |
$delta = ($primary - $secondary) / $primary * 100 if $primary != 0; |
|
|
if ($Checks{'min'}{'crit'} && $num < $Checks{'min'}{'crit'}) { |
return $delta; |
$state = 'CRITICAL'; |
|
$message = "actual value ($num) is smaller than allowed"; |
|
} elsif (defined $Checks{'min'}{'warn'} && $num < $Checks{'min'}{'warn'}) { |
|
$state = 'WARNING'; |
|
$message = "actual value ($num) is greater than allowed"; |
|
} elsif (defined $Checks{'min'}{'crit'} && defined $Checks{'min'}{'warn'}) { |
|
$state = 'OK'; |
|
$message = "actual value ($num) is OK"; |
|
} |
|
|
|
return $state, $message; |
|
} |
} |
|
|
sub check_delta |
sub update_checks |
{ |
{ |
my ($primary, $secondary) = @_; |
my $checks = shift; |
|
my $type = shift; |
|
my $new = shift; |
|
|
my $state = 'UNKNOWN'; |
foreach (@{ $new }) { |
my $message = ''; |
my ($check, $vals) = split /=/, $_, 2; |
|
unless ($vals) { |
|
$vals = $check; |
|
$check = 'default'; |
|
} |
|
my ($DS, $key) = split /:/, $check, 2; |
|
$DS ||= 'default'; |
|
$key ||= 'abs'; |
|
|
my $delta = 0; |
my ($min, $max) = split /:/, $vals; |
$delta = ($primary - $secondary) / $primary * 100 if $primary != 0; |
|
print "Delta: $delta\n"; |
|
|
|
if (defined $Checks{'change'}{'crit'} |
$checks->{$DS}->{$key}->{$type}->{'max'} = $max |
&& abs($delta) > $Checks{'change'}{'crit'}) { |
if defined $max && length $max; |
$state = 'CRITICAL'; |
$checks->{$DS}->{$key}->{$type}->{'min'} = $min |
$message = "change ($delta%) is greater than allowed"; |
if defined $min && length $min; |
} elsif (defined $Checks{'change'}{'warn'} |
|
&& abs($delta) > $Checks{'change'}{'warn'}) { |
|
$state = 'WARNING'; |
|
$message = "change ($delta%) is greater than allowed"; |
|
} elsif (defined $Checks{'change'}{'crit'} |
|
&& defined $Checks{'change'}{'warn'}) { |
|
$state = 'OK'; |
|
$message = "change ($delta%) is OK"; |
|
} |
} |
|
|
return $state, $message; |
|
} |
} |
|
|