#!/usr/bin/perl -w
#    
#  (c) 2008  Christian Hailer <christian.hailer@interhyp.de>
#            Interhyp AG
#  (c) 2015  Jonas Meurer <jmeurer@inet.de>
#            INTERNET AG
#
# 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 (or with Netsaint);  if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA
#
#######################################################################
# check_ace_failover - script for checking fault tolerance status
# on Cisco ACE 4700 clusters using SNMP
#
# Version: 0.2
# Changelog: 
# 	2008-12-19: Initial version created
#	2015-09-30: Added config option for ft group

use strict;
use Net::SNMP;
use Getopt::Long;
use lib '/usr/lib/nagios/plugins';
use utils qw (%ERRORS $TIMEOUT);

my $hostname;
my $peername;
my $community;
my $debug;
my $timeout;
my $retries;
my $ftgroup;
my $help;

Getopt::Long::Configure('bundling');
GetOptions (
	"help" 		=> \$help,
	"hostname=s" 	=> \$hostname,
	"peername=s" 	=> \$peername,
	"community=s" 	=> \$community,
	"debug" 	=> \$debug,
	"timeout=i"	=> \$timeout,
	"retries=i"	=> \$retries,
	"ft-group=i"	=> \$ftgroup,
	"h" 		=> \$help,
	"H=s"	 	=> \$hostname,
	"P=s"	 	=> \$peername,
	"C=s"	 	=> \$community,
	"d" 		=> \$debug,
	"t=i"		=> \$timeout,
	"r=i"		=> \$retries,
	"f=i"		=> \$ftgroup
);

unless (defined ($debug)) {
	$debug = 0;
}
unless (defined ($timeout)) {
	$timeout = $TIMEOUT;
}
unless (defined ($retries)) {
	$retries = 1;
}
unless (defined ($ftgroup)) {
	$ftgroup = 1;
}

# Status returned by the SNMP query

my %ace_status = (
	'1' => 'other',
	'2' => 'nonRedundant',
	'3' => 'initializing',
	'4' => 'negotiation',
	'5' => 'active',
	'6' => 'standbyCold',
	'7' => 'standbyConfig',
	'8' => 'standbyBulk',
	'9' => 'standbyHot',
	'10' => 'standbyWarm',
);

###########################################
# sub: help
# Prints help information

sub help () {
	print <<USE;
Usage: check_ace_failover [options]
where options is
-h, --help		Print this text
-H, --hostname		Hostname (required)
-P, --peername		Peername (required)
-C, --community		SNMP Community (required)
-d, --debug		Show debug information
-t, --timeout		Timeout value in seconds (defaults to $TIMEOUT)
-r, --retries		Number of retries (defaults to 1)
-f, --ft-group		Fault Tolerance Group ID (defaults to 1)

Note that every retry has its own timeout value, for example,
if timeout is 15 and retries is 1, maximum timeout would be 30s.

USE
	exit ($ERRORS{OK});
};

###########################################
# sub: status_request
# The function that does the actual snmp
# requests

sub status_request () {
	my ($hostname, $community, $debug, $timeout, $retries) = @_;
	my %status;
	my %snmp_string = (
		# 11.05.2015 jmeurer: OID angepasst für Cisco ASA 4710
		#'state' => '.1.3.6.1.4.1.9.9.650.1.1.4.1.2.1.1',
		'state' => ".1.3.6.1.4.1.9.9.650.1.1.4.1.2.1.$ftgroup",
	);
	my ($state);
	my ($session, $error) = Net::SNMP->session (    -hostname => $hostname,
							-community => $community,
							-retries => $retries,
							-debug => $debug,
							-timeout => $timeout);

	unless ($session) {
		print "Session error: $error\n";
		exit $ERRORS{UNKNOWN};
	}
	my $result = $session->get_request ($snmp_string{state});
	foreach my $key (keys %snmp_string) {
		$status{$key} = $result->{$snmp_string{$key}};
	}
	unless (defined ($status{state})) { 
		print "Error: Check timed out\n";
		exit ($ERRORS{UNKNOWN});
	}
	$session->close;
	return ($status{state});
}

# Check command line arguments

&help () if ($help);
&help () unless ($hostname && $peername && $community);

# Get the status for the host and peer unit

my ($host_state) = &status_request ($hostname, $community, $debug, $timeout, $retries);
my ($peer_state) = &status_request ($peername, $community, $debug, $timeout, $retries);

# Determine status of cluster

if ($host_state == 5 && $peer_state == 9) {
	print "OK - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{OK});
} elsif ($host_state == 5 && $peer_state == 3) {
	print "Warning - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{WARNING});
} elsif ($host_state == 5 && $peer_state == 4) {
	print "Warning - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{WARNING});
} elsif ($host_state == 5 && $peer_state != 9) {
	print "Critical - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{CRITICAL});
} elsif ($host_state != 5) {
	print "Critical - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{CRITICAL});
} else {
	print "Unknown - host: $ace_status{$host_state}, peer: $ace_status{$peer_state}\n";
	exit ($ERRORS{UNKNOWN});
}


