#!/usr/bin/perl -w
# Nagios plugin that checks LSI SAS2 controllers RAID status via sas2ircu
# program

# Copyright (C) 2011 Emmanuel Lacour <elacour@home-dn.net>
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version.
#
# This file is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file; see the file COPYING.  If not, write to the Free
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
# 02110-1301, USA.



use strict;
use lib qw(/usr/local/lib/nagios/plugins /usr/lib/nagios/plugins /usr/lib64/nagios/plugins/);
use utils qw(%ERRORS);

my $sas2ircu = '/usr/local/bin/sas2ircu';
my $status = $ERRORS{'OK'};
my %controllers;
my $errors_message;

unless ( -x $sas2ircu ) {
    print "$sas2ircu not found or not executable\n";
    exit ($ERRORS{'UNKNOWN'});
}

unless ( $> == 0 ) {
    print "This program must be run as root. You may use wrappers like sudo to do this.\n";
    exit ($ERRORS{'UNKNOWN'});
}

foreach my $line (split /\n/, `$sas2ircu LIST`) {
    if ( $line =~ /^\s+(\d+)\s+(.+)\s+(.+)\s+(.+)\s+(.+)\s+(.+)\s+(.+)\s*$/ ) {
        my $ctrl_id = $1;
        my $ctrl_type = $2;
        $controllers{$ctrl_id}{type} = $ctrl_type;
    }
}

unless ( scalar keys %controllers ) {
    print "No controller found\n";
    exit ($ERRORS{'UNKNOWN'});
}

foreach my $ctrl_id (keys %controllers) {
    my $infos = `$sas2ircu $ctrl_id DISPLAY`;

    my %ctrl_infos;
    my $ctrl_start;
    foreach my $line (split /\n/, $infos) {
	chomp($line);
        if ( $line =~ /^Controller information/ ) {
            $ctrl_start = 1;
            next;
        }
	next unless ( $ctrl_start );
        if ( $line =~ /^-/ && $ctrl_start == 1 ) {
            $ctrl_start = 2;
            next;
        }
        if ( $line =~ /^-/ && $ctrl_start == 2 ) {
            $ctrl_start = 0;
            next;
        }
        next unless ( $ctrl_start == 2 );
        if ( $line =~ /^\s*(.*)\s+:\s+(.*)$/ ) {
            my $key = $1;
            my $value = $2;
            $key =~ s/\s+$//;
            $key =~ s/^\s+//;
            $value =~ s/\s+$//;
            $value =~ s/^\s+//;
            $ctrl_infos{$key} = $value;
        }
    }

    # Volumes
    my %volumes_infos;
    my $volume_id = undef;
    foreach my $line (split /\n/, $infos) {
	chomp($line);
        if ( $line =~ /^IR volume (\d+)\s*$/ ) {
            $volume_id = $1;
            next;
        }
        if ( defined($volume_id) && $line =~ /^\s*$/ ) {
            $volume_id = undef;
            next;
        }
        next unless ( defined($volume_id) );
        if ( $line =~ /^\s*(.*)\s+:\s+(.*)\s*$/ ) {
            my $key = $1;
            my $value = $2;
            $key =~ s/\s+$//;
            $key =~ s/^\s+//;
            $value =~ s/\s+$//;
            $value =~ s/^\s+//;
            if ( $key =~ /^PHY/ ) {
                push @{$volumes_infos{$volume_id}{'disks'}}, $value;
            } else {
                $volumes_infos{$volume_id}{$key} = $value;
            }
        }
    }

    unless ( scalar keys %volumes_infos ) {
        print "\tNo volume found\n";
        next;
    }

    # Disks
    my %disks_infos;
    my $disk_start = 0;
    my $disk_encl = undef;
    my $disk_slot = undef;
    foreach my $line (split /\n/, $infos) {
	chomp($line);
        if ( $line =~ /^Device is a Hard disk/ ) {
            $disk_start = 1;
            next;
        }
        if ( $disk_start && $line =~ /^\s*$/ ) {
            $disk_start = 0;
            $disk_encl = undef;
            $disk_slot = undef;
            next;
        }
        next unless ( $disk_start );
        if ( $line =~ /^\s*(.*)\s+:\s+(.*)\s*$/ ) {
            my $key = $1;
            my $value = $2;
            $key =~ s/\s+$//;
            $key =~ s/^\s+//;
            $value =~ s/\s+$//;
            $value =~ s/^\s+//;
            if ( $key eq 'Enclosure #' ) {
                $disk_encl = $value;
                next;
            }
            if ( $key eq 'Slot #' ) {
                $disk_slot = $value;
                next;
            }
            if ( defined($disk_encl) && defined($disk_slot) ) {
                $disks_infos{$disk_encl.':'.$disk_slot}{$key} = $value;
            }
        }
    }

    foreach my $volume_id (keys %volumes_infos) {
        unless ( $volumes_infos{$volume_id}{'Status of volume'} eq 'Okay (OKY)' ) {
            $errors_message .= "Ctrl $ctrl_id: vol $volume_id ".$volumes_infos{$volume_id}{'Status of volume'};
            $status = $ERRORS{'CRITICAL'} unless ( $volumes_infos{$volume_id}{'Status of volume'} eq 'Okay (OKY)' );
        }

        unless ( scalar @{$volumes_infos{$volume_id}{disks}} ) {
            # FIXME is this critical, can this happens ?
            next;
        }

        foreach my $disk (@{$volumes_infos{$volume_id}{disks}}) {
            unless ( $disks_infos{$disk} ) {
                $errors_message .= ", disk $disk not found!";
                $status = $ERRORS{'CRITICAL'};
                next;
            }
            unless ( $disks_infos{$disk}{'State'} eq 'Optimal (OPT)' ) {
                $errors_message .= ", disk: ".$disk." : ".$disks_infos{$disk}{'State'};
                $status = $ERRORS{'CRITICAL'} unless ( $disks_infos{$disk}{'State'} eq 'Optimal (OPT)' );
            }
        }
    }
}

if ( $status == $ERRORS{'OK'} ) {
    print "All arrays OK\n";
} elsif ( $errors_message ) {
    print "$errors_message\n";
}

exit ($status);

