#!/usr/bin/perl
#
# Check zfs pool status
#
# $Header: /opt/home/doke/work/nagios/RCS/check_zpool,v 1.3 2010/09/28 23:25:36 doke Exp $

#use strict;
#use warnings;
use Getopt::Long;
#use Data::Dumper;

$ENV{PATH} = "/usr/sbin:/sbin:$ENV{PATH}";

use vars qw( $verbose $help @crits @warns @unknowns @oks @ignores );


$verbose = 0;
$help = 0;


sub usage {
    my( $rc ) = @_;
    print "Usage: $0 [-vh]
    -v    verbose
    -h    help
";
    exit $rc;
    }

Getopt::Long::Configure ("bundling");
GetOptions(
    'v+' => \$verbose,
    'h' => \$help,
    );
&usage( 0 ) if ( $help );

check_zpool();


my $rc = 0;
my $sep = '';
if ( $#crits >= 0 ) {
    $rc = 2;
    print "CRITICAL ", join( ", ", @crits );
    $sep = '; ';
    }
if ( $#warns >= 0 ) {
    $rc = 1 if ( $rc == 0 );
    print $sep, "Warning ", join( ", ", @warns );
    $sep = '; ';
    }
if ( $#unknowns >= 0 ) {
    $rc = -1 if ( $rc == 0 );
    print $sep, "Unknown ", join( ", ", @unknowns );
    $sep = '; ';
    }
if ( $rc == 0 ) {
    print "Ok ", join( ", ", @oks );
    $sep = '; ';
    }
if ( $#ignores >= 0 ) {
    print $sep, "Ignoring ", join( ", ", @ignores );
    }

print "\n";
exit $rc;


##################


#samba:~10% zpool status
#  pool: rzpool
# state: ONLINE
# scrub: none requested
# scrub: scrub completed after 0h22m with 0 errors on Fri Apr  9 11:08:20 2010
# scrub: resilver completed after 0h22m with 0 errors on Fri Apr  9 11:08:20 2010
#config:
#
#        NAME        STATE     READ WRITE CKSUM
#        rzpool      ONLINE       0     0     0
#          raidz2    ONLINE       0     0     0
#            c0t0d0  ONLINE       0     0     0
#            c0t1d0  ONLINE       0     0     0
#            c1t0d0  ONLINE       0     0     0
#            c1t1d0  ONLINE       0     0     0
#            c2t0d0  ONLINE       0     0     0
#            c2t1d0  ONLINE       0     0     0
#            c4t0d0  ONLINE       0     0     0
#            c4t1d0  ONLINE       0     0     0
#            c5t0d0  ONLINE       0     0     0
#            c5t1d0  ONLINE       0     0     0
#            c3t1d0  ONLINE       0     0     0
#          raidz2    ONLINE       0     0     0
#            c0t2d0  ONLINE       0     0     0
#            c0t3d0  ONLINE       0     0     0
#            c1t2d0  ONLINE       0     0     0
#            c1t3d0  ONLINE       0     0     0
#            c2t2d0  ONLINE       0     0     0
#            c2t3d0  ONLINE       0     0     0
#            c4t2d0  ONLINE       0     0     0
#            c4t3d0  ONLINE       0     0     0
#            c5t2d0  ONLINE       0     0     0
#            c5t3d0  ONLINE       0     0     0
#            c3t2d0  ONLINE       0     0     0
#          raidz2    ONLINE       0     0     0
#            c0t4d0  ONLINE       0     0     0
#            c0t5d0  ONLINE       0     0     0
#            c1t4d0  ONLINE       0     0     0
#            c1t5d0  ONLINE       0     0     0
#            c2t4d0  ONLINE       0     0     0
#            c2t5d0  ONLINE       0     0     0
#            c4t4d0  ONLINE       0     0     0
#            c4t5d0  ONLINE       0     0     0
#            c5t4d0  ONLINE       0     0     0
#            c5t5d0  ONLINE       0     0     0
#            c3t3d0  ONLINE       0     0     0
#          raidz2    ONLINE       0     0     0
#            c0t6d0  ONLINE       0     0     0
#            c0t7d0  ONLINE       0     0     0
#            c1t6d0  ONLINE       0     0     0
#            c1t7d0  ONLINE       0     0     0
#            c2t6d0  ONLINE       0     0     0
#            c2t7d0  ONLINE       0     0     0
#            c4t6d0  ONLINE       0     0     0
#            c4t7d0  ONLINE       0     0     0
#            c5t6d0  ONLINE       0     0     0
#            c5t7d0  ONLINE       0     0     0
#            c3t5d0  ONLINE       0     0     0
#        spares
#          c3t6d0    AVAIL   
#          c3t7d0    AVAIL   
#
#errors: No known data errors




sub check_zpool {
    my( $cmd, $pool, $state, $scrub, $name, $read, $write, $cksum, $errors );

    $cmd = "zpool status";
    $verbose && print "+ $cmd\n";
    if ( ! open( pH, "$cmd < /dev/null 2>&1 |" ) ) {
	push @unknowns, "can't run $cmd: $!";
	return;
	}
    while( <pH> ) {
	chomp;
	$verbose && print "> $_\n";
	if ( m/^ \s* pool: \s* (\S.+)/ix ) {
	    $pool = $1;
	    }
	elsif ( m/^ \s* state: \s* (\S.+)/ix ) {
	    $state = $1;
	    if ( $state eq 'ONLINE' ) {
		# ok
		push @oks, "$pool $state";
		}
	    elsif ( $state eq 'OFFLINE' ) { 
		push @warns, "$pool $state";
		}
	    else { 
		push @crits, "$pool $state";
		}
	    }
	elsif ( m/^ \s* scrub: \s* (\S.*)/ix ) {
	    $scrub = $1;
	    # scrub: scrub completed after 0h22m with 0 errors on Fri Apr  9 11:08:20 2010
	    if ( $scrub eq 'none requested' 
		    || $scrub =~ m/(scrub|resilver) completed after .* with 0 errors/ ) { 
		# ok.
		}
	    else  { 
		push @warns, "zpool $pool scrub is $scrub";
		}
	    }
	elsif ( m/^ \s* config: /ix ) {
	    # ignore
	    }
	elsif ( m/^ \s* $/ix ) {
	    # ignore
	    }
	elsif ( m/^ \s* NAME \s+ STATE \s+ READ \s+ WRITE \s+ CKSUM $/ix ) {
	    # ignore
	    }

	elsif ( m/^ \s* (\S+) \s+ (\S+) \s+ (\d+) \s+ (\d+) \s+ (\d+) $/ix ) {
	    $name = $1;
	    $state = $2;
	    $read = $3;
	    $write = $4;
	    $cksum = $5;

	    if ( $state eq 'OFFLINE' ) { 
		push @warns, "$pool $name $state";
		}
	    elsif ( $state eq 'AVAIL' ) { 
		# hot spare, ok
		}
	    elsif ( $state ne 'ONLINE' ) { 
		push @crits, "$pool $name $state";
		}
	    }
	elsif ( m/^ \s* spares: /ix ) {
	    # ignore
	    }
	elsif ( m/^ \s* errors: \s* (\S.+)/ix ) {
	    $errors = $1;
	    if ( $errors eq 'No known data errors' ) { 
		push @oks, $errors;
		}
	    else { 
		push @crits, $errors;
		}

	    }
	}
    }


