Skip to content

Instantly share code, notes, and snippets.

@fsultan
Created July 8, 2012 18:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save fsultan/3072089 to your computer and use it in GitHub Desktop.
Save fsultan/3072089 to your computer and use it in GitHub Desktop.
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
Copy link
Author

fsultan 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