#!/usr/bin/perl

# ---------------------------------------------------- #
# File : check_snmp_overland
# Author : Damien SIAUD
# Date : 11/09/2006
# Licence : GPL - http://www.fsf.org/licenses/gpl.txt
#
# This program is free software; you can redistribute it or modify
# it under the terms of the GNU General Public License
#
# Plugin check for nagios 
# ---------------------------------------------------- # 

use Net::SNMP;
use Getopt::Long;
use vars qw(%ERRORS);

use strict;


%ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);


# --------------------------- globals -------------------------- #

my $script_name = "check_snmp_overland";
my $script_version = "0.1";

my $o_host = undef;
my $o_community = undef;
my $o_port = 161;
my $o_help= undef;
my $o_version= undef;
my $o_timeout= 5;
my $o_status = undef;	# check for events status
my $o_library = undef;	# check for library status
my $o_drive = undef;	# check for drives status
my $o_module = undef;	# check for modules status
my $o_test = undef;	# check for snmp session

my $session = undef;
my $return_str = "";

my $critical_counter = 0;
my $warning_counter = 0;
my $unknown_counter = 0;
my $ok_counter = 0;

# ---------------------------- snmp ---------------------------- #

my $oid_prefix= "1.3.6.1.4.1.3351";
my $oid_generic= "1.3.6.1.4.1.3351.1.3.2.1.1.0";

# -- error status
my $oid_error_index = "1.3.6.1.4.1.3351.1.3.2.3.3.1.1";
my $oid_error_code = "1.3.6.1.4.1.3351.1.3.2.3.3.1.2";
my $oid_error_severity = "1.3.6.1.4.1.3351.1.3.2.3.3.1.3";
my $oid_error_msg = "1.3.6.1.4.1.3351.1.3.2.3.3.1.4";
my $oid_error_actionmsg = "1.3.6.1.4.1.3351.1.3.2.3.3.1.5";
my @oid_error = ($oid_error_code, $oid_error_severity, $oid_error_msg, $oid_error_actionmsg);


# -- library status
my $oid_library_table = "1.3.6.1.4.1.3351.1.3.2.3.2";
my $oid_library_index = "1.3.6.1.4.1.3351.1.3.2.3.2.1.1";
my $oid_library_config = "1.3.6.1.4.1.3351.1.3.2.3.2.1.2";
my $oid_library_scsiid = "1.3.6.1.4.1.3351.1.3.2.3.2.1.3";
my $oid_library_status = "1.3.6.1.4.1.3351.1.3.2.3.2.1.4";
my $oid_library_changerstatus = "1.3.6.1.4.1.3351.1.3.2.3.2.1.5";
my $oid_library_state = "1.3.6.1.4.1.3351.1.3.2.3.2.1.6";
my @oid_library = ($oid_library_config, $oid_library_status, $oid_library_state);


# -- drive status
my $oid_drive_table = "1.3.6.1.4.1.3351.1.3.2.3.1.1";
my $oid_drive_valid = "1.3.6.1.4.1.3351.1.3.2.3.1.1.1";
my $oid_drive_index = "1.3.6.1.4.1.3351.1.3.2.3.1.1.2";
my $oid_drive_state = "1.3.6.1.4.1.3351.1.3.2.3.1.1.3";
my $oid_drive_motion = "1.3.6.1.4.1.3351.1.3.2.3.1.1.4";
my $oid_drive_revdrive = "1.3.6.1.4.1.3351.1.3.2.3.1.1.5";
my $oid_drive_revctrl = "1.3.6.1.4.1.3351.1.3.2.3.1.1.6";
my $oid_drive_scsiid = "1.3.6.1.4.1.3351.1.3.2.3.1.1.7";
my $oid_drive_numserial = "1.3.6.1.4.1.3351.1.3.2.3.1.1.8";
my $oid_drive_cleanreq = "1.3.6.1.4.1.3351.1.3.2.3.1.1.9";


