#! /usr/bin/perl -w
#
# check_ift_hdd - nagios plugin
# 
#
# Copyright (C) 2007 Marius Rieder <marius.rieder@inf.ethz.ch>
# Copyright (C) 2010 Stephan Kranz <s.kranz@storitback.de>
#
# This program 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
# of the License, or (at your option) any later version.
#
# This program 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 program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#

use POSIX;
use strict;
use lib "/usr/local/nagios/libexec";
use utils qw($TIMEOUT %ERRORS &print_revision &support);

use Net::SNMP;
use Getopt::Long;
Getopt::Long::Configure('bundling');

my $PROGNAME = "check_ift_hdd";
my $VERSION  = "v1.1";

sub print_help ();
sub usage ();
sub process_arguments ();
sub snmp_connect();

my $status;

my %hddStatusCode = (
      0 => 'New Drive',
      1 => 'On-Line Drive',
      2 => 'Used Drive',
      3 => 'Spare Drive',
      4 => 'Initializing Drive',
      5 => 'Rebuild Drive',
      6 => 'Adding Drive',
      9 => 'Global Spare Drive',
      63 => 'Drive Absend',
      252 => 'Spare Missing',
      253 => 'Spare Missing',
      254 => 'Drive Missing',
      255 => 'Drive Failed',
   );

my $timeout ;
my $state = "UNKNOWN";
my $answer = "";
my $snmpkey=0;
my $snmpoid=0;
my $key=0;
my $community;
my $maxmsgsize = 1472 ; # Net::SNMP default is 1472
my ($seclevel, $authproto, $secname, $authpass, $privpass, $auth, $priv, $context);
my $port = 161;
my @snmpoids;
my $snmpHddTable = '.1.3.6.1.4.1.1714.1.1.6';
my %hddStatus;
my $hostname;
my $session;
my $error;
my $response;
my $snmp_version = 2;
my $opt_h ;
my $opt_V ;
my $opt_x ;
my %excluded ;

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
     print ("ERROR: No snmp response from $hostname (alarm timeout)\n");
     exit $ERRORS{"UNKNOWN"};
};


#Option checking
$status = process_arguments();

if ($status != 0)
{
	print_help() ;
	exit $ERRORS{'OK'};
}

alarm($timeout);

# Opening SNMP Session
snmp_connect();

push(@snmpoids,$snmpHddTable);

if ( $snmp_version =~ /3/ ) {
   if (!defined($response = $session->get_table($snmpHddTable, -contextname => $context))) {
      $answer=$session->error;
      $session->close;
      $state = 'CRITICAL';
      print ("$state: $answer for $snmpoid\n");
      exit $ERRORS{$state};
   }
} else {
   if (!defined($response = $session->get_table($snmpHddTable))) {
      $answer=$session->error;
      $session->close;
      $state = 'CRITICAL';
      print ("$state: $answer for $snmpoid\n");
      exit $ERRORS{$state};
}

foreach $snmpkey (keys %{$response}) {
   $snmpkey =~ /.*\.(\d+)\.(\d+)$/;
      $hddStatus{$2}{$1} = $response->{$snmpkey};
   }
}

$session->close;

alarm(0);

$state = 'OK';
foreach $key (sort {$a <=> $b} keys %hddStatus) {
   next if (exists $excluded{$key});

   if ($hddStatus{$key}{11} == 63 or $hddStatus{$key}{11} >= 252) {
      my $id = $hddStatus{$key}{15}.",".$hddStatus{$key}{17};
      $id =~ s/\s+/\ /g;
      chop($id);
      $answer .= " Drive ".$hddStatus{$key}{13}.": ".$hddStatusCode{$hddStatus{$key}{11}}." ($id)";
      $state = 'CRITICAL';
   } elsif ($hddStatus{$key}{11} == 5) {
      $answer .= " Drive".$hddStatus{$key}{13}.": ".$hddStatusCode{$hddStatus{$key}{11}};
      $state = 'WARNING' if ($state eq 'OK');
   }
}
$answer = ' All Drives OK' if ($state eq 'OK');
print ("$state:$answer\n");
exit $ERRORS{$state};


sub usage (){
	printf "\nMissing arguments!\n";
	printf "\n";
	printf "$PROGNAME -H <HOSTNAME> [-C <COMUNITY>]\n";
	printf "Copyright (C) 2007 Marius Rieder\n";
	printf "\n\n";
	support();
	exit $ERRORS{"UNKNOWN"};
}

