--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,8 @@
+syntax: glob
+*.swp
+debian/files
+check_ldap_repl
+
+syntax: regexp
+(build|configure)-stamp$
+debian/nagios-plugin-ldap-repl[./]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,22 @@
+SCRIPTS = check_ldap_repl
+CLEANFILES = ${SCRIPTS}
+DESTDIR =
+prefix = /usr
+
+plugindir = ${prefix}/lib/nagios/plugins/ius
+
+.PHONY: all clean install
+
+all: ${SCRIPTS}
+
+clean:
+ -rm -f ${CLEANFILES}
+
+install: all
+ install -d -m 0755 ${DESTDIR}/${plugindir}
+ install -m 0755 $(SCRIPTS) ${DESTDIR}/${plugindir}/
+
+%: %.pl
+ @perl -c $<
+ @cp -f $< $@
+ @chmod +x $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/check_ldap_repl.pl Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,402 @@
+#! /usr/bin/perl -w
+
+# Copyright (C) 2012 Christian Arnold
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+# Christian Arnold <arnold@schlittermann.de>
+
+# packages: libnet-ldap-perl
+# packages: libio-prompt-perl
+# packages: libio-socket-ssl-perl
+# packages: libconfig-inifiles-perl
+# packages: perl-doc (optional - for man page)
+
+use strict;
+use File::Basename;
+use Getopt::Long;
+use Config::IniFiles;
+use Net::LDAP;
+use IO::Prompt;
+use File::stat;
+use Pod::Usage;
+use if $ENV{DEBUG} => "Smart::Comments";
+
+sub version($$);
+sub read_config();
+sub ldap_object($);
+sub get_stamp($$);
+sub compare_results(%);
+
+my %ERRORS = (
+ OK => 0,
+ WARNING => 1,
+ CRITICAL => 2,
+ UNKNOWN => 3,
+ DEPENDENT => 4
+);
+
+my $ME = basename $0;
+my $NAME = "LDAPREPL";
+my $VERSION = "0.1";
+
+my %opt = (
+ init => 0,
+ delete => 0,
+ refresh => 0,
+ cn => "replcheck",
+ wait => 1,
+ file => "/etc/nagios/ius/plugins/config/check_ldap_repl.cfg",
+ master => "ldap://ldap-master:389/",
+ slave => "ldap://ldap-slave:389/"
+);
+
+MAIN: {
+ Getopt::Long::Configure('bundling');
+ GetOptions(
+ "i|init" => \$opt{init},
+ "d|delete" => \$opt{delete},
+ "r|refresh" => \$opt{refresh},
+ "b|binddn=s" => \$opt{binddn},
+ "p|password=s" => \$opt{password},
+ "c|cn=s" => \$opt{cn},
+ "w|wait=i" => \$opt{wait},
+ "M|master=s" => \$opt{master},
+ "S|slave=s" => \$opt{slave},
+ "f|file=s" => \$opt{file},
+ "h|help" => sub { pod2usage( -verbose => 1, -exitval => $ERRORS{OK} ) },
+ "m|man" => sub { pod2usage( -verbose => 2, -exitval => $ERRORS{OK} ) },
+ "V|version" => sub { version( $ME, $VERSION ); exit $ERRORS{OK}; }
+ ) or pod2usage( -verbose => 1, -exitval => $ERRORS{CRITICAL} );
+
+ if ($opt{init}) {
+ ldap_object("init");
+ print "new object successfully initialized\n";
+ exit $ERRORS{OK};
+ } elsif ($opt{delete}) {
+ ldap_object("delete");
+ print "object successfully deleted\n";
+ exit $ERRORS{OK};
+ }
+
+ ldap_object("refresh") if ($opt{refresh});
+
+ my ($master, $slave, $cn) = undef;
+ my @slaves = ();
+ my %results = ();
+
+ if (-r $opt{file}) {
+ (undef, undef, $master, $slave, $cn) = read_config();
+ @slaves = split(/,/, $slave);
+ } else {
+ $master = $opt{master};
+ @slaves = split(/,/, $opt{slave});
+ $cn = $opt{cn};
+ }
+
+ $results{$master}{'master'} = get_stamp($master, $cn);
+ sleep $opt{wait};
+ foreach (@slaves) {
+ $results{$_}{'slave'} = get_stamp($_, $cn);
+ }
+
+ compare_results(\%results);
+}
+
+sub compare_results(%) {
+ my @output = ();
+ my %stamps = ();
+ my (%results) = %{$_[0]};
+ for my $server ( keys %results ) {
+ for my $type ( keys %{ $results{$server} } ) {
+ $stamps{$results{$server}{$type}} = "";
+ push @output, "$type: $server = $results{$server}{$type}";
+ }
+ }
+
+ @output = sort(@output);
+ if (scalar(keys(%stamps)) != 1 ) {
+ print "$NAME CRITICAL: server are not in sync @output\n";
+ exit $ERRORS{CRITICAL};
+ } else {
+ print "$NAME OK: servers are in sync @output\n";
+ exit $ERRORS{OK};
+ }
+}
+
+sub read_config() {
+ my ($binddn, $password, $cn, $master, $slave);
+ my $cfg = new Config::IniFiles( -file => "$opt{file}");
+ $binddn = $cfg->val('bind', 'dn')?$cfg->val('bind', 'dn'):$opt{binddn};
+ $password = $cfg->val('bind', 'password')?$cfg->val('bind', 'password'):$opt{password};
+ $master = $cfg->val('master', 'server')?$cfg->val('master', 'server'):$opt{master};
+ $slave = $cfg->val('slave', 'server')?$cfg->val('slave', 'server'):$opt{slave};
+ $cn = $cfg->val('object', 'cn')? $cfg->val('object', 'cn'):$opt{cn};
+
+ return ($binddn, $password, $master, $slave, $cn);
+}
+
+sub ldap_object($) {
+ my $type = shift;
+ my ($binddn, $password) = undef;
+
+ my $master = $opt{master};
+ my $cn = $opt{cn};
+
+ if ( ($type eq "init") || ($type eq "delete") ) {
+ $binddn = prompt('BindDN: ');
+ $password = prompt('Password: ', -e => '*');
+ } else {
+ if ($opt{binddn} && $opt{password}) {
+ $binddn = $opt{binddn};
+ $password = $opt{password};
+ } elsif (-r $opt{file}) {
+ ($binddn, $password, $master, undef, $cn) = read_config();
+ } else {
+ $binddn = prompt('BindDN: ');
+ $password = prompt('Password: ', -e => '*');
+ }
+ }
+
+ my $ldap = Net::LDAP->new( $master ) or die "$@";
+
+ my $mesg = $ldap->bind("$binddn", password => $password);
+ if ($mesg->code) {
+ $ldap->unbind() if ($ldap);
+ print "$NAME CRITICAL: " . $mesg->error . "\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ # get ldap naming context
+ my $dse = $ldap->root_dse();
+ my $context = $dse->get_value('namingContexts');
+
+ if (! defined $context) {
+ print "$NAME CRITICAL: can't determine ldap 'naming context'\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ if ($mesg->code) {
+ print "$NAME CRITICAL: " . $mesg->error . "\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ # initialize check object
+ $mesg = $ldap->add(
+ "cn=$cn,$context",
+ attr => [
+ 'objectclass' => [ 'top', 'person' ],
+ 'cn' => "$cn",
+ 'sn' => "$cn",
+ 'description' => time()
+ ],
+ ) if ($type eq "init");
+
+ # delete check object
+ $mesg = $ldap->delete("cn=$cn,$context") if ($type eq "delete");
+
+ if ($mesg->code && ($type eq "delete" || $type eq "init")) {
+ print "$NAME CRITICAL: " . $mesg->error . "\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ # refresh check object
+ $mesg = $ldap->modify(
+ "cn=$cn,$context",
+ replace => {
+ description => time()
+ }
+ ) if ($opt{refresh});
+
+ $ldap->unbind() if ($ldap);
+ return 0;
+}
+
+sub get_stamp($$) {
+ my ($server, $cn) = @_;
+ my $ldap = Net::LDAP->new( $server ) or die "$@";
+ my $mesg = $ldap->bind();
+
+ if ($mesg->code) {
+ $ldap->unbind() if ($ldap);
+ print "$NAME CRITICAL: " . $mesg->error . "\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ # get ldap naming context
+ my $dse = $ldap->root_dse();
+ my $context = $dse->get_value('namingContexts');
+
+ if (! defined $context) {
+ print "$NAME CRITICAL: can't determine ldap 'naming context'\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ $mesg = $ldap->search(
+ base => "cn=replcheck,$context",
+ scope => "base",
+ filter => "(cn=$cn)",
+ attr => [ 'description' ]
+
+ );
+
+ if ($mesg->code) {
+ $ldap->unbind() if ($ldap);
+ print "$NAME CRITICAL: " . $mesg->error . "\n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ if ($mesg->count != 1) {
+ print "$NAME CRITICAL: \n";
+ exit $ERRORS{CRITICAL};
+ }
+
+ my $entry = $mesg->entry(0);
+ return $entry->get_value("description");
+
+ $ldap->unbind() if ($ldap);
+}
+
+sub version($$) {
+ my ( $progname, $version ) = @_;
+
+ print <<_VERSION;
+$progname version $version
+Copyright (C) 2012 by Christian Arnold and Schlittermann internet & unix support.
+
+$ME comes with ABSOLUTELY NO WARRANTY. This is free software,
+and you are welcome to redistribute it under certain conditions.
+See the GNU General Public Licence for details.
+_VERSION
+}
+
+__END__
+
+=head1 NAME
+
+check_ldap_repl - nagios/icinga plugin to check correctly working of ldap replication.
+
+=head1 SYNOPSIS
+
+check_ldap_repl [-i|--init]
+ [-d|--delete]
+ [-r|--refresh]
+ [-c|--cn string]
+ [-b|--binddn string]
+ [-p|--password string]
+ [-f|--file string]
+ [-M|--master string]
+ [-S|--slave string]
+ [-w|--wait integer]
+ [-h|--help]
+ [-m|--man]
+ [-V|--version]
+
+=head1 OPTIONS
+
+=over
+
+=item B<-i>|B<--init>
+
+Add the check object cn=replcheck,I<namingContext> to the master server if not existis. See also the B<--cn> option.
+You will ask for an B<binddn> and B<password>, if not given B<--binddn> and B<--password> options.
+Your B<binddn> must have write permission to the ldap master server.
+
+=item B<-d>|B<--delete>
+
+Delete the check object from the ldap master server if existis. See also the B<--cn> option.
+You will ask for an B<binddn> and B<password>, if not given B<--binddn> and B<--password> options.
+Your B<binddn> must have write permission to the ldap master server.
+
+=item B<-r>|B<--refresh>
+
+Refresh the stamp attribute of the check attribute with current unix time.
+You will ask for an B<binddn> and B<password>, if not given B<--binddn> and B<--password> options. See also B<--file> option.
+Your B<binddn> must have write permission to the ldap master server.
+
+=item B<-c>|B<--cn> I<string>
+
+cn for the initialized object. See also the B<--init> option. (default: replcheck)
+
+=item B<-b>|B<--binddn> I<string>
+
+DN to bind to ldap master server.
+
+=item B<-p>|B<--password> I<string>
+
+Password for binddn to ldap master server. B<PASSWORD IS SHOWN IN PROCESSES, USE CONFIG FILE!>
+
+=item B<-M>|B<--master> I<string>
+
+LDAP master server (provider) (default: ldap://ldap-master:389/)
+
+=item B<-S>|B<--slave> I<string>
+
+LDAP slave server (consumer), multiple slaves can be specified as a comma-separate list (default: ldap://ldap-slave:389/)
+
+=item B<-f>|B<--file> I<string>
+
+Config file with B<binddn> and B<password>. Verify the file B<owner>/B<group> and B<permissions>, B<(0400)> is a good choice!
+You can also set B<master,slave> and B<cn> options. (default: /etc/nagios/ius/plugins/config/check_ldap_repl.cfg)
+
+ [bind]
+ dn = cn=admin,dc=local,dc=site
+ password = secret
+
+ [master]
+ server = ldap://ldap-master:389/
+
+ [slave]
+ server = ldap://ldap-slave01:389/,ldap://ldap-slave02:389/,...
+
+ [object]
+ cn = replcheck
+
+=item B<-w>|B<--wait> I<integer>
+
+Wait I<n> seconds before check the slave servers. (default: 1)
+
+=item B<-h>|B<--help>
+
+Print detailed help screen.
+
+=item B<-m>|B<--man>
+
+Print manual page.
+
+=item B<-V>|B<--version>
+
+Print version information.
+
+=back
+
+=head1 DESCRIPTION
+
+This plugin checks if the ldap replication works correctly.
+
+=head1 VERSION
+
+This man page is current for version 0.1 of B<check_ldap_repl>.
+
+=head1 AUTHOR
+
+Written by Christian Arnold L<arnold@schlittermann.de>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2012 by Christian Arnold and Schlittermann internet & unix support.
+This is free software, and you are welcome to redistribute it under certain conditions.
+See the GNU General Public Licence for details.
+
+=cut
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/changelog Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,5 @@
+nagios-plugin-ldap-repl (0.1) stable; urgency=low
+
+ * Initial Release.
+
+ -- Christian Arnold <arnold@schlittermann.de> Thu, 29 Nov 2012 11:51:52 +0100
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/compat Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,1 @@
+7
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/control Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,14 @@
+Source: nagios-plugin-ldap-repl
+Section: net
+Priority: extra
+Maintainer: Christian Arnold <arnold@schlittermann.de>
+Build-Depends: debhelper (>= 7.0.50~)
+Standards-Version: 3.8.4
+Homepage: https://ssl.schlittermann.de/hg/ius/nagios/nagios-plugin-ldap-repl/
+
+Package: nagios-plugin-ldap-repl
+Architecture: all
+Depends: ${misc:Depends}, ${perl:Depends}, libnet-ldap-perl, libio-prompt-perl, libio-socket-ssl-perl, libconfig-inifiles-perl
+Suggests: perl-doc
+Description: nagios/icinga plugin to check ldap replication
+ This plugin checks if the ldap replication works correctly.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/copyright Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,39 @@
+This work was packaged for Debian by:
+
+ Christian Arnold <arnold@schlittermann.de> on Thu, 29 Nov 2012 11:51:52 +0100
+
+It was downloaded from:
+
+ https://ssl.schlittermann.de/hg/ius/nagios/nagios-plugin-ldap-repl/
+
+Upstream Author(s):
+
+ Christian Arnold <arnold@schlittermann.de>
+
+Copyright:
+
+ Copyright (C) 2011 Schlittermann internet & unix support
+
+License:
+
+ 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 3 of the License, or
+ (at your option) any later version.
+
+ This package 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, see <http://www.gnu.org/licenses/>.
+
+On Debian systems, the complete text of the GNU General
+Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
+
+The Debian packaging is:
+
+ Copyright (C) 2012 Christian Arnold <arnold@schlittermann.de>
+
+and is licensed under the GPL version 3, see above.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/rules Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+%:
+ dh $@
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debian/source/format Thu Nov 29 12:12:29 2012 +0100
@@ -0,0 +1,1 @@
+3.0 (native)