# -- module status
my $oid_module_table = "1.3.6.1.4.1.3351.1.3.2.5.5";
my $oid_module_num = "1.3.6.1.4.1.3351.1.3.2.5.1.0";		# Indication of the number of modules
my $oid_module_desc = "1.3.6.1.4.1.3351.1.3.2.5.5.1.1";		# message desribing the module
my $oid_module_index = "1.3.6.1.4.1.3351.1.3.2.5.5.1.2";	# module geometry (master or slave)
my $oid_module_attached = "1.3.6.1.4.1.3351.1.3.2.5.5.1.3";	# indication of whether or not module is attached
my $oid_module_status = "1.3.6.1.4.1.3351.1.3.2.5.5.1.4";	# message desribing the current status of the module
my $oid_module_config = "1.3.6.1.4.1.3351.1.3.2.5.5.1.5";	# Indication of this module's type
my $oid_module_fwrev = "1.3.6.1.4.1.3351.1.3.2.5.5.1.6";	# module's firmware revision level
my $oid_module_numbins = "1.3.6.1.4.1.3351.1.3.2.5.5.1.7";	# Indication of the number of bins within this module
my $oid_module_numdrives = "1.3.6.1.4.1.3351.1.3.2.5.5.1.8";	# Indication of the number of drives within this module
my $oid_module_nummailslots = "1.3.6.1.4.1.3351.1.3.2.5.5.1.9";	# Indication of the number of mailslots within this module



# ---------------------------- main ----------------------------- #

check_options();

($session, $return_str) = Net::SNMP->session(
	-hostname	=> $o_host,
	-community	=> $o_community,
	-port		=> $o_port,
	-timeout	=> $o_timeout
);


if (!defined($session)) {
	print "ERROR opening session: $return_str\n";
	exit $ERRORS{'UNKNOWN'};
}

if(defined($o_test)) {

	my $result = $session->get_request(
		-varbindlist => [$oid_generic]
	);

	if (!defined($result)) {
		printf("ERROR: %s.\n", $session->error);
		$session->close();
		exit $ERRORS{'UNKNOWN'};
	}

	$return_str .= "overlandLoopback for host ".$session->hostname." is '$result->{$oid_generic}'\n";
	$ok_counter++;
}

if(defined($o_status)) {

	my $result = $session->get_request(
		-varbindlist => \@oid_error
	);

	if (!defined($result)) {
		printf("ERROR: %s.\n", $session->error);
		$session->close();
		exit $ERRORS{'UNKNOWN'};
	}

	$return_str .= "Event Log : Code = $result->{$oid_error_code}, Severity = $result->{$oid_error_severity}, Message = $result->{$oid_error_msg}, Action = $result->{$oid_error_actionmsg}\n";


	# 0 = informational error, not very severe
	# 1 = mild error, operator intervention not necessary
	# 2 = hard error, may be corrected remotely
	# 3 = very severe, power cycle required to clear
	
	if($result->{$oid_error_severity} == 0) {
		$warning_counter++;
	}
	elsif($result->{$oid_error_severity} == 1) {
		$warning_counter++;
	}
	elsif($result->{$oid_error_severity} == 2) {
		$critical_counter++;
	}
	elsif($result->{$oid_error_severity} == 3) {
		$critical_counter++;
	}
	else {
		$ok_counter++;
	}
}

if(defined($o_library)) {

	my $result = $session->get_request(
		-varbindlist => \@oid_library
	);

	if(defined($result)) {

		my $config = $result->{$oid_library_config} == 1 ? "Multimodule" : "Standalone";
		my $status = $result->{$oid_library_status};

		my %lib_state = (
			'0'	=> 'initializing', 
			'1'	=> 'online', 
			'2'	=> 'offline'
		);
		
		my $state = $lib_state{$result->{$oid_library_state}};
		
		$return_str .= "$config library status : $result->{$oid_library_status}. State: $state\n";

		if($result->{$oid_library_state} == 0 || $result->{$oid_library_state} == 1) {
			$ok_counter++;
		}
		elsif($result->{$oid_library_state} == 2) {
			$critical_counter++;
		}
		else {
			$unknown_counter++;
		}
	}
}