sub print_help (){
	printf "$PROGNAME plugin for Nagios monitors status \n";
	printf "of each harddisk in a ift raid.\n";
	printf "\nUsage:\n";
	printf "   -H (--hostname)   Hostname to query - (required)\n";
	printf "   -C (--community)  SNMP read community (defaults to public,\n";
	printf "                     used with SNMP v1 and v2c\n";
	printf "   -v (--snmp_version)  1 for SNMP v1 (default)\n";
	printf "                        2 for SNMP v2c\n";
	printf "                          SNMP v2c will use get_bulk for less overhead\n";
	printf "                        3 for SNMPv3 (requires -U option)";
	printf "   -p (--port)       SNMP port (default 161)\n";
	printf "   -x (--exclude)    A comma separated list of ifType values that should be excluded \n";
	printf "                     from the report (default for an empty list is PPP(23).\n";
	printf "   -L (--seclevel)   choice of \"noAuthNoPriv\", \"authNoPriv\", or	\"authPriv\"\n";
	printf "   -U (--secname)    username for SNMPv3 context\n";
	printf "   -c (--context)    SNMPv3 context name (default is empty	string)";
	printf "   -A (--authpass)   authentication password (cleartext ascii or localized key\n";
	printf "                     in hex with 0x prefix generated by using	\"snmpkey\" utility\n"; 
	printf "                     auth password and authEngineID\n";
	printf "   -a (--authproto)  Authentication protocol ( MD5 or SHA1)\n";
	printf "   -X (--privpass)   privacy password (cleartext ascii or localized key\n";
	printf "                     in hex with 0x prefix generated by using	\"snmpkey\" utility\n"; 
	printf "                     privacy password and authEngineID\n";
	printf "   -M (--maxmsgsize) Max message size - usefull only for v1 or v2c\n";
	printf "   -t (--timeout)    seconds before the plugin times out (default=$TIMEOUT)\n";
	printf "   -V (--version)    Plugin version\n";
	printf "   -h (--help)       usage help \n\n";
	print_revision($PROGNAME, $VERSION);
	
}

sub process_arguments() {
   $status = GetOptions(
         "V"   => \$opt_V,		    "version"        => \$opt_V,
         "h"   => \$opt_h,		    "help"           => \$opt_h,
         "v=i" => \$snmp_version,	"snmp_version=i" => \$snmp_version,
         "C=s" => \$community,		"community=s"    => \$community,
         "L=s" => \$seclevel,		"seclevel=s"     => \$seclevel,
         "a=s" => \$authproto,		"authproto=s"    => \$authproto,
         "U=s" => \$secname,		"secname=s"      => \$secname,
         "A=s" => \$authpass,		"authpass=s"     => \$authpass,
         "X=s" => \$privpass,		"privpass=s"     => \$privpass,
         "c=s" => \$context,		"context=s"      => \$context,
         "p=i" => \$port,		"port=i"         => \$port,
         "H=s" => \$hostname,		"hostname=s"     => \$hostname,
         "x:s" => \$opt_x,		"exclude:s"      => \$opt_x,
         "M=i" => \$maxmsgsize,		"maxmsgsize=i"   => \$maxmsgsize,
         "t=i" => \$timeout,		"timeout=i"      => \$timeout,
      );

   if ($status == 0){
      print_help() ;
      exit $ERRORS{'OK'};
   }

   if ($opt_V) {
      print_revision($PROGNAME, $VERSION);
      exit $ERRORS{'OK'};
   }

   if ($opt_h) {
      print_help();
      exit $ERRORS{'OK'};
   }

   unless (defined $timeout) {
      $timeout = $TIMEOUT;
   }

   if ($snmp_version eq '3' ) {
      unless (defined $seclevel) {
         $seclevel = 'noAuthNoPriv';
      }
      unless ($seclevel eq ('noAuthNoPriv' || 'authNoPriv' || 'authPriv' ) and defined($secname)) {
         usage();
         exit $ERRORS{"UNKNOWN"};
      }

      if ($seclevel =~ /^auth/ and not defined($authpass)) {
         usage();
         exit $ERRORS{"UNKNOWN"};
      } elsif ($seclevel eq 'authPriv'  and not defined($privpass)) {
	 usage();
	 exit $ERRORS{"UNKNOWN"};
      }
   } elsif (not $snmp_version eq '1') {
      $snmp_version = '2c';
   }

   unless (defined $community) {
      $community = 'public';
   }

   # Excluded hdd
   if (defined $opt_x) {
      my @x = split(/,/, $opt_x);
      if (@x) {
	 foreach $key (@x){
	    $excluded{$key} = 1;
	 }
      }
   }

   if (! utils::is_hostname($hostname)){
      usage();
      exit $ERRORS{"UNKNOWN"};
   }
}

sub snmp_connect() {
   if ( $snmp_version =~ /3/ ) {
      if ($seclevel eq 'noAuthNoPriv') {
         ($session, $error) = Net::SNMP->session(
               -hostname  => $hostname,
               -port      => $port,
               -version  => $snmp_version,
               -username => $secname,
            );
      }elsif ( $seclevel eq 'authNoPriv' ) {
         ($session, $error) = Net::SNMP->session(
               -hostname  => $hostname,
               -port      => $port,
               -version  => $snmp_version,
               -username => $secname,
               -authprotocol => $authproto,
               -authpassword => $authpass
            );
      }elsif ($seclevel eq 'authPriv' ) {
         ($session, $error) = Net::SNMP->session(
               -hostname  => $hostname,
               -port      => $port,
               -version  => $snmp_version,
               -username => $secname,
               -authprotocol => $authproto,
               -authpassword => $authpass,
               -privpassword => $privpass
            );
      }
   } else {
      ($session, $error) = Net::SNMP->session(
            -hostname   => $hostname,
            -community  => $community,
            -port       => $port,
            -version    => $snmp_version,
         );
   }

   if (!defined($session)) {
      $state='UNKNOWN';
      $answer=$error;
      print ("$state: $answer");
      exit $ERRORS{$state};
   }
}
