summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuilhem Moulin <guilhem@fripost.org>2015-06-11 10:49:36 +0200
committerGuilhem Moulin <guilhem@fripost.org>2015-06-11 10:54:16 +0200
commitf6e10c1db16267ec433445e74bc9a03f6bb3dd7e (patch)
tree5aef3af415a2ab70e3a30a6d0ff5c1f8000b44a9
parent4a3a70ef223bdf9f86dd43556588b83a06a2ddf8 (diff)
Use a single LDAP connection per Munin round to collect slapd statistics.
Using multigraphs instead.
-rw-r--r--roles/common-LDAP/tasks/main.yml21
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/slapd2269
-rwxr-xr-xroles/common/files/usr/local/share/munin/plugins/slapd2_348
-rw-r--r--roles/common/templates/etc/munin/plugin-conf.d/munin-node.j23
4 files changed, 276 insertions, 365 deletions
diff --git a/roles/common-LDAP/tasks/main.yml b/roles/common-LDAP/tasks/main.yml
index a8c784d..aff0e58 100644
--- a/roles/common-LDAP/tasks/main.yml
+++ b/roles/common-LDAP/tasks/main.yml
@@ -8,7 +8,7 @@
- ldapvi
- db-util
- python-ldap
- # for the 'slapd2_' munin plugin
+ # for the 'slapd2' munin plugin
- libnet-ldap-perl
- libauthen-sasl-perl
@@ -137,22 +137,13 @@
mode=0755
-- name: Install 'slapd2_' Munin wildcard plugin
- # we don't install 'slapd_' because it doesn't support SASL binds
- file: src=/usr/local/share/munin/plugins/slapd2_
- dest=/etc/munin/plugins/slapd2_{{ item }}
+- name: Install 'slapd2' Munin plugin
+ # we don't install 'slapd_' because it doesn't support SASL binds and
+ # ours is more parcimonious with LDAP connections
+ file: src=/usr/local/share/munin/plugins/slapd2
+ dest=/etc/munin/plugins/slapd2
owner=root group=root
state=link force=yes
- with_items:
- # sudo /usr/share/munin/plugins/slapd2_ suggest
- - connections
- - statistics_entries
- - operations_diff
- - statistics_referrals
- - statistics_pdu
- - waiters
- - statistics_bytes
- - operations
tags:
- munin
- munin-node
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..68c482b
--- /dev/null
+++ b/roles/common/files/usr/local/share/munin/plugins/slapd2
@@ -0,0 +1,269 @@
+#!/usr/bin/perl -w
+
+# Munin plugin for monitoring slapd. Based on Bjorn Ruberg's slapd_
+# plugin. The main difference is that in our case munin SASL-binds
+# against the LDAP directory, and a single connection is used to collect
+# all statistics.
+# Copyright Bjorn Ruberg <bjorn@ruberg.no>
+# Copyright © 2015 Guilhem Moulin <guilhem@fripost.org>
+#
+# 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, version 2 of the License.
+#
+# 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/>.
+
+use warnings;
+use strict;
+
+use Net::LDAP ();
+use Net::LDAP::Util ();
+use Authen::SASL ();
+
+# 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"
+ }
+ );
+
+
+my $ldap = Net::LDAP::->new( 'ldapi://' );
+my $sasl = Authen::SASL::->new( mechanism => 'EXTERNAL' );
+my $mesg = $ldap->bind( undef, sasl => $sasl );
+die "LDAP error code $mesg->code: $mesg->error\n",
+ Net::LDAP::Util::ldap_error_text($mesg), "\n"
+ if $mesg->code;
+my $basedn = 'cn=Monitor';
+
+
+if (@ARGV and $ARGV[0] eq 'config') {
+ foreach my $action (keys %OPS) {
+ print "multigraph slapd2_$action\n";
+ print "graph_title $OPS{$action}->{title}\n";
+ print "graph_info $OPS{$action}->{info}\n";
+ print "graph_vlabel $OPS{$action}->{vlabel}\n";
+ print "graph_args --base 1000 -l 0\n";
+ print "graph_scale no\n";
+ print "graph_category OpenLDAP\n";
+
+ if ($OPS{$action}->{label2}) {
+ foreach my $key (keys %{$OPS{$action}->{label2}}) {
+ my $name = $action . "_" . $key;
+ print "$name.label $OPS{$action}->{label2}->{$key}\n";
+ print "$name.type GAUGE\n";
+ }
+ } elsif ($action =~ /^operations(?:_diff)?$/) {
+ my $mesg = $ldap->search ( base => "$OPS{$action}->{search},$basedn"
+ , scope => 'one'
+ , deref => 'never'
+ , filter => '(objectclass=*)'
+ , attrs => [ 'monitorOpInitiated'
+ , 'monitorOpCompleted'
+ , 'cn' ]
+ );
+ die "LDAP error code $mesg->code: $mesg->error\n",
+ Net::LDAP::Util::ldap_error_text($mesg), "\n"
+ if $mesg->code;
+
+ while (my $e = $mesg->pop_entry) {
+ my $cn = $e->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";
+ }
+ }
+ } else {
+ print "$action.label $OPS{$action}->{label}\n";
+ print "$action.type DERIVE\n";
+ print "$action.min 0\n";
+ }
+ }
+}
+
+else {
+ foreach my $action (keys %OPS) {
+ 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 $mesg = $ldap->search ( base => "$OPS{$action}->{search},$basedn"
+ , scope => $OPS{$action}->{scope} // 'one'
+ , deref => 'never'
+ , filter => $OPS{$action}->{filter} // '(objectclass=*)'
+ , attrs => \@searchattrs
+ );
+ die "LDAP error code $mesg->code: $mesg->error\n",
+ Net::LDAP::Util::ldap_error_text($mesg), "\n"
+ if $mesg->code;
+
+ print "multigraph slapd2_$action\n";
+ while (my $e = $mesg->pop_entry) {
+ my $cn = $e->get_value('cn');
+ if ($action =~ /operations(_diff)?$/) {
+ if ($1) {
+ my $opsInit = $e->get_value('monitorOpInitiated');
+ my $opsComp = $e->get_value('monitorOpCompleted');
+ printf "operations_diff_%s.value %d\n", lc $cn, ($opsInit - $opsComp);
+ } else {
+ printf "operations_%s.value %d\n", lc $cn, $e->get_value('monitorOpCompleted');
+ }
+ } else {
+ # Hotfix, must do for now
+ printf "%s.value %d\n",
+ (($action =~ /_/ or $action eq 'connections') ? lc $action : lc "${action}_${cn}"),
+ $e->get_value('monitorCounter');
+ }
+ }
+ }
+}
+
+#$mesg = $ldap->search( base => 'cn=Monitor'
+# , scope => 'base'
+# , deref => 'never'
+# , attrs =>
+
+$ldap->unbind();
+
+
+#$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;
diff --git a/roles/common/files/usr/local/share/munin/plugins/slapd2_ b/roles/common/files/usr/local/share/munin/plugins/slapd2_
deleted file mode 100755
index 56774ac..0000000
--- a/roles/common/files/usr/local/share/munin/plugins/slapd2_
+++ /dev/null
@@ -1,348 +0,0 @@
-#!/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;
diff --git a/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2 b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
index e5ba9b5..6cfa3f9 100644
--- a/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
+++ b/roles/common/templates/etc/munin/plugin-conf.d/munin-node.j2
@@ -136,7 +136,6 @@ env.PGPORT 5432
[fail2ban]
user root
-[slapd2_*]
+[slapd2]
user munin
group munin
-env.server ldapi://