| version 1.8, 2009/11/09 18:11:33 |
version 1.15, 2009/11/23 22:24:45 |
|
|
| #!/usr/bin/perl -T |
#!/usr/bin/perl -T |
| # $RedRiver: check_bioctl,v 1.7 2009/11/09 18:00:09 andrew Exp $ |
# $RedRiver: check_bioctl,v 1.14 2009/11/23 21:58:04 andrew Exp $ |
| ######################################################################## |
######################################################################## |
| # check_bioctl *** A nagios check for OpenBSD bioctl |
# check_bioctl *** A nagios check for OpenBSD bioctl |
| # |
# |
| # 2006.07.26 #*#*# andrew fresh <andrew@mad-techies.org> |
# 2006.07.26 #*#*# andrew fresh <andrew@afresh1.com> |
| ######################################################################## |
######################################################################## |
| use strict; |
use strict; |
| use warnings; |
use warnings; |
| |
|
| %ENV = (); |
local %ENV = (); |
| |
|
| use constant NAGIOS_OUTPUT => 1; |
my $NAGIOS_OUTPUT = 0; |
| |
|
| |
my $License = <<'EOL'; |
| |
Copyright (c) 2009 Andrew Fresh <andrew@afresh1.com> |
| |
Permission to use, copy, modify, and distribute this software for any |
| |
purpose with or without fee is hereby granted, provided that the above |
| |
copyright notice and this permission notice appear in all copies. |
| |
|
| |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| |
EOL |
| |
|
| |
my $PROGNAME = 'check_bioctl'; |
| |
my $BIOCTL = '/sbin/bioctl'; |
| |
|
| use POSIX; |
use POSIX; |
| use lib "/usr/local/libexec/nagios"; |
my $PREFIX; |
| use utils qw($TIMEOUT %ERRORS &print_revision &support); |
|
| |
|
| |
BEGIN { |
| |
## no critic 'warnings' |
| |
no warnings 'uninitialized'; |
| |
$PREFIX = "${PREFIX}" || '/usr/local'; # Magic for OpenBSD ports tree |
| |
} |
| |
use lib $PREFIX . '/libexec/nagios'; |
| |
use utils qw($TIMEOUT %ERRORS &support); |
| |
|
| |
$SIG{'ALRM'} = sub { |
| |
print "ERROR: $PROGNAME timeout\n"; |
| |
exit $ERRORS{'UNKNOWN'}; |
| |
}; |
| |
alarm($TIMEOUT); |
| |
|
| use Getopt::Long; |
use Getopt::Long; |
| Getopt::Long::Configure('bundling'); |
Getopt::Long::Configure('bundling'); |
| |
|
| my $PROGNAME = "check_bioctl"; |
|
| my $BIOCTL = '/sbin/bioctl'; |
|
| |
|
| # This maps the status we get from bioctl to something nagios can use |
# This maps the status we get from bioctl to something nagios can use |
| my %Status_Map = ( |
my %Status_Map = ( |
| Online => 'OK', |
Online => 'OK', |
|
|
| 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; |
|
|
| 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}; |
| |
|
| |
if ($NAGIOS_OUTPUT) { |
| |
print "$error (" . scalar( @{ $STATES{$error} } ) . ")"; |
| |
if ( $error ne 'OK' ) { |
| |
print '<br>'; |
| |
print map {" - $_<br>"} @{ $STATES{$error} }; |
| |
} |
| |
} |
| |
else { |
| |
print "$error (" . scalar( @{ $STATES{$error} } ) . "):\n"; |
| |
print map {" $_\n"} @{ $STATES{$error} }; |
| |
} |
| |
} |
| |
} |
| |
if ( $have_results == 0 ) { |
| |
print "No results found\n"; |
| |
} |
| |
exit $ERRORS{$state}; |
| |
|
| |
sub read_bioctl { |
| |
my ($devices) = @_; |
| |
my %volumes; |
| |
|
| |
foreach my $d ( @{$devices} ) { |
| |
open my $bioctl, q{-|}, $BIOCTL, $d |
| |
or die "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; |
| |
} |
| |
## no critic 'die' |
| |
close $bioctl |
| |
or die $! |
| |
? "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} }; |
| |
} |
| |
} |
| |
} |
| |
|
| |
return %volumes; |
| |
} |
| |
|
| |
{ |
| |
my $vid; |
| |
my $controller; |
| |
|
| |
sub parse_bioctl_line { |
| |
my ($line) = @_; |
| |
chomp $line; |
| |
|
| # Do these by columns cuZ that is the easiest for now |
# Do these by columns cuZ that is the easiest for now |
| my @o = unpack( "A6 A1 A11 A15 A7 A9 A*", $_ ); |
my @o = unpack( "A6 A1 A11 A15 A7 A9 A*", $line ); |
| next if $o[0] eq 'Volume'; |
return if $o[0] eq 'Volume'; |
| |
|
| foreach (@o) { |
foreach (@o) { |
| s/^\s+//; |
s/^\s+//xms; |
| s/\s+$//; |
s/\s+$//xms; |
| } |
} |
| |
|
| my ( $controller, $id, $status, $size, $dev, $details, $name ) = @o; |
my ( $c, $id, $status, $size, $dev, $details, $name ) = @o; |
| my $index = $id; |
my $index = $id; |
| if ($controller) { |
if ($c) { |
| $volume_id = $id; |
$vid = $id; |
| |
$controller = $c; |
| } |
} |
| else { |
else { |
| $index = "$volume_id.$id"; |
$index = "$vid.$id"; |
| } |
} |
| |
|
| $VOLUMES{$device}{$index} = { |
return $index, |
| type => 'volume', |
{ |
| controller => $controller, |
controller => $controller, |
| id => $id, |
id => $id, |
| status => $status, |
status => $status, |
|
|
| device => $dev, |
device => $dev, |
| details => $details, |
details => $details, |
| name => $name, |
name => $name, |
| }; |
volume_id => $vid, |
| |
}; |
| if ( $dev =~ /^\d+:\d+/ ) { |
|
| $VOLUMES{$device}{$index}{'volume'} |
|
| = $VOLUMES{$device}{$volume_id}; |
|
| } |
|
| |
|
| } |
} |
| close $bioctl; |
|
| } |
} |
| |
|
| foreach my $device ( sort keys %VOLUMES ) { |
sub check_status { |
| foreach my $index ( sort keys %{ $VOLUMES{$device} } ) { |
my ($volumes) = @_; |
| my $cur_state |
|
| = $Status_Map{ $VOLUMES{$device}{$index}{'status'} } |
|
| ? $Status_Map{ $VOLUMES{$device}{$index}{'status'} } |
|
| : 'UNKNOWN'; |
|
| |
|
| if ( $VOLUMES{$device}{$index}{'device'} =~ /^\d+:\d/ ) { |
my %states; |
| push @{ $states{$cur_state} }, |
foreach my $d ( sort keys %{$volumes} ) { |
| |
foreach my $i ( sort { $a <=> $b } keys %{ $volumes->{$d} } ) { |
| |
my $volume = $volumes->{$d}->{$i}; |
| |
my $state = $Status_Map{ $volume->{'status'} } || 'UNKNOWN'; |
| |
|
| |
push @{ $states{$state} }, |
| sprintf( |
sprintf( |
| "%5s %-7s %-11s %s", |
"%5s %-7s %-11s %s", |
| $VOLUMES{$device}{$index}{'volume'}{'controller'}, |
$volume->{'controller'}, $volume->{'device'}, |
| $VOLUMES{$device}{$index}{'device'}, |
$volume->{'status'}, $volume->{'name'} |
| $VOLUMES{$device}{$index}{'status'}, |
|
| $VOLUMES{$device}{$index}{'name'} |
|
| ); |
); |
| } |
} |
| else { |
|
| push @{ $states{$cur_state} }, |
|
| sprintf( "%5s %-7s %s", |
|
| $VOLUMES{$device}{$index}{'controller'}, |
|
| $VOLUMES{$device}{$index}{'device'}, |
|
| $VOLUMES{$device}{$index}{'status'} ); |
|
| } |
|
| } |
} |
| |
return %states; |
| } |
} |
| |
|
| my $have_results = 0; |
|
| $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}; |
|
| |
|
| if (NAGIOS_OUTPUT) { |
|
| print "$error (" . scalar( @{ $states{$error} } ) . ")"; |
|
| if ( $error ne 'OK' ) { |
|
| print '<br>'; |
|
| print map {" - $_<br>"} @{ $states{$error} }; |
|
| } |
|
| } |
|
| else { |
|
| print "$error (" . scalar( @{ $states{$error} } ) . "):\n"; |
|
| print map {" $_\n"} @{ $states{$error} }; |
|
| } |
|
| } |
|
| } |
|
| if ( $have_results == 0 ) { |
|
| print "No results found\n"; |
|
| } |
|
| exit $ERRORS{$state}; |
|
| |
|
| sub print_help { |
sub print_help { |
| print <<EOL; |
print <<"EOL"; |
| $PROGNAME plugin for Nagios monitors bioctl on OpenBSD |
$PROGNAME plugin for Nagios monitors bioctl on OpenBSD |
| $PROGNAME -d <device> [ -d <device2> [ -d ... ] ] |
$PROGNAME -d <device> [ -d <device2> [ -d ... ] ] |
| |
|
|
|
| EOL |
EOL |
| |
|
| print_revision( $PROGNAME, '$Revision$' ); |
print_revision( $PROGNAME, '$Revision$' ); |
| |
|
| |
print $License; |
| |
|
| |
return 1; |
| } |
} |
| |
|
| |
sub print_revision { |
| |
my ( $prog, $rev ) = @_; |
| |
$rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms; |
| |
|
| |
print "$prog $rev\n"; |
| |
|
| |
return 1; |
| |
} |