version 1.10, 2009/11/12 18:54:38 |
version 1.23, 2017/02/08 19:00:15 |
|
|
#!/usr/bin/perl -T |
#!/usr/bin/perl -T |
# $RedRiver: check_bioctl,v 1.9 2009/11/09 20:22:43 andrew Exp $ |
# $AFresh1: check_bioctl,v 1.22 2017/02/08 17:34:23 andrew Exp $ |
######################################################################## |
######################################################################## |
# check_bioctl *** A nagios check for OpenBSD bioctl |
# check_bioctl *** A nagios check for OpenBSD bioctl |
# |
# |
|
|
######################################################################## |
######################################################################## |
use strict; |
use strict; |
use warnings; |
use warnings; |
|
use 5.010; |
|
|
%ENV = (); |
local %ENV = (); |
|
|
use constant NAGIOS_OUTPUT => 1; |
my $NAGIOS_OUTPUT = 1; |
|
|
my $License = <<'EOL'; |
my $License = <<'EOL'; |
Copyright (c) 2009 Andrew Fresh <andrew@afresh1.com> |
Copyright (c) 2009 Andrew Fresh <andrew@afresh1.com> |
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
EOL |
EOL |
|
|
my $PROGNAME = "check_bioctl"; |
my $PROGNAME = 'check_bioctl'; |
my $BIOCTL = '/sbin/bioctl'; |
my $BIOCTL = '/sbin/bioctl'; |
|
my @DOAS = ( '/usr/bin/doas', '-n' ); |
|
|
use POSIX; |
use POSIX; |
my $PREFIX; |
my $PREFIX; |
|
|
BEGIN { |
BEGIN { |
## no critic 'warnings' |
## no critic 'warnings' |
no warnings 'uninitialized'; |
no warnings 'uninitialized'; |
$PREFIX = "${PREFIX}" || '/usr/local'; # Magic for OpenBSD ports tree |
$PREFIX = "${PREFIX}" || '/usr/local'; # Magic for OpenBSD ports tree |
} |
} |
use lib $PREFIX . '/libexec/nagios'; |
use lib $PREFIX . '/libexec/nagios'; |
use utils qw($TIMEOUT %ERRORS &support); |
use utils qw($TIMEOUT %ERRORS &support); |
|
|
$SIG{'ALRM'} = sub { |
$SIG{'ALRM'} = sub { |
print ("ERROR: $PROGNAME timeout\n"); |
say "ERROR: $PROGNAME timeout"; |
exit $ERRORS{'UNKNOWN'}; |
exit $ERRORS{'UNKNOWN'}; |
}; |
}; |
alarm($TIMEOUT); |
alarm($TIMEOUT); |
|
|
|
|
Invalid => 'CRITICAL', |
Invalid => 'CRITICAL', |
); |
); |
|
|
my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK |
|
my %states; # This stores the count of states; |
|
my @devices; |
my @devices; |
my $opt_h; |
my $opt_h; |
my $opt_V; |
my $opt_V; |
|
|
} |
} |
|
|
if ($opt_V) { |
if ($opt_V) { |
print_revision( $PROGNAME, '$Revision$ ' ); |
print_revision(); |
exit $ERRORS{'OK'}; |
exit $ERRORS{'OK'}; |
} |
} |
|
|
if ( $opt_h || not @devices ) { |
if ( $opt_h || !@devices ) { |
print_help(); |
print_help(); |
exit $ERRORS{'OK'}; |
exit $ERRORS{'OK'}; |
} |
} |
|
|
my %VOLUMES; |
my %VOLUMES = read_bioctl( \@devices ); |
foreach my $device (@devices) { |
my %STATES = check_status( \%VOLUMES ); |
open my $bioctl, '-|', $BIOCTL, $device or die "Couldn't open bioctl: $!"; |
|
my $volume_id; |
|
|
|
while (<$bioctl>) { |
my $have_results = 0; |
chomp; |
my $state = 'OK'; |
|
foreach my $error ( sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS ) { |
|
if ( exists $STATES{$error} ) { |
|
$have_results++; |
|
$state = $error if $ERRORS{$state} < $ERRORS{$error}; |
|
|
# Do these by columns cuZ that is the easiest for now |
if ($NAGIOS_OUTPUT) { |
my @o = unpack( "A6 A1 A11 A15 A7 A9 A*", $_ ); |
print "$error (" . scalar( @{ $STATES{$error} } ) . ")"; |
next if $o[0] eq 'Volume'; |
if ( $error ne 'OK' ) { |
|
print '<br>'; |
foreach (@o) { |
print map {" - $_<br>"} @{ $STATES{$error} }; |
s/^\s+//; |
} |
s/\s+$//; |
|
} |
} |
|
|
my ( $controller, $id, $status, $size, $dev, $details, $name ) = @o; |
|
my $index = $id; |
|
if ($controller) { |
|
$volume_id = $id; |
|
} |
|
else { |
else { |
$index = "$volume_id.$id"; |
print "$error (" . scalar( @{ $STATES{$error} } ) . "):\n"; |
|
print map {" $_\n"} @{ $STATES{$error} }; |
} |
} |
|
} |
|
} |
|
if ( $have_results == 0 ) { |
|
say 'No results found'; |
|
} |
|
exit $ERRORS{$state}; |
|
|
$VOLUMES{$device}{$index} = { |
sub fail { |
type => 'volume', |
my ($message) = @_; |
controller => $controller, |
print $message; |
id => $id, |
exit $ERRORS{'UNKNOWN'}; |
status => $status, |
} |
size => $size, |
|
device => $dev, |
|
details => $details, |
|
name => $name, |
|
}; |
|
|
|
if ( $dev =~ /^\d+:\d+/ ) { |
sub read_bioctl { |
$VOLUMES{$device}{$index}{'volume'} |
my ($devices) = @_; |
= $VOLUMES{$device}{$volume_id}; |
my %volumes; |
|
|
|
foreach my $d ( @{$devices} ) { |
|
open my $bioctl, q{-|}, @DOAS, $BIOCTL, $d |
|
or fail("Couldn't open bioctl: $!\n"); |
|
LINE: while ( my $line = <$bioctl> ) { |
|
my ( $i, $item ) = parse_bioctl_line($line); |
|
next LINE if !defined $i; |
|
$volumes{$d}{$i} = $item; |
} |
} |
|
close $bioctl |
|
or fail( $! |
|
? "Error closing bioctl pipe: $!\n" |
|
: "Exit status $? from bioctl\n" ); |
|
} |
|
|
|
foreach my $d ( keys %volumes ) { |
|
foreach my $i ( keys %{ $volumes{$d} } ) { |
|
my $item = $volumes{$d}{$i}; |
|
if ( $item->{device} =~ /^\d+:\d+/xms ) { |
|
$item->{'volume'} = $volumes{$d}{ $item->{volume_id} }; |
|
} |
|
} |
} |
} |
close $bioctl; |
|
|
return %volumes; |
} |
} |
|
|
foreach my $device ( sort keys %VOLUMES ) { |
sub parse_bioctl_line { |
foreach my $index ( sort keys %{ $VOLUMES{$device} } ) { |
($_) = @_; |
my $cur_state |
chomp; |
= $Status_Map{ $VOLUMES{$device}{$index}{'status'} } |
|
? $Status_Map{ $VOLUMES{$device}{$index}{'status'} } |
|
: 'UNKNOWN'; |
|
|
|
if ( $VOLUMES{$device}{$index}{'device'} =~ /^\d+:\d/ ) { |
my @o = map { s/^\s+|\s+$//g; $_ } split; |
push @{ $states{$cur_state} }, |
return if $o[0] eq 'Volume'; |
sprintf( |
|
"%5s %-7s %-11s %s", |
state $vid = ''; |
$VOLUMES{$device}{$index}{'volume'}{'controller'}, |
state $controller; |
$VOLUMES{$device}{$index}{'device'}, |
|
$VOLUMES{$device}{$index}{'status'}, |
my $index = "$vid.$o[0]"; |
$VOLUMES{$device}{$index}{'name'} |
if ( $o[0] !~ /^\d+$/ ) { |
); |
$controller = shift @o; |
} |
$vid = $o[0]; |
else { |
$index = $vid; |
push @{ $states{$cur_state} }, |
|
sprintf( "%5s %-7s %s", |
|
$VOLUMES{$device}{$index}{'controller'}, |
|
$VOLUMES{$device}{$index}{'device'}, |
|
$VOLUMES{$device}{$index}{'status'} ); |
|
} |
|
} |
} |
|
|
|
return $index, { |
|
controller => $controller, |
|
volume_id => $vid, |
|
id => shift @o, |
|
status => shift @o, |
|
size => shift @o, |
|
device => shift @o, |
|
name => shift @o, |
|
description => join ' ', @o, |
|
}; |
} |
} |
|
|
my $have_results = 0; |
sub check_status { |
$state = 'OK'; |
my ($volumes) = @_; |
foreach my $error ( sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS ) { |
|
if ( exists $states{$error} ) { |
|
$have_results++; |
|
$state = $error if $ERRORS{$state} < $ERRORS{$error}; |
|
|
|
if (NAGIOS_OUTPUT) { |
my %states; |
print "$error (" . scalar( @{ $states{$error} } ) . ")"; |
foreach my $d ( sort keys %{$volumes} ) { |
if ( $error ne 'OK' ) { |
foreach my $i ( sort { $a <=> $b } keys %{ $volumes->{$d} } ) { |
print '<br>'; |
my $volume = $volumes->{$d}->{$i}; |
print map {" - $_<br>"} @{ $states{$error} }; |
my $state = $Status_Map{ $volume->{'status'} } || 'UNKNOWN'; |
} |
|
|
push @{ $states{$state} }, |
|
sprintf( |
|
"%5s %-7s %-11s %s", |
|
$volume->{'controller'}, $volume->{'device'}, |
|
$volume->{'status'}, $volume->{'name'} |
|
); |
} |
} |
else { |
|
print "$error (" . scalar( @{ $states{$error} } ) . "):\n"; |
|
print map {" $_\n"} @{ $states{$error} }; |
|
} |
|
} |
} |
|
return %states; |
} |
} |
if ( $have_results == 0 ) { |
|
print "No results found\n"; |
|
} |
|
exit $ERRORS{$state}; |
|
|
|
sub print_help { |
sub print_help { |
print <<"EOL"; |
print <<"EOL"; |
|
|
|
|
EOL |
EOL |
|
|
print_revision( $PROGNAME, '$Revision$' ); |
print_revision(); |
|
|
print $License; |
print $License; |
|
|
|
return 1; |
} |
} |
|
|
|
|
sub print_revision { |
sub print_revision { |
my ($prog, $rev) = @_; |
my $rev = '$Revision$'; |
$rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms; |
$rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms; |
|
|
print "$prog $rev\n"; |
say "$PROGNAME $rev"; |
|
|
|
return 1; |
} |
} |