check_ldap_repl.pl
changeset 21 172a86d4d34e
parent 20 79e0cc971747
equal deleted inserted replaced
20:79e0cc971747 21:172a86d4d34e
     1 #! /usr/bin/perl -w
       
     2 
       
     3 #    Copyright (C) 2012  Christian Arnold
       
     4 #    Copyright (C) 2016  Matthias Förste
       
     5 #
       
     6 #    This program is free software: you can redistribute it and/or modify
       
     7 #    it under the terms of the GNU General Public License as published by
       
     8 #    the Free Software Foundation, either version 3 of the License, or
       
     9 #    (at your option) any later version.
       
    10 #
       
    11 #    This program is distributed in the hope that it will be useful,
       
    12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    14 #    GNU General Public License for more details.
       
    15 #
       
    16 #    You should have received a copy of the GNU General Public License
       
    17 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
       
    18 #
       
    19 #    Matthias Förste <foerste@schlittermann.de>
       
    20 
       
    21 =encoding utf8
       
    22 =cut
       
    23 
       
    24 use strict;
       
    25 use warnings;
       
    26 
       
    27 # required? https://rt.cpan.org/Public/Bug/Display.html?id=95875
       
    28 use threads;
       
    29 
       
    30 use File::Basename;
       
    31 use AppConfig;
       
    32 use Net::LDAP;
       
    33 use File::stat;
       
    34 use Pod::Usage;
       
    35 use if $ENV{DEBUG} => "Smart::Comments";
       
    36 
       
    37 my %ERRORS = (
       
    38     OK        => 0,
       
    39     WARNING   => 1,
       
    40     CRITICAL  => 2,
       
    41     UNKNOWN   => 3,
       
    42     DEPENDENT => 4
       
    43 );
       
    44 
       
    45 my $ME      = basename $0;
       
    46 my $NAME    = "LDAPREPL";
       
    47 my $VERSION = "0.4";
       
    48 
       
    49 my $defaults = {
       
    50     'attribute|a=s' => 'description',
       
    51     'dn|d=s'        => undef,
       
    52     'binddn|D=s'    => undef,
       
    53     'password=s'    => undef,
       
    54     'config=s'      => '/etc/nagios-plugins/config/ldap_repl.cfg',
       
    55     'provider|p=s'  => 'ldapi:///',
       
    56     'consumer|c=s@' => undef,
       
    57     'wait|w=i'      => 1,
       
    58     'help|h!'       => sub { pod2usage(-verbose => 1, -exitval => $ERRORS{OK}) },
       
    59     'man|m!'        => sub { pod2usage(-verbose => 2, -exitval => $ERRORS{OK}) },
       
    60     'version|V!'    => sub { version($ME, $VERSION); exit $ERRORS{OK}; }
       
    61 };
       
    62 
       
    63 sub critical { print STDERR "$NAME CRITICAL: ", @_; exit $ERRORS{CRITICAL}; }
       
    64 $SIG{__DIE__} = sub { print STDERR "$NAME UNKNOWN: ", @_; exit $ERRORS{UNKNOWN}; };
       
    65 
       
    66 sub stamp {
       
    67     my ($u, $dn, $attr) = @_;
       
    68 
       
    69     my $l = ref $u eq 'Net::LDAP' ? $u : Net::LDAP->new($u, onerror => 'die')
       
    70       or die "$@";
       
    71     my $r = $l->search(base => $dn, scope => 'base', filter => '(objectClass=*)');
       
    72     die "unexpected result count: ", $r->count unless $r->count == 1;
       
    73     my @v = $r->entry(0)->get_value($attr);
       
    74     die "unexpected value count [@v]" unless @v == 1;
       
    75     return $v[0];
       
    76 
       
    77 }
       
    78 
       
    79 sub version {
       
    80     my ($progname, $version) = @_;
       
    81 
       
    82     print <<_VERSION;
       
    83 $progname version $version
       
    84 Copyright (C) 2012 by Christian Arnold and Schlittermann internet & unix support.
       
    85 Copyright (C) 2016 by Matthias Förste and Schlittermann internet & unix support.
       
    86 
       
    87 $ME comes with ABSOLUTELY NO WARRANTY. This is free software,
       
    88 and you are welcome to redistribute it under certain conditions.
       
    89 See the GNU General Public Licence for details.
       
    90 _VERSION
       
    91 }
       
    92 
       
    93 MAIN: {
       
    94 
       
    95     my $c = AppConfig->new(
       
    96         { CASE => 1 },
       
    97         map {
       
    98             $_,
       
    99               { ref $defaults->{$_} eq 'CODE'
       
   100                 ? 'ACTION'
       
   101                 : 'DEFAULT' => $defaults->{$_} }
       
   102         } keys %{$defaults}
       
   103     ) or die "Can't initialize";
       
   104 
       
   105     my $cf = $c->get('config');
       
   106 
       
   107     # ignore default configuration file if it does not exist
       
   108     $c->file($cf) if -e $cf;
       
   109 
       
   110     # read configuration file if passed on command line
       
   111     $c->getopt(qw(no_ignore_case));
       
   112     $c->file($cf) if $cf ne ($cf = $c->get('config'));
       
   113 
       
   114     # make sure that command line options override any config file options
       
   115     $c->getopt;
       
   116 
       
   117     my %o = $c->varlist('.');
       
   118     $o{binddn} //= $o{dn};
       
   119     my $t = time();
       
   120 
       
   121     my $p = Net::LDAP->new($o{provider}, onerror => 'die') or die $@;
       
   122     $p->bind($o{binddn}, password => $o{password});
       
   123     $p->modify($o{dn}, replace => { $o{attribute} => $t });
       
   124 
       
   125     my $tp = stamp($p, $o{dn}, $o{attribute});
       
   126     die "Provider update failed for unknown reason\n" unless $tp == $t;
       
   127     sleep $o{wait};
       
   128     for (@{ $o{consumer} }) {
       
   129         critical "'$_' out of sync\n"
       
   130           unless $tp == stamp($_, $o{dn}, $o{attribute});
       
   131     }
       
   132 
       
   133     print "$NAME OK: servers are in sync\n";
       
   134     exit $ERRORS{OK};
       
   135 
       
   136 }
       
   137 
       
   138 __END__
       
   139 
       
   140 =pod
       
   141 
       
   142 =head1 NAME
       
   143 
       
   144 check_ldap_repl - nagios/icinga plugin to check ldap replication. This works by
       
   145 updating an entry on the provider and checking whether the update is replicated
       
   146 by querying the consumers for the updated entry after a short waiting period.
       
   147 
       
   148 =head1 SYNOPSIS
       
   149 
       
   150 check_ldap_repl [-d|--dn string]
       
   151                 [-D|--binddn string]
       
   152                 [--password string]
       
   153                 [--config string]
       
   154                 [-p|--provider string]
       
   155                 [-c|--consumer string]
       
   156                 [-w|--wait integer]
       
   157                 [-h|--help]
       
   158                 [-m|--man]
       
   159                 [-V|--version]
       
   160 
       
   161 =head1 OPTIONS
       
   162 
       
   163 =over
       
   164 
       
   165 =item B<-a>|B<--attribute> I<string>
       
   166 
       
   167 Attribute of the entry that will be updated and checked for replication. (default: description)
       
   168 
       
   169 =item B<-d>|B<--dn> I<string>
       
   170 
       
   171 DN of the entry whose attribute will be updated and checked for replication.
       
   172 
       
   173 =item B<-b>|B<--binddn> I<string>
       
   174 
       
   175 DN to use when binding to provider for update. (default: same as dn)
       
   176 
       
   177 =item B<--password> I<string>
       
   178 
       
   179 Password to use when binding to provider for update. B<PASSWORD IS SHOWN IN PROCESSES, USE CONFIG FILE!>
       
   180 
       
   181 =item B<-p>|B<--provider> I<string>
       
   182 
       
   183 provider uri (default: ldapi:///)
       
   184 
       
   185 =item B<-S>|B<--consumer> I<string>
       
   186 
       
   187 consumer uri. Multiple consumers can be specified as a comma separated list (see below).
       
   188 
       
   189 =item B<--config> I<string>
       
   190 
       
   191 Path to configuration file. Use this to store the binddn and its password.
       
   192 Verify the ownership and B<permissions>, B<(0400)> is a good choice! (default:
       
   193 /etc/nagios-plugins/config/ldap_repl.cfg)
       
   194     
       
   195 
       
   196 Example:
       
   197 
       
   198  # attribute = description
       
   199  dn = cn=replcheck,dc=local,dc=site
       
   200  # binddn = # same as dn per default
       
   201  password = secret
       
   202  #provider = ldapi:///
       
   203  consumer = ldap://consumer-01:389/,ldap://consumer-02:389/,...
       
   204  #wait = 1
       
   205 
       
   206 =item B<-w>|B<--wait> I<integer>
       
   207 
       
   208 Wait I<n> seconds before checking the consumer servers. (default: 1)
       
   209 
       
   210 =item B<-h>|B<--help>
       
   211 
       
   212 Print detailed help screen.
       
   213 
       
   214 =item B<-m>|B<--man>
       
   215 
       
   216 Print manual page.
       
   217 
       
   218 =item B<-V>|B<--version>
       
   219 
       
   220 Print version information.
       
   221 
       
   222 =back
       
   223 
       
   224 =head1 DESCRIPTION
       
   225 
       
   226 This plugin checks if the ldap replication works correctly by updating an
       
   227 attribute of an entry on the provider and checking whether the update has been
       
   228 replicated to one or more consumers after some configurable time. It is
       
   229 recommended to run it on the provider because the directory needs to be updated
       
   230 there. The object classes for dn and binddn don't matter much, but they should
       
   231 support authentication and the chosen attribute for updates. The attribute
       
   232 should support numeric integer values (it will be updated with the current
       
   233 unix epoch). Example:
       
   234 
       
   235     430 cn=replcheck,ou=Users,dc=wiegandslide,dc=de
       
   236     objectClass: simpleSecurityObject
       
   237     objectClass: applicationProcess
       
   238     cn: replcheck
       
   239     userPassword: {SSHA}Twb/q2n4G6+PmSUfZaK09smj751ts9Rz
       
   240 
       
   241 The attribute does not neccessarily need to exist initially. It should be
       
   242 created upon first update. You may also need to update your acl.
       
   243 
       
   244 =head1 VERSION
       
   245 
       
   246 This man page is current for version 0.4 of B<check_ldap_repl>.
       
   247 
       
   248 =head1 AUTHOR
       
   249 
       
   250 Written by Christian Arnold L<arnold@schlittermann.de>. Modified by Matthias Förste L<foerste@schlittermann.de>.
       
   251 
       
   252 =head1 COPYRIGHT
       
   253 
       
   254 Copyright (C) 2012 by Christian Arnold and Schlittermann internet & unix support.
       
   255 Copyright (C) 2016 by Matthias Förste and Schlittermann internet & unix support.
       
   256 This is free software, and you are welcome to redistribute it under certain conditions.
       
   257 See the GNU General Public Licence for details.
       
   258 
       
   259 =cut