source: trunk/server/common/oursrc/scripts-munin-plugins/389ds @ 2838

Last change on this file since 2838 was 2361, checked in by quentin, 11 years ago
Munin plugin for monitoring 389-ds
  • Property svn:executable set to *
File size: 7.9 KB
Line 
1#!/usr/bin/perl -w
2# -*- perl -*-
3# vim: ft=perl
4
5# Copyright Quentin Smith <quentin@mit.edu>
6# and Bjorn Ruberg <bjorn@ruberg.no>
7# Licenced under GPL v2
8#
9
10# We use one script for all monitoring.
11# This script may be symlinked with several names, all
12# performing different functions:
13# 389ds_statistics_bytes
14# 389ds_statistics_pdu
15# 389ds_statistics_referrals
16# 389ds_statistics_entries
17# 389ds_connections
18# 389ds_waiters
19# 389ds_operations
20# 389ds_operations_diff
21
22# Magic markers
23#%# family=auto
24#%# capabilities=autoconf suggest
25
26use strict;
27
28my $ret = '';
29
30if (! eval "require Net::LDAP;") {
31   $ret = "Net::LDAP not found";
32}
33
34use vars qw ( $config $param $act $scope $descr $cn $vlabel
35              $info $title $label);
36
37# Change these to reflect your LDAP ACL. The given DN must have
38# read access to the Monitor branch.
39my $basedn = "cn=Monitor";
40my $server = ($ENV{'server'} || 'localhost');
41my $userdn = ($ENV{'binddn'} || '');
42my $userpw = ($ENV{'bindpw'} || '');
43
44# Remember: connections, bytes, pdu needs scope=base
45
46# http://www.icir.org/fenner/mibs/extracted/DIRECTORY-SERVER-MIB-rfc2605.txt
47
48# The possible measurements
49my %ops =
50    (
51     # Only read Total
52     'connections' 
53     => {
54         'search' => 'cn=monitor',
55         'searchattr' => 'totalconnections',
56         'desc'   => 'The number of connections',
57         'label'  => 'connections',
58         'vlabel' => 'connections/${graph_period}',
59         'title'  => 'Connection rate',
60         'info'   => 'Rate of connections to the LDAP server',
61         'scope'  => "base"
62         },
63     'connections_active' 
64     => {
65         'search' => 'cn=monitor',
66         'searchattr' => 'currentconnections',
67         'desc'   => 'The number of connections',
68         'label'  => 'connections',
69         'vlabel' => 'connections',
70         'type'   => 'GAUGE',
71         'title'  => 'Active connections',
72         'info'   => 'Number of connections to the LDAP server',
73         'scope'  => "base"
74         },
75     'binds'
76     => {
77         'search' => 'cn=snmp,cn=monitor',
78         'label2' => {
79             'anonymousbinds' => 'Anonymous',
80             'unauthbinds'  => 'Unauthenticated',
81             'simpleauthbinds' => 'Simple authentication',
82             'strongauthbinds' => 'Strong authentication',
83             'bindsecurityerrors' => 'Errors',
84         },
85         'desc'   => 'The number of binds',
86         'vlabel' => 'binds/${graph_period}',
87         'type'   => 'DERIVE',
88         'title'  => 'Binds',
89         'info'   => 'Number of binds to the LDAP server',
90         'scope'  => "base"
91         },     
92     'statistics_bytes'
93     => {
94         'search' => "cn=monitor",
95         'searchattr' => 'bytessent',
96         'desc'   => "The number of bytes sent by the LDAP server.",
97         'vlabel' => 'bytes/${graph_period}',
98         'label'  => 'bytes',
99         'title'  => "Number of bytes sent",
100         'info'   => "The graph shows the number of bytes sent",
101         'scope'  => "base"
102         },
103     # Entries
104     'statistics_entries'
105     => {
106         'search' => "cn=monitor",
107         'searchattr' => 'entriessent',
108         'desc'   => "The number of entries sent by the LDAP server.",
109         'vlabel' => 'entries/${graph_period}',
110         'label'  => 'entries',
111         'title'  => "Number of LDAP Entries",
112         'info'   => "The graph shows the number of entries sent",
113         'scope'  => "base"
114         },
115     'operations'
116     => {
117         'search' => 'cn=snmp,cn=monitor',
118         'label2' => {
119             readops        => 'Read',
120             compareops     => 'Compare',
121             addentryops    => 'Add entry',
122             removeentryops => 'Remove entry',
123             modifyentryops => 'Modify entry',
124             modifyrdnops   => 'Modify RDN',
125             listops        => 'List',
126             searchops      => 'Search',
127             onelevelsearchops => 'One-level search',
128             wholesubtreesearchops => 'Subtree search',
129             errors         => 'Error',
130             securityerrors => 'Security error',
131         },
132         'desc'   => 'The number of operations',
133         'vlabel' => 'ops/${graph_period}',
134         'type'   => 'DERIVE',
135         'title'  => 'Operations',
136         'info'   => 'Number of completed LDAP operations',
137         'scope'  => "base"
138         },
139     );
140
141# Config subroutine
142sub config {
143    my $action = shift;
144    if(!exists $ops{$action}) {
145        die "Unknown action specified: $action";
146    }
147    print <<EOF;
148graph_args --base 1000 -l 0
149graph_vlabel $ops{$action}->{'vlabel'}
150graph_title $ops{$action}->{'title'}
151graph_category 389-ds
152graph_info $ops{$action}->{'info'}
153EOF
154   
155    if ($ops{$action}->{'label2'}) {
156        while (my ($key, $val) = each (%{$ops{$action}->{'label2'}})) {
157          my $name = $action . "_" . $key;
158          print "$name.label $val\n";
159          print "$name.type ",$ops{$action}->{'type'}||"DERIVE","\n";
160        }
161    } else {
162        print "$action.label $ops{$action}->{'label'}\n";
163        print "$action.type ",$ops{$action}->{'type'}||"DERIVE","\n";
164        print "$action.min 0\n";
165    }
166}
167
168sub autoconf {
169    # Check for Net::LDAP
170    if ($ret) {
171        print "no ($ret)\n";
172        exit 0;
173    }
174
175    # Check for LDAP version 3
176    my $ldap = Net::LDAP->new ($server, version => 3)
177        or do { print "no ($@)\n"; exit 0; };
178
179    my $mesg;
180    if ($userdn ne '') {
181      $mesg = $ldap->bind ($userdn, password => $userpw)
182        or do { print "no ($@)\n"; exit 0; };
183    } else {
184      $mesg = $ldap->bind
185        or do { print "no ($@)\n"; exit 0; };
186    }
187    if ($mesg->code) {
188      print "no (" . $mesg->error . ")\n";
189      exit 0;
190    }
191
192    $mesg =
193        $ldap->search (
194                       base   => $basedn,
195                       scope  => 'one',
196                       filter => '(objectClass=monitorServer)',
197                       attrs  => 'cn',
198                       );
199    if ($mesg->code) {
200      print "no (" . $mesg->error . ")\n";
201      exit 0;
202    }
203    print "yes\n";
204    exit 0;
205}
206
207# Determine action based on filename first
208
209if ($ARGV[0]) {
210    if ($ARGV[0] eq 'autoconf') {
211        autoconf();
212    } elsif ($ARGV[0] eq "suggest") {
213        print "$0\n";
214    } elsif ($ARGV[0] eq "config") {
215        foreach my $action (keys %ops) {
216            print "multigraph 389ds_", $action, "\n";
217            &config ($action);
218        }
219    }
220    exit 0;
221}
222
223# Net::LDAP variant
224my $ldap = Net::LDAP->new ($server, version => 3)
225    or die "Failed to connect to server $server: $@";
226my $mesg;
227if ($userdn ne '') {
228  $mesg = $ldap->bind ($userdn, password => $userpw)
229      or die "Failed to bind with $userdn: $@";
230} else {
231  $mesg = $ldap->bind
232      or die "Failed to bind anonymously: $@";
233}
234if ($mesg->code) {
235  die "Failed to bind: " . $mesg->error;
236}
237
238foreach my $action (keys %ops) {
239    print "multigraph 389ds_", $action, "\n";
240
241    # Default scope for LDAP searches. We'll change to other scopes if
242    # necessary.
243    $scope = "one";
244
245    my $searchdn = $ops{$action}->{'search'};
246    my $searchattrs;
247
248    if ($ops{$action}->{'label2'}) {
249        $searchattrs = [keys %{$ops{$action}->{'label2'}}];
250    } else {
251        $searchattrs = [$ops{$action}->{'searchattr'} || 'monitorCounter', 'cn'];
252    }
253
254    my $filter;
255    if ($ops{$action}->{'filter'}) {
256      $filter = "(&(objectclass=*)" . $ops{$action}->{'filter'} . ")";
257    } else {
258      $filter = "(objectClass=*)";
259    }
260
261    if ($ops{$action}->{'scope'}) {
262      $scope = $ops{$action}->{'scope'};
263    }
264
265    my @search = (
266                       base   => $searchdn,
267                       scope  => $scope,
268                       filter => $filter,
269                       attrs  => $searchattrs,
270        );
271
272    #use Data::Dumper; print Dumper({@search});
273
274    $mesg =
275        $ldap->search (@search);
276
277    $mesg->code && die $mesg->error;
278
279    my $max = $mesg->count;
280
281    for (my $i = 0 ; $i < $max ; $i++) {
282        my $entry = $mesg->entry ($i);
283        my $cn = $entry->get_value('cn');
284        if ($ops{$action}->{'label2'}) {
285        foreach my $attr (keys %{$ops{$action}->{'label2'}}) {
286            print lc ("${action}_${attr}.value ");
287            print $entry->get_value($attr), "\n";
288        }
289        } else {
290        print lc ("${action}.value ");
291        print $entry->get_value($ops{$action}->{'searchattr'} || 'monitorCounter'), "\n";
292        }
293    }
294}
295$ldap->unbind;
Note: See TracBrowser for help on using the repository browser.