#!/usr/bin/perl -w

# COPYRIGHT:
#
# This software is Copyright (c) 2008 NETWAYS GmbH, Tobias Redel
#                                <support@netways.de>
#
# (Except where explicitly superseded by other copyright notices)
#
#
# LICENSE:
#
# This work is made available to you under the terms of Version 2 of
# the GNU General Public License. A copy of that license should have
# been provided with this software, but in any event can be snarfed
# from http://www.fsf.org.
#
# This work 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., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 or visit their web page on the internet at
# http://www.fsf.org.
#
#
# CONTRIBUTION SUBMISSION POLICY:
#
# (The following paragraph is not intended to limit the rights granted
# to you to modify and distribute this software under the terms of
# the GNU General Public License and is only of importance to you if
# you choose to contribute your changes and enhancements to the
# community by submitting them to NETWAYS GmbH.)
#
# By intentionally submitting any modifications, corrections or
# derivatives to this work, or any other work intended for use with
# this Software, to NETWAYS GmbH, you confirm that
# you are the copyright holder for those contributions and you grant
# NETWAYS GmbH a nonexclusive, worldwide, irrevocable,
# royalty-free, perpetual, license to use, copy, create derivative
# works based on those contributions, and sublicense and distribute
# those contributions and any derivatives thereof.
#
# Nagios and the Nagios logo are registered trademarks of Ethan Galstad.

=head1 NAME

check_dss

=head1 SYNOPSIS

check_dss -H <host or IP>
	  -C <community>
	  -P <snmp version>
	  [-s]
	  [-m]
	  [-i] <interface>
	  [-w]
	  [-c]
	  [-h]
	  [-V]

=head1 OPTIONS

=over

=item -H|--host <host or IP>

Hostname or IP address

=item -C|--community <community>

SNMP community (eg. 'public')

=item -P|--protocol

SNMP protocol version

=item -s|--swap

Check SWAP space (can be used with -w and -c)

=item -m|--memory

Check physical memory (can be used with -w and -c)

=item -i|--interface <interface>

Check interface

=item -w|--warning <free space>

Specify WARNING (MB or percent); WARNING if space less than <free space>

=item -c|--critical <free space>

Specify CRITICAL (MB or percent); CRITICAL if space less than <free space>

=item -h|--help

Print help message and exit

=item -V|--version

Print version and exit

=back

=head1 DESCRIPTION

A plugin for checking open-e Data Storage Server

=cut



use strict;
use Getopt::Long qw(:config no_ignore_case bundling);
use Pod::Usage;
use Net::SNMP;

# version string
my $version = '0.1';

# define states
our @state = ('OK', 'WARNING', 'CRITICAL', 'UNKNOWN');

# get CLI parameters
my ($optHost, $optCommunity, $optProtocol, $optMemory, $optSWAP, $optInterface, $optWarning, $optCritical, $optHelp, $optVersion);
GetOptions(
	"H|host=s"	=> \$optHost,
	"C|community=s"	=> \$optCommunity,
	"P|protocol=s"	=> \$optProtocol,
	"s|swap"	=> \$optSWAP,
	"m|memory"	=> \$optMemory,
	"i|interface=s" => \$optInterface,
	"w|warning=s"	=> \$optWarning,
	"c|critical=s"	=> \$optCritical,
	"h|help"	=> \$optHelp,
	"V|version"	=> \$optVersion
);



# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #
# help and version page...
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #

# should print version?
if (defined $optVersion) { print $version."\n"; exit 0; }

# should print help?
if (defined $optHelp || !defined $optHost || !defined $optCommunity || !defined $optProtocol) { pod2usage(1); }
if (!defined $optSWAP && !defined $optMemory && !defined $optInterface) { pod2usage(1); }



# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #
# let's go!
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #

# define vars
my $MIBS;

# define MIBS
my $MIBmain = '.1.3.6.1.2.1';
$MIBS->{MEM}->{size}->{OID}  = $MIBmain.'.25.2.3.1.5.2';
$MIBS->{MEM}->{used}->{OID}  = $MIBmain.'.25.2.3.1.6.2';
$MIBS->{SWAP}->{size}->{OID} = $MIBmain.'.25.2.3.1.5.3';
$MIBS->{SWAP}->{used}->{OID} = $MIBmain.'.25.2.3.1.6.3';
$MIBS->{INTERFACES}->{search}->{OID} = $MIBmain.'.2.2.1.2';
$MIBS->{INTERFACES}->{state}->{OID}  = $MIBmain.'.2.2.1.8';
$MIBS->{INTERFACES}->{speed}->{OID}  = $MIBmain.'.2.2.1.5';

# create SNMP session
my $session = SNMPcreateSession($optHost, $optCommunity, $optProtocol);

# get stuff...
doSWAP($optWarning, $optCritical) if defined $optSWAP;
doMEM($optWarning, $optCritical) if defined $optMemory;
doInterface($optInterface) if defined $optInterface;



# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #
# functions...
# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #

sub LeavePlugin {
        my $exitCode = shift;
        my $comment  = shift;

	# close SNMP session...
	$session->close;

	# ...and exit
        print $state[$exitCode]." - $comment\n";
        exit $exitCode;
}


sub SNMPcreateSession {
	my $hostname  = shift;
	my $community = shift;
	my $version   = shift;
	my $timeout   = 10;
	my ($session, $error) = Net::SNMP->session(
                                -hostname      => $hostname,
				-community     => $community,
				-version       => $version,
                          	-timeout       => $timeout
                        	);

	return $session;
}


