pcp
[Top] [All Lists]

[PATCH] 389 DS PCP PMDA

To: pcp@xxxxxxxxxxx
Subject: [PATCH] 389 DS PCP PMDA
From: Marko Myllynen <myllynen@xxxxxxxxxx>
Date: Fri, 19 Sep 2014 14:25:11 +0300
Cc: Rich Megginson <rmeggins@xxxxxxxxxx>
Delivered-to: pcp@xxxxxxxxxxx
Organization: Red Hat
Reply-to: myllynen@xxxxxxxxxx
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0
Hi,

below is a 389 Directory Server PMDA, ds389, tested on RHEL 6 
(389-ds-base-1.2.11) / Fedora 20 (389-ds-base-1.3.2). It provides server and 
database (userRoot) metrics and chaining database could be easily added if 
deemed useful. Access log statistics provided by logconv.pl would be something 
to consider for a separate PMDA, i.e., they are out of scope for this PMDA.

RHDS Administration Guide sections 15.6-15.9 document all the above, the 
statistics described in 15.7 and 15.8 are being collected:

https://access.redhat.com/documentation/en-US/Red_Hat_Directory_Server/9.0/html/Administration_Guide/

The only real concern I have at the moment is the need for the 
query_interval/timestamp stuff which is pretty ugly but when doing e.g. "pminfo 
-dfmtT ds389.userroot" two successive queries are done for some reason, I think 
we should avoid such needless LDAP queries.

Connection options could be perhaps improved but using the PMDA on other than 
localhost doesn't sound like a critical feature.

If you want to test this locally, just install the 389-ds-base RPM and run 
setup-ds.pl and you'll have 389 DS up and running.

>From 9850dcc93b97a15daf09b84aad312e5fb2189637 Mon Sep 17 00:00:00 2001
From: Marko Myllynen <myllynen@xxxxxxxxxx>
Date: Fri, 19 Sep 2014 14:04:22 +0300
Subject: [PATCH] 389 DS PCP PMDA

---
 src/pmdas/ds389/Install      |   28 ++++
 src/pmdas/ds389/Remove       |   23 +++
 src/pmdas/ds389/pmdads389.pl |  316 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 367 insertions(+), 0 deletions(-)
 create mode 100755 src/pmdas/ds389/Install
 create mode 100755 src/pmdas/ds389/Remove
 create mode 100644 src/pmdas/ds389/pmdads389.pl