if(defined($o_drive)) {
	
	my $result = (Net::SNMP->VERSION < 4) ?  
                 $session->get_table($oid_drive_table)
                 :$session->get_table(Baseoid => $oid_drive_table);
  
	if (!defined($result)) {
		printf("ERROR: Description table : %s.\n", $session->error);
		$session->close;
		exit $ERRORS{"UNKNOWN"};
	}

	my @index=undef;
	foreach my $key ( keys %$result) {

		if ( $key =~ /$oid_drive_index/ ) { 
			push @index, $result->{$key};
		}
	}

	my %drv_state = (
		'0'	=> 'initialized, SCSI id is set',
		'1'	=> 'initialized, with some error',
		'3'	=> 'inserted, but not powered on',
		'4'	=> 'physically removed from library'
	);

	foreach my $id (@index) {

		next if(!$id=~/^\d+$/);

		if( $result->{"$oid_drive_valid.$id"} =~ /INVALID/i ) {
			$critical_counter++;
		}
		
		my $state= $result->{"$oid_drive_state.$id"};

		if( $state == 0 ) {
			$ok_counter++;
		}
		else {
			$critical_counter++;
		}

		$return_str .= "Drive ".$result->{"$oid_drive_valid.$id"}." on Scsi(".$result->{"$oid_drive_scsiid.$id"}.") NumSerial(".$result->{"$oid_drive_numserial.$id"}.") Motion(". $result->{"$oid_drive_motion.$id"}.") state : $drv_state{$state} \n";

	}
}

if(defined($o_module)) {

	my $num = $session->get_request(
		-varbindlist => [$oid_module_num]
	);

	if (!defined($num)) {
		printf("ERROR: Description table : %s.\n", $session->error);
		$session->close;
		exit $ERRORS{"UNKNOWN"};
	}

	for my $id (1..$num->{$oid_module_num}) {
		my $result = $session->get_request(
			-varbindlist => ["$oid_module_desc.$id","$oid_module_status.$id"]
		);

		$return_str .= "Module ".$result->{"$oid_module_desc.$id"}." status is ".$result->{"$oid_module_status.$id"}."\n";
	}
}


$session->close;

print $return_str;

if($critical_counter > 0) {
	exit $ERRORS{'CRITICAL'};
}
elsif($warning_counter > 0) {
	exit $ERRORS{'WARNING'};
}
elsif($unknown_counter > 0) {
	exit $ERRORS{'UNKNOWN'};
}

exit $ERRORS{'OK'};


# --------------------------- functions ------------------------- #

sub usage {
	print "Usage: $0 -H <host> -C <community> [-l] [-d] [-m] [-s] [-p <port>] [-t <timeout>] [-T] [-V] [-h]\n";
}


sub version {
	print "$script_name v$script_version\n";
}


sub help {
	version();
	usage();

	print <<HELP;
	-h, --help
   		print this help message
	-H, --hostname=HOST
		name or IP address of host to check
	-C, --community=COMMUNITY NAME
		community name for the host's SNMP agent (implies v1 protocol)
	-l, --library
		check for libraries status
	-d, --drive
		check for drives status
	-m, --module
		check for modules status
	-s, --status
		check for events status
	-P, --port=PORT
		SNMP port (Default 161)
	-t, --timeout=INTEGER
		timeout for SNMP
	-V, --version
		version number
	-T, --test
		check snmp connexion
HELP
}



sub check_options {
	Getopt::Long::Configure("bundling");
	GetOptions(
		'h'	=> \$o_help,		'help'		=> \$o_help,
		'H:s'	=> \$o_host,		'hostname:s'	=> \$o_host,
		'P:i'	=> \$o_port,		'port:i'	=> \$o_port,
		'C:s'	=> \$o_community,	'community:s'	=> \$o_community,
		't:i'	=> \$o_timeout,		'timeout:i'	=> \$o_timeout,
		'V'	=> \$o_version,		'version'	=> \$o_version,
		's'	=> \$o_status,		'status'	=> \$o_status,
		'l'	=> \$o_library,		'library'	=> \$o_library,
		'd'	=> \$o_drive,		'drive'		=> \$o_drive,
		'm'	=> \$o_module,		'module'	=> \$o_module,
		'T'	=> \$o_test,		'test'		=> \$o_test,
	);

	if(defined($o_help)) {
		help(); 
		exit $ERRORS{'UNKNOWN'};
	}

	if(defined($o_version)) {
		version();
		exit $ERRORS{'UNKNOWN'};
	}

	if(!defined($o_host) || !defined($o_community)) {
		usage();
		exit $ERRORS{'UNKNOWN'};
	}
}

