=================================================================== RCS file: /cvs/nagios/check_bioctl/check_bioctl,v retrieving revision 1.1 retrieving revision 1.14 diff -u -r1.1 -r1.14 --- nagios/check_bioctl/check_bioctl 2006/07/27 01:02:43 1.1 +++ nagios/check_bioctl/check_bioctl 2009/11/23 21:58:04 1.14 @@ -1,194 +1,253 @@ #!/usr/bin/perl -T -# $RedRiver$ +# $RedRiver: check_bioctl,v 1.13 2009/11/23 21:57:31 andrew Exp $ ######################################################################## # check_bioctl *** A nagios check for OpenBSD bioctl -# -# 2006.07.26 #*#*# andrew fresh +# +# 2006.07.26 #*#*# andrew fresh ######################################################################## -# TODO: -# Really need real documentation. -######################################################################## use strict; use warnings; -#use Data::Dumper; +local %ENV = (); -%ENV = (); +my $NAGIOS_OUTPUT = 1; -use constant NAGIOS_OUTPUT => 1; +my $License = <<'EOL'; +Copyright (c) 2009 Andrew Fresh +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 lib "/usr/local/libexec/nagios"; -use utils qw($TIMEOUT %ERRORS &print_revision &support); +my $PREFIX; +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; 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 my %Status_Map = ( - Online => 'OK', - Offline => 'WARNING', - Degraded => 'CRITICAL', - Failed => 'CRITICAL', - Building => 'WARNING', - Rebuild => 'WARNING', - 'Hot spare' => 'OK', - Unused => 'OK', - Scrubbing => 'WARNING', - Invalid => 'CRITICAL', + Online => 'OK', + Offline => 'CRITICAL', + Degraded => 'CRITICAL', + Failed => 'CRITICAL', + Building => 'WARNING', + Rebuild => 'WARNING', + 'Hot spare' => 'OK', + Unused => 'OK', + Scrubbing => 'WARNING', + Invalid => 'CRITICAL', ); - -my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK -my %states; # This stores the count of states; -my $device; +my $state = 'UNKNOWN'; # tells whether the it is warning, critical, or OK +my @devices; my $opt_h; my $opt_V; #Option checking my $status = GetOptions( - "version|V" => \$opt_V, - "help|h" => \$opt_h, - "device|d=s" => \$device, + "version|V" => \$opt_V, + "help|h" => \$opt_h, + "device|d=s" => \@devices, ); -if ($status == 0) { - print_help() ; - exit $ERRORS{'OK'}; +if ( $status == 0 ) { + print_help(); + exit $ERRORS{'OK'}; } if ($opt_V) { - print_revision($PROGNAME,'$Revision: 1.1 $ '); - exit $ERRORS{'OK'}; + print_revision( $PROGNAME, '$Revision: 1.14 $ ' ); + exit $ERRORS{'OK'}; } -if ($opt_h || not $device) { - print_help(); - exit $ERRORS{'OK'}; +if ( $opt_h || !@devices ) { + print_help(); + exit $ERRORS{'OK'}; } -my %DISKS; -my %VOLUMES; -open my $bioctl, "-|", $BIOCTL, $device or die "Couldn't open bioctl: $!"; -my $volume_id; -while (<$bioctl>) { - chomp; - # Do these by columns cuZ that is the easiest for now - # Volume Status Size Device - my @o = unpack("A6 A1 A11 A15 A7 A9 A*", $_); - next if $o[0] eq 'Volume'; +my %VOLUMES = read_bioctl( \@devices ); +my %STATES = check_status( \%VOLUMES ); - foreach (@o) { - s/^\s+//; - s/\s+$//; - } +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}; - #print Dumper \@o; + if ($NAGIOS_OUTPUT) { + print "$error (" . scalar( @{ $STATES{$error} } ) . ")"; + if ( $error ne 'OK' ) { + print '
'; + print map {" - $_
"} @{ $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}; - my ($controller, $id, $status, $size, $dev, $details, $name) = @o; +sub read_bioctl { + my ($devices) = @_; + my %volumes; - if ($controller) { - $volume_id = $id; + 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"; + } - $VOLUMES{$volume_id} = { - controller => $controller, - id => $volume_id, - status => $status, - size => $size, - device => $dev, - details => $details, - name => $name, - } - } + 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} }; + } + } + } - if ($dev =~ /^\d+:\d+/) { - $DISKS{$volume_id}{$id} = { - volume => $VOLUMES{$volume_id}, - id => $id, - status => $status, - size => $size, - device => $dev, - details => $details, - name => $name, - }; - } - + return %volumes; } -close $bioctl; -#print Dumper \%VOLUMES, \%DISKS; +{ + my $vid; -foreach my $volume (sort keys %VOLUMES) { - next if $VOLUMES{$volume}{'device'} =~ /^\d+:\d+/; - my $cur_state = $Status_Map{ $VOLUMES{$volume}{'status'} } ? - $Status_Map{ $VOLUMES{$volume}{'status'} } : - 'UNKNOWN'; - push @{ $states{$cur_state} }, sprintf("%5s %-7s %s", - $VOLUMES{$volume}{'controller'}, - $VOLUMES{$volume}{'device'}, - $VOLUMES{$volume}{'status'} - ); -} + sub parse_bioctl_line { + my ($line) = @_; + chomp $line; -foreach my $volume (sort keys %DISKS) { - foreach my $disk (sort keys %{ $DISKS{$volume} }) { - my $cur_state = $Status_Map{ $DISKS{$volume}{$disk}{'status'} } ? - $Status_Map{ $DISKS{$volume}{$disk}{'status'} } : - 'UNKNOWN'; - push @{ $states{$cur_state} }, sprintf("%5s %-7s %-11s %s", - $DISKS{$volume}{$disk}{'volume'}{'controller'}, - $DISKS{$volume}{$disk}{'device'}, - $DISKS{$volume}{$disk}{'status'}, - $DISKS{$volume}{$disk}{'name'} - ); - } + # Do these by columns cuZ that is the easiest for now + my @o = unpack( "A6 A1 A11 A15 A7 A9 A*", $line ); + return if $o[0] eq 'Volume'; + + foreach (@o) { + s/^\s+//xms; + s/\s+$//xms; + } + + my ( $controller, $id, $status, $size, $dev, $details, $name ) = @o; + my $index = $id; + if ($controller) { + $vid = $id; + } + else { + $index = "$vid.$id"; + } + + my %item = ( + type => 'volume', + controller => $controller, + id => $id, + status => $status, + size => $size, + device => $dev, + details => $details, + name => $name, + volume_id => $vid, + ); + + return $index, \%item; + } } -#print Dumper \%states; +sub check_status { + my ($volumes) = @_; -$state = 'OK'; -my $have_results = 0; -foreach my $error (sort { $ERRORS{$a} <=> $ERRORS{$b} } keys %ERRORS) { - if (exists $states{$error}) { - $have_results++; - $state = $error; - } + my %states; + foreach my $device ( sort keys %{$volumes} ) { + foreach my $index ( sort keys %{ $volumes->{$device} } ) { + my $cur_volume = $volumes->{$device}->{$index}; + my $cur_state = $Status_Map{ $cur_volume->{'status'} } + || 'UNKNOWN'; + + if ( $cur_volume->{'device'} =~ /^\d+:\d/xms ) { + push @{ $states{$cur_state} }, + sprintf( + "%5s %-7s %-11s %s", + $cur_volume->{'volume'}{'controller'}, + $cur_volume->{'device'}, + $cur_volume->{'status'}, + $cur_volume->{'name'} + ); + } + else { + push @{ $states{$cur_state} }, + sprintf( "%5s %-7s %s", + $cur_volume->{'controller'}, + $cur_volume->{'device'}, + $cur_volume->{'status'} ); + } + } + } + return %states; } -foreach my $error (sort { $ERRORS{$b} <=> $ERRORS{$a} } keys %ERRORS) { - if (exists $states{$error}) { - if (NAGIOS_OUTPUT) { - print "$error (" . scalar(@{ $states{ $error } }) . ")"; - unless ($error eq 'OK') { - print '
'; - print map { " - $_
" } @{ $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 { - print < + $PROGNAME -d [ -d [ -d ... ] ] Usage: -d, --device=DEVICE - DEVICE to check. Can either be a disk, as in sd0 - or a raid card like ami0 + DEVICE to check. Can be any device that bioctl(8) accepts -h (--help) usage help -V (--version) version information EOL - - print_revision($PROGNAME, '$Revision: 1.1 $'); + + print_revision( $PROGNAME, '$Revision: 1.14 $' ); + + print $License; + + return 1; } +sub print_revision { + my ( $prog, $rev ) = @_; + $rev =~ s/^\D+([\d\.]+)\D+$/v$1/xms; + + print "$prog $rev\n"; + + return 1; +}