#!/usr/bin/perl -w
#
# Plugin to check status of linux mdstat raid partitions
#   Some code taken from check_linux_raid.pl by Steve Milton, 
#     Copyright (c) 2002 ISOMEDIA, Inc.
#

use strict;
use File::Basename;
BEGIN {
  use lib dirname($0);
  use Nagios::Plugin;
}

my $VERSION = '0.2 [http://www.openfusion.com.au/labs/nagios/]';

my $USAGE = qq(usage: %s [-e] [-v]\n);
my $errors_only;
my @SPEC = (
  "errors-only|e" => [ \$errors_only, 
  q(-e, --errors-only
   Display only devices with errors) ],
);

parse_args(
  version => $VERSION,
  usage => $USAGE,
  spec => \@SPEC,
);

# Exit with an error if we're not on Linux
&exit("UNKNOWN", "$plugin only works on Linux") unless $^O eq 'linux';

open (MDSTAT, "</proc/mdstat") ||
    &exit("CRITICAL", "Failed to open /proc/mdstat: $!");
my %md = ();
my $current = '';
while (<MDSTAT>) {
    chomp;
    if (/^(md\d+)\s*:/) {
        my $dev = $1;
        $md{$dev} ||= {};
        $md{$dev}->{line1} = $_;
        $md{$dev}->{line1} =~ s/\s+$//;
        $md{$dev}->{active} = 1 if m/active/;
        $current = $dev;
    }
    elsif (m/^\s*$/) {
        undef $current;
    }
    elsif ($current) {
        if (/(\[[_U]+\])/) {
            $md{$current}->{status} = $1;
            $md{$current}->{line2} = $_;
            $md{$current}->{line2} =~ s/^\s+//;
            $md{$current}->{line2} =~ s/\s+$//;
        }
        elsif (/recovery\s*=\s*(\S+)/) {  
            $md{$current}->{recovery} = $1;
            $md{$current}->{line3} = $_;
            $md{$current}->{line3} =~ s/^\s+//;
            $md{$current}->{line3} =~ s/\s+$//;
            $md{$current}->{finish} = $1 if /finish\s*=\s*(\S+)/;
        }
        elsif (/resync\s*=\s*(\S+)/) {  
            $md{$current}->{resync} = $1;
            $md{$current}->{line3} = $_;
            $md{$current}->{line3} =~ s/^\s+//;
            $md{$current}->{line3} =~ s/\s+$//;
            $md{$current}->{finish} = $1 if /finish\s*=\s*(\S+)/;
        }
    }
}
if ($verbose) {
    eval { require YAML; print "md data:\n" . YAML::Dump(\%md); }
}

my @check;
if (@ARGV) {
    my @bogus = grep { ! exists $md{$_} } @ARGV;
    if (@bogus) {
        &exit("CRITICAL", sprintf("Unknown md device%s: %s", 
            (@bogus > 1 ? 's' : ''),
            join(' ', @bogus)
        ));
    }
    @check = @ARGV;
}
else {
    @check = sort keys %md;
}
&exit("UNKNOWN", "No raid devices found") unless @check;

my (@crit, @warn, @ok);
for my $dev (@check) {
    my $status = sprintf("%s%s%s", 
        $md{$dev}->{line1} || '',
        $md{$dev}->{line2} ? ' ' . $md{$dev}->{line2} : '',
        $md{$dev}->{line3} ? ' ' . $md{$dev}->{line3} : '',
    );
    if ($md{$dev}->{status} =~ m/_/) {
        if ($md{$dev}->{recovery}) {
            push @warn, $status;
        }
        else {
            push @crit, $status;
        }
    }
    elsif ($md{$dev}->{status} =~ m/\[U+\]/) {
        push @ok, $status unless $errors_only;
    }
    elsif ($md{$dev}->{active}) {
        push @ok, $status unless $errors_only;
    }
    else {
        push @crit, $status;
    }
}

my $results = join ' :: ', @crit, @warn, @ok;
$results ||= sprintf "%s raid device%s found, all OK", 
  scalar(keys %md), (scalar(keys %md) == 1 ? '' : 's');
exit_results(CRITICAL => \@crit, WARNING => \@warn, results => $results);

# arch-tag: 1956e645-1026-4fda-a953-dfea5dbf1ae1
# vim:ft=perl:ai:sw=4
