#!/usr/bin/perl -w
# nagios: -epn
# Don't run this plugin in the embedded perl interpreter
# It hasn't been tested that way
#
#
# This plugin is used to query slapd to get the current number of
# connections and the max number of file descriptors. Considering
# slapd will use some file descriptors for index files and data files
# you'll never see 100% usage. But it's a good idea to set the
# thresholds so you'll know if you're running out of FDs before
# slapd stops accepting new connections (or starts tossing old ones)

use strict;
use Getopt::Long;
use Net::LDAP;
use Net::LDAP::Control::Paged;
use Net::LDAP::Constant qw(LDAP_CONTROL_PAGED);

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

# LDAP Server info
my $ldap_server = undef;
my $ldap_binddn = undef;
my $ldap_password = undef;

# Globals
my $Version='1.0';

# Standard options
my $o_help=		undef; 	# wan't some help ?
my $o_verb=		undef;	# verbose mode
my $o_version=		undef;	# print version

my $o_timeout=  60; 		# Timeout
my $o_warn = 80;
my $o_crit = 90;

# functions

sub p_version { print "t.pl version : $Version\n"; }

sub print_usage {
    print "Usage: $0 [-v] [-t <timeout>] [-V] [--bind=<dn>] [--passwd=<password>]\n";
}

sub help {
   print "\nCheck OpenLDAP File Descriptors for Nagios version ",$Version,"\n";
   print_usage();
   print <<EOT;
-v, --verbose
   print extra debugging information (including interface list on the system)
-h, --help
   print this help message
-H, --hostname
   ldap server to query
-b, --bind
   ldap bind DN (if needed)
-p, --passwd
   ldap password to use (if binding is needed)
-t, --timeout=INTEGER
   timeout for SNMP in seconds (Default: 5)   
-V, --version
   prints version number
-w --warn=PERCENTAGE
   warning percentage
-c --crit=PERCENTAGE
   critical percentage
EOT
}

# For verbose output
sub verb { my $t=shift; print $t,"\n" if defined($o_verb) ; }

sub check_options {
    Getopt::Long::Configure ("bundling");
	GetOptions(
   	'v'	=> \$o_verb,		'verbose'	=> \$o_verb,
        'h'     => \$o_help,    	'help'        	=> \$o_help,
        'H:s'   => \$ldap_server,    	'hostname:s'	=> \$ldap_server,
        'b:s'   => \$ldap_binddn,    	'bind:s'	=> \$ldap_binddn,
        'p:s'   => \$ldap_password,    	'passwd:s'	=> \$ldap_password,
        't:i'   => \$o_timeout,    	'timeout:i'	=> \$o_timeout,
        'c:i'   => \$o_crit,    	'crit:i'	=> \$o_crit,
        'w:i'   => \$o_warn,    	'warn:i'	=> \$o_warn,
	'V'	=> \$o_version,		'version'	=> \$o_version
    );
    if (defined ($o_help) ) { help(); exit 1; }
    if (! defined ($ldap_server)) { help(); exit 1; }
    if (defined($o_version)) { p_version(); exit 1; }
}

########## MAIN #######

check_options();

verb("Alarm at $o_timeout + 5");
alarm($o_timeout+5);

my $ldap = Net::LDAP->new($ldap_server, version=>3) or
           die ("unable to connect to LDAP server $@");

my $result=undef;
if (defined($ldap_binddn) && defined($ldap_password)) {
   $result = $ldap->bind($ldap_binddn, password=>$ldap_password);
} else {
   $result = $ldap->bind();
}
if ($result->code) {
   die ("error binding to LDAP server: ",$result->error);
}

my $connections = 0;
my $MaxFDs = 0;

my $ldap_base = "cn=Connections,cn=Monitor";
my %args = (
   'base'	=> $ldap_base,
   'filter'	=> "(cn=Current)",
   'attrs'	=> ['monitorCounter'],
);
my $ldap_search = undef;
if ($ldap_search = $ldap->search(%args)) {
   if ($ldap_search->code) {
      verb("error searching ldap: %s", $ldap_search->error);
   }
   if ($ldap_search->count > 0) {
      verb("Found " . $ldap_search->count . " records");
      my $record = $ldap_search->shift_entry;
      if (defined($record)) {
         $connections = $record->get_value('monitorCounter');
      }
   } else {
      print "UNKNOWN: Couldn't find $args{'filter'}\n";
      exit $ERRORS{'UNKNOWN'};
   }
}

%args = (
   'base'	=> $ldap_base,
   'filter'	=> "(cn=Max File Descriptors)",
   'attrs'	=> ['monitorCounter'],
);
if ($ldap_search = $ldap->search(%args)) {
   if ($ldap_search->code) {
      verb("error searching ldap: %s", $ldap_search->error);
   }
   if ($ldap_search->count > 0) {
      verb("Found " . $ldap_search->count . " records");
      my $record = $ldap_search->shift_entry;
      if (defined($record)) {
         $MaxFDs = $record->get_value('monitorCounter');
      }
   } else {
      print "UNKNOWN: Couldn't find $args{'filter'}\n";
      exit $ERRORS{'UNKNOWN'};
   }
}

$ldap->unbind;

verb ("MaxFDs = $MaxFDs   connections=$connections");
my $percent = $connections / $MaxFDs * 100.0;
my $t = int ($MaxFDs * ($o_warn / 100.0) + 0.5);
my $tt = int ($MaxFDs * ($o_crit / 100.0) + 0.5);
#my $perfstr = "\| max_conns=$percent;$o_warn;$o_crit file_descriptors=$connections;$t;$tt max_fds=$MaxFDs";
my $perfstr = "\| max_conns=$percent;$o_warn;$o_crit file_descriptors=$connections;$t;$tt";

if ($percent >= $o_crit) {
   print "CRITICAL: Max FDs = $percent % $perfstr\n";
   exit $ERRORS{'CRITICAL'};
} elsif ($percent >= $o_warn) {
   print "WARNING: Max FDs = $percent % $perfstr\n";
   exit $ERRORS{'WARNING'};
} else {
   print "OK: Max FDs = $percent % $perfstr\n";
   exit $ERRORS{'OK'};
}
exit 0;

