#!/usr/bin/perl -w # -*- perl -*- # vim: ft=perl # Copyright Quentin Smith # and Bjorn Ruberg # Licenced under GPL v2 # # We use one script for all monitoring. # This script may be symlinked with several names, all # performing different functions: # 389ds_statistics_bytes # 389ds_statistics_pdu # 389ds_statistics_referrals # 389ds_statistics_entries # 389ds_connections # 389ds_waiters # 389ds_operations # 389ds_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 # http://www.icir.org/fenner/mibs/extracted/DIRECTORY-SERVER-MIB-rfc2605.txt # The possible measurements my %ops = ( # Only read Total 'connections' => { 'search' => 'cn=monitor', 'searchattr' => 'totalconnections', 'desc' => 'The number of connections', 'label' => 'connections', 'vlabel' => 'connections/${graph_period}', 'title' => 'Connection rate', 'info' => 'Rate of connections to the LDAP server', 'scope' => "base" }, 'connections_active' => { 'search' => 'cn=monitor', 'searchattr' => 'currentconnections', 'desc' => 'The number of connections', 'label' => 'connections', 'vlabel' => 'connections', 'type' => 'GAUGE', 'title' => 'Active connections', 'info' => 'Number of connections to the LDAP server', 'scope' => "base" }, 'binds' => { 'search' => 'cn=snmp,cn=monitor', 'label2' => { 'anonymousbinds' => 'Anonymous', 'unauthbinds' => 'Unauthenticated', 'simpleauthbinds' => 'Simple authentication', 'strongauthbinds' => 'Strong authentication', 'bindsecurityerrors' => 'Errors', }, 'desc' => 'The number of binds', 'vlabel' => 'binds/${graph_period}', 'type' => 'DERIVE', 'title' => 'Binds', 'info' => 'Number of binds to the LDAP server', 'scope' => "base" }, 'statistics_bytes' => { 'search' => "cn=monitor", 'searchattr' => 'bytessent', 'desc' => "The number of bytes sent by the LDAP server.", 'vlabel' => 'bytes/${graph_period}', 'label' => 'bytes', 'title' => "Number of bytes sent", 'info' => "The graph shows the number of bytes sent", 'scope' => "base" }, # Entries 'statistics_entries' => { 'search' => "cn=monitor", 'searchattr' => 'entriessent', 'desc' => "The number of entries sent by the LDAP server.", 'vlabel' => 'entries/${graph_period}', 'label' => 'entries', 'title' => "Number of LDAP Entries", 'info' => "The graph shows the number of entries sent", 'scope' => "base" }, 'operations' => { 'search' => 'cn=snmp,cn=monitor', 'label2' => { readops => 'Read', compareops => 'Compare', addentryops => 'Add entry', removeentryops => 'Remove entry', modifyentryops => 'Modify entry', modifyrdnops => 'Modify RDN', listops => 'List', searchops => 'Search', onelevelsearchops => 'One-level search', wholesubtreesearchops => 'Subtree search', errors => 'Error', securityerrors => 'Security error', }, 'desc' => 'The number of operations', 'vlabel' => 'ops/${graph_period}', 'type' => 'DERIVE', 'title' => 'Operations', 'info' => 'Number of completed LDAP operations', 'scope' => "base" }, ); # Config subroutine sub config { my $action = shift; if(!exists $ops{$action}) { die "Unknown action specified: $action"; } print <{'vlabel'} graph_title $ops{$action}->{'title'} graph_category 389-ds 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 ",$ops{$action}->{'type'}||"DERIVE","\n"; } } else { print "$action.label $ops{$action}->{'label'}\n"; print "$action.type ",$ops{$action}->{'type'}||"DERIVE","\n"; print "$action.min 0\n"; } } sub 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 { $mesg = $ldap->bind 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; } # Determine action based on filename first if ($ARGV[0]) { if ($ARGV[0] eq 'autoconf') { autoconf(); } elsif ($ARGV[0] eq "suggest") { print "$0\n"; } elsif ($ARGV[0] eq "config") { foreach my $action (keys %ops) { print "multigraph 389ds_", $action, "\n"; &config ($action); } } exit 0; } # 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 { $mesg = $ldap->bind or die "Failed to bind anonymously: $@"; } if ($mesg->code) { die "Failed to bind: " . $mesg->error; } foreach my $action (keys %ops) { print "multigraph 389ds_", $action, "\n"; # Default scope for LDAP searches. We'll change to other scopes if # necessary. $scope = "one"; my $searchdn = $ops{$action}->{'search'}; my $searchattrs; if ($ops{$action}->{'label2'}) { $searchattrs = [keys %{$ops{$action}->{'label2'}}]; } else { $searchattrs = [$ops{$action}->{'searchattr'} || 'monitorCounter', 'cn']; } my $filter; if ($ops{$action}->{'filter'}) { $filter = "(&(objectclass=*)" . $ops{$action}->{'filter'} . ")"; } else { $filter = "(objectClass=*)"; } if ($ops{$action}->{'scope'}) { $scope = $ops{$action}->{'scope'}; } my @search = ( base => $searchdn, scope => $scope, filter => $filter, attrs => $searchattrs, ); #use Data::Dumper; print Dumper({@search}); $mesg = $ldap->search (@search); $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 ($ops{$action}->{'label2'}) { foreach my $attr (keys %{$ops{$action}->{'label2'}}) { print lc ("${action}_${attr}.value "); print $entry->get_value($attr), "\n"; } } else { print lc ("${action}.value "); print $entry->get_value($ops{$action}->{'searchattr'} || 'monitorCounter'), "\n"; } } } $ldap->unbind;