diff --git a/src/pmdas/ds389/Install b/src/pmdas/ds389/Install
new file mode 100755
index 0000000..8c0c97c
--- /dev/null
+++ b/src/pmdas/ds389/Install
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2014 Marko Myllynen <myllynen@xxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=ds389
+pmda_interface=2
+dso_opt=false
+daemon_opt=false
+perl_opt=true
+socket_opt=false
+
+pmdaSetup
+pmdaInstall
+exit 0
diff --git a/src/pmdas/ds389/Remove b/src/pmdas/ds389/Remove
new file mode 100755
index 0000000..2f3b60d
--- /dev/null
+++ b/src/pmdas/ds389/Remove
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Copyright (C) 2014 Marko Myllynen <myllynen@xxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+
+. $PCP_DIR/etc/pcp.env
+. $PCP_SHARE_DIR/lib/pmdaproc.sh
+
+iam=ds389
+
+pmdaSetup
+pmdaRemove
+exit 0
diff --git a/src/pmdas/ds389/pmdads389.pl b/src/pmdas/ds389/pmdads389.pl
new file mode 100644
index 0000000..a154094
--- /dev/null
+++ b/src/pmdas/ds389/pmdads389.pl
@@ -0,0 +1,316 @@
+#
+# Copyright (C) 2014 Marko Myllynen <myllynen@xxxxxxxxxx>
+#
+# 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; either version 2 of the License, or (at your
+# option) any later version.
+#
+# 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.
+#
+
+use strict;
+use warnings;
+use PCP::PMDA;
+use Net::LDAP;
+use POSIX;
+
+my $server = 'localhost';
+my $binddn = 'cn=Directory Manager';
+my $bindpw = 'Manager12';
+my $scope  = 'base';
+my $cnbase = 'cn=monitor';
+my $urbase = 'cn=monitor,cn=userRoot,cn=ldbm database,cn=plugins,cn=config';
+my $filter = '(objectclass=*)';
+my $query_interval = 2; # seconds
+
+use vars qw( $ldap $pmda %metrics );
+
+# Configuration files for overriding the above settings
+for my $file (pmda_config('PCP_PMDAS_DIR') . '/ds389/ds389.conf', 
'./ds389.conf') {
+       eval `cat $file` unless ! -f $file;
+}
+
+# Timestamps
+my $ts_cn = 0;
+my $ts_ur = 0;
+
+sub ds389_connection_setup {
+       if (!defined($ldap)) {
+               $ldap = Net::LDAP->new($server);
+               return if (!defined($ldap));
+               my $mesg = $ldap->bind($binddn, password => $bindpw);
+               if ($mesg->code) {
+                       $pmda->log("bind failed: " . $mesg->error);
+                       die;
+               }
+       }
+}
+
+sub ds389_time_to_epoch {
+       my ($time) = @_;
+
+       return mktime(substr($time,12,2),
+                     substr($time,10,2),
+                     substr($time,8,2),
+                     substr($time,6,2),
+                     substr($time,4,2) - 1,
+                     substr($time,0,4) - 1900);
+}
+
+sub ds389_process_entry {
+       my ($entry, $prefix, $cluster) = @_;
+       my $currtime;
+
+       foreach my $attr ($entry->attributes) {
+               my @metric;
+               my $value = $entry->get_value($attr);
+
+               if ($attr eq 'currenttime') {
+                       $currtime = ds389_time_to_epoch($value);
+                       next;
+               }
+
+               if ($attr eq 'starttime') {
+                       my $starttime = ds389_time_to_epoch($value);
+                       $value = $currtime - $starttime;
+                       $attr = 'uptime';
+               }
+
+               @metric = ('ds389.' . $prefix . $attr, $value);
+               $metrics{$metric[0]} = \@metric;
+       }
+}
+
+sub ds389_fetch {
+       if (!defined($ldap)) {
+               ds389_connection_setup();
+       }
+       return unless defined($ldap);
+
+       my ($cluster) = @_;
+       my $mesg;
+
+       if ($cluster eq 0) {
+               if ((strftime("%s", localtime()) - $ts_cn) > $query_interval) {
+                       # $pmda->log("cn search");
+                       $ts_cn = strftime("%s", localtime());
+                       $mesg = $ldap->search(scope => $scope, base => $cnbase, 
filter => $filter);
+                       if ($mesg->code) {
+                               $pmda->log("search failed: " . $mesg->error);
+                               return;
+                       }
+                       ds389_process_entry($mesg->entry, 'cn.', 0);
+               }
+       }
+
+       if ($cluster eq 1) {
+               if ((strftime("%s", localtime()) - $ts_ur) > $query_interval) {
+                       # $pmda->log("ur search");
+                       $ts_ur = strftime("%s", localtime());
+                       $mesg = $ldap->search(scope => $scope, base => $urbase, 
filter => $filter);
+                       if ($mesg->code) {
+                               $pmda->log("search failed: " . $mesg->error);
+                               return;
+                       }
+                       ds389_process_entry($mesg->entry, 'userroot.', 1);
+               }
+       }
+}
+
+sub ds389_fetch_callback {
+       my ($cluster, $item, $inst) = @_; 
+
+       if ($inst != PM_INDOM_NULL)     { return (PM_ERR_INST, 0); }
+
+       my $pmnm = pmda_pmid_name($cluster, $item);
+       my $value = $metrics{$pmnm};
+
+       if (!defined($value))           { return (PM_ERR_APPVERSION, 0); }
+
+       return ($value->[1], 1);
+}
+
+$pmda = PCP::PMDA->new('ds389', 137);
+
+# Metrics available on 389 DS 1.3.2.23
+
+# cn=monitor
+$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.threads', '', '');
+$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.currentconnections', '', '');
+$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.totalconnections', '', '');
+$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.currentconnectionsatmaxthreads', '', '');
+$pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.maxthreadsperconnhits', '', '');
+$pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.dtablesize', '', '');
+$pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.readwaiters', '', '');
+$pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.opsinitiated', '', '');
+$pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.opscompleted', '', '');
+$pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.cn.entriessent', '', '');
+$pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+               'ds389.cn.bytessent', '', '');
+$pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0),
+               'ds389.cn.uptime', '', ''); # calculated
+
+# cn=monitor,cn=userRoot,cn=ldbm database,cn=plugins,cn=config
+$pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_DISCRETE, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.readonly', '', '');
+$pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.entrycachehits', '', '');
+$pmda->add_metric(pmda_pmid(1,2), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.entrycachetries', '', '');
+$pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.entrycachehitratio', '', '');
+$pmda->add_metric(pmda_pmid(1,4), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+               'ds389.userroot.currententrycachesize', '', '');
+$pmda->add_metric(pmda_pmid(1,5), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_DISCRETE, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+               'ds389.userroot.maxentrycachesize', '', '');
+$pmda->add_metric(pmda_pmid(1,6), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.currententrycachecount', '', '');
+$pmda->add_metric(pmda_pmid(1,7), PM_TYPE_32, PM_INDOM_NULL,
+               PM_SEM_DISCRETE, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.maxentrycachecount', '', '');
+$pmda->add_metric(pmda_pmid(1,8), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.dncachehits', '', '');
+$pmda->add_metric(pmda_pmid(1,9), PM_TYPE_U64, PM_INDOM_NULL,
+               PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.dncachetries', '', '');
+$pmda->add_metric(pmda_pmid(1,10), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.dncachehitratio', '', '');
+$pmda->add_metric(pmda_pmid(1,11), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+               'ds389.userroot.currentdncachesize', '', '');
+$pmda->add_metric(pmda_pmid(1,12), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_DISCRETE, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+               'ds389.userroot.maxdncachesize', '', '');
+$pmda->add_metric(pmda_pmid(1,13), PM_TYPE_U32, PM_INDOM_NULL,
+               PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.currentdncachecount', '', '');
+$pmda->add_metric(pmda_pmid(1,14), PM_TYPE_32, PM_INDOM_NULL,
+               PM_SEM_DISCRETE, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+               'ds389.userroot.maxdncachecount', '', '');
+
+$pmda->set_refresh(\&ds389_fetch);
+$pmda->set_fetch_callback(\&ds389_fetch_callback);
+$pmda->set_user('pcp');
+$pmda->run;
+
+=pod
+
+=head1 NAME
+
+pmdads389 - 389 Directory Server PMDA
+
+=head1 DESCRIPTION
+
+B<pmdads389> is a Performance Metrics Domain Agent (PMDA) which extracts
+live performance data from a running 389 Directory Server instance.
+
+See the Red Hat Directory Server Administration Guide for description 
+for each metric.
+
+=head1 INSTALLATION
+
+B<pmdads389> uses configuration file:
+
+=over
+
+=item * $PCP_PMDAS_DIR/ds389/ds389.conf
+
+=back
+
+This file can contain overridden values (Perl code) for the settings 
+listed at the start of pmdads389.pl, namely:
+
+=over
+
+=item * LDAP server
+
+=item * bind DN
+
+=item * bind password
+
+=item * search scope
+
+=item * search base
+
+=item * search filter
+
+=item * query interval
+
+=back
+
+Once this is setup, you can access the names and values for the
+389 DS performance metrics by doing the following as root:
+
+        # cd $PCP_PMDAS_DIR/ds389
+        # ./Install
+
+If you want to undo the installation, do the following as root:
+
+        # cd $PCP_PMDAS_DIR/ds389
+        # ./Remove
+
+B<pmdads389> is launched by pmcd(1) and should never be executed
+directly.  The Install and Remove scripts notify pmcd(1) when
+the agent is installed or removed.
+
+=head1 FILES
+
+=over
+
+=item $PCP_PMDAS_DIR/ds389/ds389.conf
+
+configuration file for B<pmdads389>
+
+=item $PCP_PMDAS_DIR/ds389/Install
+
+installation script for the B<pmdads389> agent
+
+=item $PCP_PMDAS_DIR/ds389/Remove
+
+undo installation script for the B<pmdads389> agent
+
+=item $PCP_LOG_DIR/pmcd/ds389.log
+
+default log file for error messages from B<pmdads389>
+
+=back
+
+=head1 SEE ALSO
+
+ldapsearch(1), pmcd(1), ns-slapd(8).
+
-- 
1.7.1



-- 
Marko Myllynen

<Prev in Thread] Current Thread [Next in Thread>