#! /usr/bin/perl -w
#
# check_hp - nagios plugin
#
# Copyright (C) 2008 Guenther Mair,
# Derived from check_ifoperstatus by Christoph Kron.
#
# 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.
#
#
# Report bugs to:  guenther.mair@hoslo.ch
#
# $Id: check_hp 29 2012-04-04 16:19:44Z gunny $
#

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::config('bundling');

my $PROGNAME = "check_hp";
my $REVISION = '$Rev: 29 $';
sub print_help ();
sub usage ();
sub process_arguments ();

my $DEBUG = 0;

my $timeout;
my $hostname;
my $session;
my $error;
my $response;
my $opt_h;
my $opt_V;
my $key;
my $lastc;
my $name;
my $status;
my $state = 'OK';
my $answer = "";
my $community = "public";
my $snmp_version = 1;
my $maxmsgsize = 1472; # Net::SNMP default is 1472
my ($seclevel, $authproto, $secname, $authpass, $privpass, $auth, $priv);
my $context = "";
my $port = 161;
my @snmpoids;
my $debug;
my $countComponents = 0;

# Compaq/HP system states

my %cpqGenericStates = (
  '1','other',
  '2','ok',
  '3','degraded',
  '4','failed');

my %cpqDaLogDrvStates = (
  '1','other',
  '2','ok',
  '3','failed',
  '4','unconfigured',
  '5','recovering',
  '6','readyForRebuild',
  '7','rebuilding',
  '8','wrongDrive',
  '9','badConnect',
  '10','overheating',
  '11','shutdown',
  '12','expanding',
  '13','notAvailable',
  '14','queuedForExpansion');

my %cpqDaPhyDrvStates = (
  '1','other',
  '2','ok',
  '3','failed',
  '4','predictiveFailure');

my %cpqDaPhyDrvSmartStates = (
  '1','other',
  '2','ok',
  '3','replaceDrive');

my %cpqDaTapeDrvStates = (
  '1', 'unknown',
  '2', 'ok',
  '3', 'degraded',
  '4', 'failed',
  '5', 'offline',
  '6', 'missingWasOk',
  '7', 'missingWasOffline');

my %cpqSeCpuStates = (
  '1','unknown',
  '2','ok',
  '3','degraded',
  '4','failed',
  '5','disabled');

my %cpqHeResilientMemStates = (
  '1', 'other',
  '2', 'ok',
  '3', 'degraded');

my %cpqFcaHostStates = (
  '1', 'unknown',
  '2', 'ok',
  '3', 'failed',
  '4', 'shutdown',
  '5', 'loopDegraded',
  '6', 'loopFailed',
  '7', 'notConnected');

# Compaq/HP system OIDs (ascending numeric order)

my $cpqSeCpuStatus = '1.3.6.1.4.1.232.1.2.2.1.1.6';
my $cpqDaCntlrCondition = '1.3.6.1.4.1.232.3.2.2.1.1.6';
my $cpqDaLogDrvStatus = '1.3.6.1.4.1.232.3.2.3.1.1.4';
my $cpqDaLogDrvCondition = '1.3.6.1.4.1.232.3.2.3.1.1.11';
my $cpqDaPhyDrvStatus = '1.3.6.1.4.1.232.3.2.5.1.1.6';
my $cpqDaPhyDrvCondition = '1.3.6.1.4.1.232.3.2.5.1.1.37';
my $cpqDaPhyDrvSmartStatus = '1.3.6.1.4.1.232.3.2.5.1.1.57';
my $cpqDaTapeDrvStatus = '1.3.6.1.4.1.232.3.2.9.1.1.8';
my $cpqHeEventLogCondition = '1.3.6.1.4.1.232.6.2.11.2.0';
my $cpqHeThermalSystemFanStatus = '1.3.6.1.4.1.232.6.2.6.4';
my $cpqHeThermalCpuFanStatus = '1.3.6.1.4.1.232.6.2.6.5';
my $cpqHeFltTolFanCondition = '1.3.6.1.4.1.232.6.2.6.7.1.9';
my $cpqHeTemperatureCondition = '1.3.6.1.4.1.232.6.2.6.8.1.6';
my $cpqHeFltTolPwrSupplyCondition = '1.3.6.1.4.1.232.6.2.9.1';
my $cpqHeFltTolPowerSupplyCondition = '1.3.6.1.4.1.232.6.2.9.3.1.4';
my $cpqRackCommonEnclosureFanCondition = '1.3.6.1.4.1.232.22.2.3.1.3.1.11';
my $cpqRackPowerSupplyCondition = '1.3.6.1.4.1.232.22.2.5.1.1.1.17';
my $cpqHeResilientMemCondition = '1.3.6.1.4.1.232.6.2.14.4';
my $cpqFcaHostCntlrStatus = '1.3.6.1.4.1.232.16.2.7.1.1.4';

