Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Script to monitor OpenLDAP performance and sync-replication status via Hobbit
#!/usr/bin/perl
# Buchan Milne <bgmilne@mandriva.org> 20051213
# Script to monitor OpenLDAP performance and sync-replication status via
# Hobbit (may also still work with BigBrother).
#
# 1)Install Net::LDAP (perl-ldap) and Date::Manip (perl-DateManip)
# 2)Run as task from hobbitserver.cfg (or BBEXT in bbdef.sh for BigBrother)
# 3)Use ncv in hobbit to collect data:
# -add "ol=ncv" to TEST2RRD, and "ncv" to GRAPHS in hobbitserver.cfg
# -add NCV_ol="ReadWaiters:GAUGE,WriteWaiters:GAUGE,CurrentConnections:GAUGE"
# to hobbitserver.cfg
# 4)Add something like the contents of hobbitgraph-ol.cfg to hobbitgraph.cfg
# 5)Ensure monitor backend in OpenLDAP 2.1 or later is configured for
# anonymous access from the display server
# 6)Add "ol" to hosts in bb-hosts to monitor with this script
use strict;
use Net::LDAP;
use Date::Manip;
my ($slave,$bbhost,$ldap_message,$ldap_entry,$monitor,$tmp,$content,$status,$base);
my (@slaves,@values);
my %ldap;
my (%ldap_perf,%performance,%master);
my $service = "ol";
my @slave_states = ("in sync", "not a sync-repl slave", "could not check master", "out of sync");
my @state_colours = ("OK", "NONE", "NONE", "WARN","ERR");
my @state_names = ("green", "clear", "clear", "yellow","red");
if ( $ENV{'BBHOME'} ) {
# Use bbhostgrep if available (hobbit), otherwise use a hardcoded list
# of servers:
if ( -f "$ENV{'BBHOME'}/bin/bbhostgrep" ) {
print "DEBUG Found bbhostgrep\n" if $ENV{DEBUG};
open (BBHOSTGREP, $ENV{BBHOME} . "/bin/bbhostgrep " . $service . " |") or die $*;
while (<BBHOSTGREP>) {
my ($junk,$host);
($junk,$host) = split ' ';
print "DEBUG Adding $host to server list\n" if $ENV{DEBUG};
push @slaves, $host;
}
close BBHOSTGREP;
} else {
print "DEBUG Couldn't find bbhostgrep\n" if $ENV{DEBUG};
#@slaves = ('master.domain.com', 'ldap1.domain.com', 'ldap2.domain.com');
@slaves = ('localhost');
}
@state_colours = ("&green", "&clear", "&clear", "&yellow","&red");
} else {
@slaves = @ARGV;
}
foreach $slave (@slaves) {
%master = ();
$status = 0;
$content = "";
print "DEBUG Using $slave\n" if $ENV{DEBUG};
$bbhost = $slave;
$bbhost =~ s/\./\,/g;
if ($ldap{$slave} ne undef or $ldap{$slave} = Net::LDAP->new( $slave, async=> 1 ) ) {
print "DEBUG Binding to $slave\n" if $ENV{DEBUG};
$ldap_message = $ldap{$slave}->bind;
# Get monitor context
$ldap_message = $ldap{$slave}->search(
base => '',
scope => 'base',
filter => '(objectclass=*)',
attrs => ['monitorContext']
);
$ldap_message->code && die $ldap_message->error;
$ldap_entry = $ldap_message->entry(0);
$monitor = $ldap_entry->get_value('monitorContext');
#$ldap_message = $ldap->root_dse();
#$ldap_message->code && die $ldap_message->error;
#$monitor = $ldap_message->get_value('monitorContext');
print "DEBUG Monitor context for $slave: $monitor\n" if $ENV{DEBUG};
%performance = &get_perf($slave,$monitor,$ldap{$slave});
$content = "\n";
foreach ( sort keys %performance ) {
$content .= sprintf "%s : %s\n",$_,$performance{$_};
}
# Get databases that have a master
$ldap_message = $ldap{$slave}->search(
base => $monitor,
scope => 'sub',
filter => '(&(namingContexts=*)(MonitorUpdateRef=*))',
attrs => [ 'monitorupdateref', 'namingContexts' ]
);
if ( $ldap_message->count == 0 ) {
$content .= "$state_colours[0] Not a syncrepl slave\n";
} else {
$content .= "Replication status of slave databases\n";
}
for $ldap_entry ( $ldap_message->all_entries ) {
$master{$ldap_entry->get_value('namingContexts')} = $ldap_entry->get_value('monitorupdateref');
}
for ( keys ( %master )) {
my ($slave_status,$msg) = &check_slave($slave,$master{$_},$_,\%ldap);
$content .= sprintf("%s %s %s %s\n", $state_colours[$slave_status],$_,$slave_states[$slave_status],$msg);
$status = ($status lt $slave_status) ? $slave_status : $status;
}
} else {
$status = 4;
$content = "$@\n";
}
if ( $ENV{BBHOME} eq "" ) {
print $state_colours[$status] . " $slave " . `date`;
print $content;
} else {
my $line = "status " . $bbhost . "." . $service . " " . $state_names[$status] . " " . `date` . "\n";
$line .= $content;
if ( $ENV{BB} ) {
system ("$ENV{BB}", "$ENV{BBDISP}", "$line");
} else {
print "$line";
}
}
}
# clean up ldap connections
foreach (keys %ldap) {
next if not defined ($ldap{$_});
print "DEBUG Unbinding from $_\n" if $ENV{DEBUG};
$ldap{$_}->unbind;
}
sub get_contextcsn {
my ($c_ldapserver,$c_base,$c_ldap) = @_;
my $c_message;
my $c_entry;
my $bound = 'TRUE';
$c_message = $c_ldap->search(
base => $c_base,
scope => 'base',
filter => '(objectclass=*)',
attrs => ['contextCSN']
);
$c_message->code && return $c_message->error;
$c_entry = $c_message->entry(0);
return $c_entry->get_value('contextCSN');
}
sub get_perf {
my ($ldapserver,$base,$ldapconn) = @_;
my ($message,$entry,$dn,$value,$monitortype,$monitorfilter,$firstattrib);
my $bound =' TRUE';
my %perf;
my @monitorattribs;
if ( $ldapconn == undef ) {
$bound = 'FALSE';
printf "DEBUG Binding to $ldapserver\n" if $ENV{DEBUG};
$ldapconn = Net::LDAP->new( $ldapserver, async => 1) or die "$@" unless defined ( $ldapconn);
$message = $ldapconn->bind;
}
# search on monitorcontext for structuralobjectclass
# OL 2.1 = structuralObjectClass: monitor
# OL 2.2 and later = structuralObjectClass: monitorServer
$message = $ldapconn->search(
base => $base,
filter => '(objectclass=*)',
scope => 'base',
attrs => ['structuralObjectClass']
);
$message->code && die $message->error;
$monitortype = $message->entry(0)->get_value('structuralObjectClass');
print "DEBUG monitor is " . $monitortype . "\n" if $ENV{DEBUG};
if ( $monitortype eq "monitorServer" ) {
$monitorfilter = '(&
(|
(objectclass=monitorCounterObject)
(objectclass=monitorOperation)
(objectclass=monitorContainer)
)
(|
(monitorcounter=*)
(monitorOpInitiated=*)
)
)';
@monitorattribs = ['monitorCounter', 'monitorOpInitiated', 'monitorOpCompleted', 'dn'];
$firstattrib = 'monitorCounter';
} elsif ( $monitortype eq 'monitor' ) {
$monitorfilter = '(objectclass=monitor)';
@monitorattribs = ['description', 'dn'];
$firstattrib = 'description';
}
# counters:
print "DEBUG Searching under $base with filter $monitorfilter on $ldapserver\n" if $ENV{DEBUG};
$message = $ldapconn->search(
base => $base,
scope => 'sub',
filter => $monitorfilter,
attrs => @monitorattribs
);
$message->code && die $message->error;
foreach $entry ( $message->all_entries ) {
$dn = $entry->dn;
next if ($dn =~ m/(cn=(Connections|Backends|Databases|Listeners|Time|TLS|SASL|Log)|(^cn=Monitor))/);
print "DEBUG got $dn\n" if $ENV{DEBUG};
$dn =~ s/,$base$//;
$dn =~ s/cn=//g;
$dn =~ s/\,/ /g;
$dn =~ s/ Operations//g;
$dn =~ s/Operations/Operation/g;
$dn =~ s/Statistics//g;
print "DEBUG getting $firstattrib for $dn\n" if $ENV{DEBUG};
$value = $entry->get_value($firstattrib);
if ( $value eq "" ) {
$value = $dn . " Initiated";
$perf{$value} = $entry->get_value('monitorOpInitiated');
$value = $dn . " Completed";
$perf{$value} = $entry->get_value('monitorOpCompleted');
} else {
$perf{$dn} = $value;
}
print "DEBUG $dn:\t $value, $perf{$dn}\n" if $ENV{DEBUG};
}
print "DEBUG Finished search results\n" if $ENV{DEBUG};
return %perf;
}
sub check_slave {
my ($slave,$master,$db,$ldap) = @_;
if ($ldap{$master{$_}} eq undef) {
print "DEBUG Binding to master $master{$_}\n" if $ENV{DEBUG};
$ldap{$master{$_}} = Net::LDAP->new( $master{$_}, async=> 1) or return (2,"");
$ldap{$master{$_}}->bind or return (2,"");
}
my ($mastercsn,$slavecsn);
print "DEBUG Checking $master for $db\n" if $ENV{DEBUG};
$slavecsn = &get_contextcsn($slave,$db,$$ldap{$slave}) or return (1,"");
$mastercsn = &get_contextcsn($master,$db,$$ldap{$master}) or return (2,"");
if ($slavecsn == $mastercsn){
return (0,"");
} else {
my $slavetime = $slavecsn;
my $mastertime = $mastercsn;
my $time;
$slavetime =~ s/#.*//g;
$mastertime =~ s/#.*//g;
$time = DateCalc($mastertime,$slavetime);
$time =~ s/^(.)0:0:/$1/;
$time =~ s/^\+(.*)$/$1 ahead/g;
$time =~ s/^\-(.*)$/$1 behind/g;
foreach ("weeks","days") { $time =~s/:/ $_ /;}
$time =~ s/:/-/g;
return (3,$time);
}
}
@fsultan

This comment has been minimized.

Copy link
Owner Author

commented Jul 8, 2012

I found this script referred to in a couple of syncrepl monitoring related posts. The original source is now a dead link. I found this code in openldap's archive cache (http://www.openldap.org/lists/openldap-software/200602/plDBeaONcBEt.pl) and decided to post it here for redundancy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.