sub doSWAP {
	my $warning =  shift;
	my $critical = shift;
	my ($swapSize, $swapUsed, $swapFree, $swapFreePercent);
	my $message;
	my $status = 0;

	# get stuff via SNMP
	my $result = $session->get_request(-varbindlist => [$MIBS->{SWAP}->{size}->{OID}, $MIBS->{SWAP}->{used}->{OID}]);

	# calc values (to MB)
	$swapSize = sprintf("%.0f", $result->{$MIBS->{SWAP}->{size}->{OID}}/1024);
	$swapUsed = sprintf("%.0f", $result->{$MIBS->{SWAP}->{used}->{OID}}/1024);
	$swapFree = sprintf("%.0f", $swapSize - $swapUsed);

	# calc used in percent
	my $onePercent = $swapSize/100;
	$swapFreePercent = sprintf("%.0f", $swapFree/$onePercent);

	# finish
	$message = "$swapFree MB free ($swapFreePercent%)";
	if (defined $warning && defined $critical) {
		# decide status...
		if ($warning =~ /%/ && $critical =~ /%/) {
			$warning  = (split(/%/, $warning))[0];
			$critical = (split(/%/, $critical))[0];
			
			$warning  = $warning*$onePercent;
			$critical = $critical*$onePercent;

			if ($swapFree <= $warning)  { $status = 1; }
			if ($swapFree <= $critical) { $status = 2; }

			$warning  = sprintf("%.0f", $swapSize-$warning);
			$critical = sprintf("%.0f", $swapSize-$critical);
		} else {
			if ($swapFree <= $warning)  { $status = 1; }
			if ($swapFree <= $critical) { $status = 2; }
		}

		# ...and add stuff to message
		$message .= ";| SWAP=$swapUsed"."MB;$warning;$critical;0;$swapSize";
	}

	LeavePlugin($status, $message);
}


sub doMEM {
         my $warning =  shift;
         my $critical = shift;
         my ($memSize, $memUsed, $memFree, $memFreePercent);
         my $message;
         my $status = 0;
 
         # get stuff via SNMP
         my $result = $session->get_request(-varbindlist => [$MIBS->{MEM}->{size}->{OID}, $MIBS->{MEM}->{used}->{OID}]);
 
         # calc values (to MB)
         $memSize = sprintf("%.0f", $result->{$MIBS->{MEM}->{size}->{OID}}/1024);
         $memUsed = sprintf("%.0f", $result->{$MIBS->{MEM}->{used}->{OID}}/1024);
         $memFree = sprintf("%.0f", $memSize - $memUsed);
 
         # calc used in percent
         my $onePercent = $memSize/100;
         $memFreePercent = sprintf("%.0f", $memFree/$onePercent);
 
         # finish
         $message = "$memFree MB free ($memFreePercent%)";
         if (defined $warning && defined $critical) {
                 # decide status...
                 if ($warning =~ /%/ && $critical =~ /%/) {
                         $warning  = (split(/%/, $warning))[0];
                         $critical = (split(/%/, $critical))[0];
                 
                         $warning  = $warning*$onePercent;
                         $critical = $critical*$onePercent;
                 
                         if ($memFree <= $warning)  { $status = 1; }
                         if ($memFree <= $critical) { $status = 2; }
                         
                         $warning  = sprintf("%.0f", $memSize-$warning);
                         $critical = sprintf("%.0f", $memSize-$critical);
                 } else {
                         if ($memFree <= $warning)  { $status = 1; }
                         if ($memFree <= $critical) { $status = 2; }
                 }
          
                 # ...and add stuff to message
                 $message .= ";| MEM=$memUsed"."MB;$warning;$critical;0;$memSize";
         }
 
         LeavePlugin($status, $message);
}


sub doInterface {
	my $interfaceGiven = shift;
	my ($interfaceFound, $interfaceIdent, $interfaceState, $interfaceSpeed);
	my ($result, $state);

	# search MIB
	$result = $session->get_table($MIBS->{INTERFACES}->{search}->{OID});
	foreach(keys %{$result}) {
		my $result2 = $session->get_request(-varbindlist => [$_]);
		$interfaceFound = $_ if $result2->{$_} eq $interfaceGiven;
	}

	# exit if interface not found
	LeavePlugin('3', "Interface '$interfaceGiven' not found!") if !defined $interfaceFound;

	# get identifier
	my @val = split(/\./, $interfaceFound); foreach(@val) { $interfaceIdent = $_; }

	# get state
	$result = $session->get_request($MIBS->{INTERFACES}->{state}->{OID}.'.'.$interfaceIdent);
	if ($result->{$MIBS->{INTERFACES}->{state}->{OID}.'.'.$interfaceIdent} == 1) {
		$interfaceState = "online";
		$state = "0";

		# get interface speed
		my $result2 = $session->get_request($MIBS->{INTERFACES}->{speed}->{OID}.'.'.$interfaceIdent);
		$interfaceSpeed = $result2->{$MIBS->{INTERFACES}->{speed}->{OID}.'.'.$interfaceIdent};
		$interfaceSpeed = $interfaceSpeed / 100000;
	} elsif ($result->{$MIBS->{INTERFACES}->{state}->{OID}.'.'.$interfaceIdent} == 2) {
		$interfaceState = "offline";
		$state = "2";
	} else {
		$interfaceState = "unknown";
		$state = "2";
	}

	# generate message and leave plugin
	my $message = "Interface '$interfaceGiven' is $interfaceState";
	$message .= " with speed $interfaceSpeed" if defined $interfaceSpeed;
	LeavePlugin($state, $message);

}