my @cpqComponents = (
  $cpqSeCpuStatus,
  $cpqDaCntlrCondition,
  $cpqDaLogDrvStatus,
  $cpqDaLogDrvCondition,
  $cpqDaPhyDrvStatus,
  $cpqDaPhyDrvCondition,
  $cpqDaPhyDrvSmartStatus,
  $cpqDaTapeDrvStatus,
  $cpqHeEventLogCondition,
  $cpqHeThermalSystemFanStatus,
  $cpqHeThermalCpuFanStatus,
  $cpqHeFltTolFanCondition,
  $cpqHeTemperatureCondition,
  $cpqHeFltTolPwrSupplyCondition,
  $cpqHeFltTolPowerSupplyCondition,
  $cpqRackCommonEnclosureFanCondition,
  $cpqRackPowerSupplyCondition,
  $cpqHeResilientMemCondition,
  $cpqFcaHostCntlrStatus);

my @cpqComponentName = (
  'cpqSeCpuStatus',
  'cpqDaCntlrCondition',
  'cpqDaLogDrvStatus',
  'cpqDaLogDrvCondition',
  'cpqDaPhyDrvStatus',
  'cpqDaPhyDrvCondition',
  'cpqDaPhyDrvSmartStatus',
  'cpqDaTapeDrvStatus',
  'cpqHeEventLogCondition',
  'cpqHeThermalCpuFanStatus',
  'cpqHeThermalSystemFanStatus',
  'cpqHeFltTolFanCondition',
  'cpqHeTemperatureCondition',
  'cpqHeFltTolPwrSupplyCondition',
  'cpqHeFltTolPowerSupplyCondition',
  'cpqRackCommonEnclosureFanCondition',
  'cpqRackPowerSupplyCondition',
  'cpqHeResilientMemCondition',
  'cpqFcaHostCntlrStatus');

my @cpqComponentStateType = (
  'cpqSeCpuStates',
  'cpqGenericStates',
  'cpqDaLogDrvStates',
  'cpqGenericStates',
  'cpqDaPhyDrvStates',
  'cpqGenericStates',
  'cpqDaPhyDrvSmartStates',
  'cpqDaTapeDrvStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqGenericStates',
  'cpqHeResilientMemStates',
  'cpqFcaHostStates');


## Validate Arguments

process_arguments();


## Just in case of problems, let's not hang Nagios

$SIG{'ALRM'} = sub {
  print ("ERROR: No snmp response from $hostname (alarm)\n");
  exit $ERRORS{"UNKNOWN"};
};

alarm($timeout);


## Main function

print "Compaq/HP Agent Check:";
for (my $i = 0; $i < @cpqComponents; $i++ ) {
  fetch_status($cpqComponents[$i], $cpqComponentName[$i], $cpqComponentStateType[$i]);
}
if ($countComponents == 0) {
  $state = "UNKNOWN";
  print " no cpq/hp component found\n";
} elsif (!defined $debug && $state eq 'OK') {
  print " overall system state OK\n";
} else {
  print "\n";
}
exit $ERRORS{$state};


### subroutines

sub fetch_status {
  my $value;

  if ($_[1] eq "cpqHeEventLogCondition") {
    if (!defined ($response = $session->get_request($_[0]))) {
      print  " " . $_[1] . " - " . $_[0] . " (OID-tree not found, ignoring)" if (defined $debug);
      # tree not found, ignore!
      return -1;
    }
  } elsif (!defined ($response = $session->get_table($_[0]))) {
    print  " " . $_[1] . " - " . $_[0] . " (OID-tree not found, ignoring)" if (defined $debug);
    # tree not found, ignore!
    return -1;
  }

  while ( ($key, $value) = each %{$response} ) {
    if ($value > 2) {
      # 1 = other/unknow  => assume OK
      # 2 = ok            => OK
      # 3 = failure/worse => CRITICAL
      $state = 'CRITICAL';
    }
    if (defined $debug || $value > 2) {
      print " " . $_[1] . " (";
      print substr($key, length($_[0])+1) . ":" if defined $key;
      if ($_[2] eq 'cpqGenericStates') { print $cpqGenericStates{$value} }
      elsif ($_[2] eq 'cpqHeResilientMemStates') { print $cpqHeResilientMemStates{$value} }
      elsif ($_[2] eq 'cpqDaLogDrvStates') { print $cpqDaLogDrvStates{$value} }
      elsif ($_[2] eq 'cpqDaPhyDrvStates') { print $cpqDaPhyDrvStates{$value} }
      elsif ($_[2] eq 'cpqDaPhyDrvSmartStates') { print $cpqDaPhyDrvSmartStates{$value} }
      elsif ($_[2] eq 'cpqDaTapeDrvStates') { print $cpqDaTapeDrvStates{$value} }
      elsif ($_[2] eq 'cpqSeCpuStates') { print $cpqSeCpuStates{$value} }
      elsif ($_[2] eq 'cpqFcaHostStates') { print $cpqFcaHostStates{$value} };
      print ")";
    }
    $countComponents++;
  }
}

