summaryrefslogtreecommitdiffstats
path: root/roles/common/files/usr/local
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2015-06-10 18:16:13 +0200
committerGuilhem Moulin <guilhem@fripost.org>2015-06-10 18:52:21 +0200
commitf24f936c69ee97cca6095923549430cb6d510320 (patch)
treec541c7976bfdf43486b3052ed893c84b1ae029b1 /roles/common/files/usr/local
parentb408390ae9311b7d703ce57c25a78dce23c31b16 (diff)
slapd monitoring.
We don't use the provided 'slapd_' Munin plugin because it doesn't support SASL binds.
Diffstat (limited to 'roles/common/files/usr/local')
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/slapd2_348
1 files changed, 348 insertions, 0 deletions
diff --git a/roles/common/files/usr/local/share/munin/plugins/slapd2_ b/roles/common/files/usr/local/share/munin/plugins/slapd2_
new file mode 100755
index 0000000..56774ac
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/slapd2_
@@ -0,0 +1,348 @@
+#!/usr/bin/perl -w
+# -*- perl -*-
+# vim: ft=perl
+
+# Copyright Bjorn Ruberg <bjorn@ruberg.no>
+# Licenced under GPL v2
+#
+# TODO:
+# - Check for OpenLDAP version
+
+# We use one script for all monitoring.
+# This script may be symlinked with several names, all
+# performing different functions:
+# slapd_statistics_bytes
+# slapd_statistics_pdu
+# slapd_statistics_referrals
+# slapd_statistics_entries
+# slapd_connections
+# slapd_waiters
+# slapd_operations
+# slapd_operations_diff
+
+# Magic markers
+#%# family=auto
+#%# capabilities=autoconf suggest
+
+use strict;
+
+my $ret = '';
+
+if (! eval "require Net::LDAP;") {
+ $ret = "Net::LDAP not found";
+}
+
+use vars qw ( $config $param $act $scope $descr $cn $vlabel
+ $info $title $label);
+
+# Change these to reflect your LDAP ACL. The given DN must have
+# read access to the Monitor branch.
+my $basedn = "cn=Monitor";
+my $server = ($ENV{'server'} || 'localhost');
+my $userdn = ($ENV{'binddn'} || '');
+my $userpw = ($ENV{'bindpw'} || '');
+
+# Remember: connections, bytes, pdu needs scope=base
+
+# The possible measurements
+my %ops =
+ ('statistics_bytes'
+ => {
+ 'search' => "cn=Bytes,cn=Statistics",
+ 'desc' => "The number of bytes sent by the LDAP server.",
+ 'vlabel' => 'Bytes per ${graph_period}',
+ 'label' => 'Bytes',
+ 'title' => "Number of bytes sent",
+ 'info' => "The graph shows the number of bytes sent",
+ 'scope' => "base"
+ },
+ 'statistics_pdu'
+ => {
+ 'search' => "cn=PDU,cn=Statistics",
+ 'desc' => "The number of PDUs sent by the LDAP server.",
+ 'vlabel' => 'PDUs per ${graph_period}',
+ 'label' => 'PDUs',
+ 'title' => "Number of PDUs sent",
+ 'info' => "The graph shows the number of PDUs sent",
+ 'scope' => "base"
+ },
+ # Referrals
+ 'statistics_referrals'
+ => {
+ 'search' => "cn=Referrals,cn=Statistics",
+ 'desc' => "The number of Referrals sent by the LDAP server.",
+ 'vlabel' => 'Referrals per ${graph_period}',
+ 'label' => 'Referrals',
+ 'title' => "Number of LDAP Referrals",
+ 'info' => "The graph shows the number of referrals sent",
+ 'scope' => "base"
+ },
+ # Entries
+ 'statistics_entries'
+ => {
+ 'search' => "cn=Entries,cn=Statistics",
+ 'desc' => "The number of Entries sent by the LDAP server.",
+ 'vlabel' => 'Entries per ${graph_period}',
+ 'label' => 'Entries',
+ 'title' => "Number of LDAP Entries",
+ 'info' => "The graph shows the number of entries sent",
+ 'scope' => "base"
+ },
+ # Only read Total
+ 'connections'
+ => {
+ 'search' => 'cn=Total,cn=Connections',
+ 'desc' => 'The number of connections',
+ 'label' => 'Connections',
+ 'vlabel' => 'Connections per ${graph_period}',
+ 'title' => 'Number of Connections',
+ 'info' => 'Number of connections to the LDAP server',
+ 'scope' => "base"
+ },
+ # dn: cn=Write,cn=Waiters,cn=Monitor
+ # dn: cn=Read,cn=Waiters,cn=Monitor
+ 'waiters'
+ => {
+ 'search' => 'cn=Waiters',
+ 'filter' => '(|(cn=Write)(cn=Read))',
+ 'desc' => "The current number of Waiters",
+ 'label2' => {'write' => 'Write',
+ 'read' => 'Read'},
+ 'vlabel' => "Waiters",
+ 'title' => "Number of Waiters",
+ 'info' => "The graph shows the number of Waiters"
+ },
+ 'operations'
+ => {
+ 'search' => "cn=Operations",
+ 'desc' => "Operations",
+ 'vlabel' => 'Operations per ${graph_period}',
+ 'label' => 'Operations',
+ 'title' => "Operations",
+ 'info' => "Number of completed LDAP operations"
+ },
+ 'operations_diff'
+ => {
+ 'search' => "cn=Operations",
+ 'desc' => "Operations deviance",
+ 'vlabel' => 'Deviance',
+ 'label' => 'Deviance',
+ 'title' => "Operations deviance",
+ 'info' => "Deviance between Initiated and Completed ops"
+ }
+ );
+
+# Config subroutine
+sub config {
+ my $action = shift;
+ print <<EOF;
+graph_args --base 1000 -l 0
+graph_scale no
+graph_vlabel $ops{$action}->{'vlabel'}
+graph_title $ops{$action}->{'title'}
+graph_category OpenLDAP
+graph_info $ops{$action}->{'info'}
+EOF
+
+ if ($ops{$action}->{'label2'}) {
+ while (my ($key, $val) = each (%{$ops{$action}->{'label2'}})) {
+ my $name = $action . "_" . $key;
+ print "$name.label $val\n";
+ print "$name.type GAUGE\n";
+ }
+ } elsif ($action =~ /^operations(?:_diff)?$/) {
+ my $ldap = Net::LDAP->new ($server)
+ or die "Failed to connect to server $server: $@";
+ my $mesg;
+ if ($userdn ne '') {
+ $mesg = $ldap->bind ($userdn, password => $userpw)
+ or die "Failed to bind with $userdn: $@";
+ } else {
+ require Authen::SASL;
+ my $sasl = Authen::SASL::->new( mechanism => 'EXTERNAL' );
+ $mesg = $ldap->bind( undef, sasl => $sasl )
+ or die "Failed to SASL bind: $@";
+ }
+ if ($mesg->code) {
+ die "Failed to bind: " . $mesg->error;
+ }
+ my $searchdn = $ops{$action}->{'search'} . "," . $basedn;
+ $mesg =
+ $ldap->search (
+ base => $searchdn,
+ scope => 'one',
+ filter => '(objectclass=*)',
+ attrs => ['monitorOpInitiated',
+ 'monitorOpCompleted',
+ 'cn'],
+ );
+ $mesg->code && die $mesg->error;
+
+ my $max = $mesg->count;
+ for (my $i = 0 ; $i < $max ; $i++) {
+ my $entry = $mesg->entry ($i);
+ my $cn = $entry->get_value ('cn');
+ my $name = $action . "_" . lc ($cn);
+ print "$name.label $cn\n";
+ print "$name.type DERIVE\n";
+ print "$name.min 0\n";
+ if ($action eq "operations") {
+ print "$name.info The number of $cn operations\n";
+ } else {
+ print "$name.info The difference between Initiated ";
+ print "and Completed operations (should be 0)\n";
+ print "$name.warning 1\n";
+ }
+ }
+
+ $ldap->unbind;
+ } else {
+ print "$action.label $ops{$action}->{'label'}\n";
+ print "$action.type DERIVE\n";
+ print "$action.min 0\n";
+ }
+}
+
+# Determine action based on filename first
+(my $action = $0) =~ s/^.*slapd2_([\w\d_]+)$/$1/;
+
+if ($ARGV[0]) {
+ if ($ARGV[0] eq 'autoconf') {
+ # Check for Net::LDAP
+ if ($ret) {
+ print "no ($ret)\n";
+ exit 0;
+ }
+
+ # Check for LDAP version 3
+ my $ldap = Net::LDAP->new ($server, version => 3)
+ or do { print "no ($@)\n"; exit 0; };
+
+ my $mesg;
+ if ($userdn ne '') {
+ $mesg = $ldap->bind ($userdn, password => $userpw)
+ or do { print "no ($@)\n"; exit 0; };
+ } else {
+ require Authen::SASL;
+ my $sasl = Authen::SASL::->new( mechanism => 'EXTERNAL' );
+ $mesg = $ldap->bind( undef, sasl => $sasl )
+ or do { print "no ($@)\n"; exit 0; };
+ }
+ if ($mesg->code) {
+ print "no (" . $mesg->error . ")\n";
+ exit 0;
+ }
+
+ $mesg =
+ $ldap->search (
+ base => $basedn,
+ scope => 'one',
+ filter => '(objectClass=monitorServer)',
+ attrs => [
+ 'cn',
+ ],
+ );
+ if ($mesg->code) {
+ print "no (" . $mesg->error . ")\n";
+ exit 0;
+ }
+ print "yes\n";
+ exit 0;
+ } elsif ($ARGV[0] eq "config") {
+ if(!exists $ops{$action}) {
+ die "Unknown action specified: $action";
+ }
+ &config ($action);
+ } elsif ($ARGV[0] eq "suggest") {
+ print join ("\n", keys (%ops)), "\n";
+ }
+ exit 0;
+}
+
+# If $action isn't in %ops, we quit
+if(!exists $ops{$action}) {
+ die "Unknown action specified: $action";
+}
+
+# Default scope for LDAP searches. We'll change to other scopes if
+# necessary.
+$scope = "one";
+
+# Net::LDAP variant
+my $ldap = Net::LDAP->new ($server, version => 3)
+ or die "Failed to connect to server $server: $@";
+my $mesg;
+if ($userdn ne '') {
+ $mesg = $ldap->bind ($userdn, password => $userpw)
+ or die "Failed to bind with $userdn: $@";
+} else {
+ require Authen::SASL;
+ my $sasl = Authen::SASL::->new( mechanism => 'EXTERNAL' );
+ $mesg = $ldap->bind( undef, sasl => $sasl )
+ or die "Failed to bind anonymously: $@";
+}
+if ($mesg->code) {
+ die "Failed to bind: " . $mesg->error;
+}
+
+my $searchdn = $ops{$action}->{'search'} . "," . $basedn;
+my $searchattrs;
+
+if ($action =~ /^operations(_diff)?$/) {
+ # We look for different parameters in Operations branch
+ $searchattrs = ['monitorOpInitiated', 'monitorOpCompleted', 'cn'];
+} else {
+ $searchattrs = ['monitorCounter', 'cn'];
+}
+
+my $filter;
+if ($ops{$action}->{'filter'}) {
+ $filter = "(&(objectclass=*)" . $ops{$action}->{'filter'} . ")";
+} else {
+ $filter = "(objectClass=*)";
+}
+
+if ($ops{$action}->{'scope'}) {
+ $scope = $ops{$action}->{'scope'};
+}
+
+$mesg =
+ $ldap->search (
+ base => $searchdn,
+ scope => $scope,
+ filter => $filter,
+ attrs => $searchattrs,
+ );
+
+$mesg->code && die $mesg->error;
+
+my $max = $mesg->count;
+
+for (my $i = 0 ; $i < $max ; $i++) {
+ my $entry = $mesg->entry ($i);
+ my $cn = $entry->get_value('cn');
+ if ($action =~ /operations(_diff)?$/) {
+ if ($1) {
+ my $opsInit =
+ $entry->get_value('monitorOpInitiated');
+ my $opsComp =
+ $entry->get_value('monitorOpCompleted');
+ print lc ("operations_diff_${cn}.value ");
+ print ($opsInit - $opsComp);
+ print "\n";
+ } else {
+ print lc ("operations_${cn}.value ");
+ print $entry->get_value('monitorOpCompleted'),
+ "\n";
+ }
+ } else {
+ # Hotfix, must do for now
+ if ($action =~ /_/ || $action eq 'connections') {
+ print lc ("${action}.value ");
+ } else {
+ print lc ("${action}_${cn}.value ");
+ }
+ print $entry->get_value('monitorCounter'), "\n";
+ }
+}
+$ldap->unbind;