sub usage() {
  printf "\nMissing arguments!\n";
  printf "\n";
  printf "usage: \n";
  printf "check_hp -H <HOSTNAME> [-C <community>] [-d]\n";
  printf "Copyright (C) 2008 Guenther Mair\n";
  printf "\n\n";
  exit $ERRORS{"UNKNOWN"};
}

sub print_help() {
  printf "check_hp plugin for Nagios\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 "   -d (--debug)      debug / verbose mode (print checked details)\n";
  printf "   -L (--seclevel)   choice of \"noAuthNoPriv\", \"authNoPriv\", or \"authPriv\"\n";
  printf "   -U (--secname)    username for SNMPv3 context\n";
  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 "   -p (--port)       SNMP port (default 161)\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, '$Revision: 29 $');
}

sub process_arguments() {
  $status = GetOptions(
    "V"   => \$opt_V, "version"    => \$opt_V,
    "h"   => \$opt_h, "help"       => \$opt_h,
    "d"   => \$debug, "debug"      => \$debug,
    "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,
    "p=i" => \$port,  "port=i" =>\$port,
    "H=s" => \$hostname, "hostname=s" => \$hostname,
    "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,'$Revision: 29 $');
    exit $ERRORS{'OK'};
  }

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

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

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

  if ($snmp_version =~ /3/) {
    # Must define a security level even though default is noAuthNoPriv
    # v3 requires a security username
    if (defined $seclevel  && defined $secname) {

      # Must define a security level even though defualt is noAuthNoPriv
      unless ( grep /^$seclevel$/, qw(noAuthNoPriv authNoPriv authPriv) ) {
        usage();
        exit $ERRORS{"UNKNOWN"};
      }

      # Authentication wanted
      if ( $seclevel eq 'authNoPriv' || $seclevel eq 'authPriv' ) {
        unless ( $authproto eq 'MD5' || $authproto eq 'SHA1' ) {
          usage();
          exit $ERRORS{"UNKNOWN"};
        }

        if (!defined $authpass) {
          usage();
          exit $ERRORS{"UNKNOWN"};
        } else {
          if ($authpass =~ /^0x/) {
            $auth = "-authkey => $authpass" ;
          } else {
            $auth = "-authpassword => $authpass";
          }
        }
      }

      # Privacy (DES encryption) wanted
      if ($seclevel eq 'authPriv') {
        if (!defined $privpass) {
          usage();
          exit $ERRORS{"UNKNOWN"};
        } else {
          if ($privpass =~ /^0x/) {
            $priv = "-privkey => $privpass";
          } else {
            $priv = "-privpassword => $privpass";
          }
        }
      }
    } else {
      usage();
      exit $ERRORS{'UNKNOWN'}; ;
    }
  } # end snmpv3

  # start snmpv1 / snmpv2
  if ($snmp_version =~ /[12]/) {
    ($session, $error) = Net::SNMP->session(
      -hostname   => $hostname,
      -community  => $community,
      -port       => $port,
      -version    => $snmp_version,
      -maxmsgsize => $maxmsgsize
    );

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

  } elsif ($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,
        $auth,
        -authprotocol => $authproto
      );
    } elsif ($seclevel eq 'authPriv') {
      ($session, $error) = Net::SNMP->session(
        -hostname     => $hostname,
        -port         => $port,
        -version      => $snmp_version,
        -username     => $secname,
        $auth,
        -authprotocol => $authproto,
        $priv
      );
    }

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

  } else {
    $state='UNKNOWN';
    print ("$state: No support for SNMP v$snmp_version yet\n");
    exit $ERRORS{$state};
  }
}
## End validation
