Skip to content

Commit

Permalink
openldap monitoring plugin added (netdata#4513)
Browse files Browse the repository at this point in the history
* openldap monitoring plugin added

* fixed identation, added makefile link

* removed trailing whitespaces

* style fixes

* removed some more trailnf spaces

* refactored conn method, formatting suggestions, simpler config

* format suggestions, added connect-reconnect methods and alive flag

* removed trailing whitespaces

* trailing spaces

* connection manipulation and cosmetics

* charts names units and titles

* added connection timeout

* timout option moved

* removed disable by default

* timeout default value

* default vars and cofig comments added

* user pass commented and enabled plugin by default

* python.d disabled openldap

* error handling, allow anonymous bind

* ldap exception

* anonymous bind refactoring

* none as default removed from username password
  • Loading branch information
ekartsonakis authored and ilyam8 committed Nov 15, 2018
1 parent 3ab78aa commit c23aed3
Show file tree
Hide file tree
Showing 6 changed files with 351 additions and 1 deletion.
1 change: 1 addition & 0 deletions collectors/python.d.plugin/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ include nvidia_smi/Makefile.inc
include nsd/Makefile.inc
include ntpd/Makefile.inc
include ovpn_status_log/Makefile.inc
include openldap/Makefile.inc
include phpfpm/Makefile.inc
include portcheck/Makefile.inc
include postfix/Makefile.inc
Expand Down
13 changes: 13 additions & 0 deletions collectors/python.d.plugin/openldap/Makefile.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-3.0-or-later

# THIS IS NOT A COMPLETE Makefile
# IT IS INCLUDED BY ITS PARENT'S Makefile.am
# IT IS REQUIRED TO REFERENCE ALL FILES RELATIVE TO THE PARENT

# install these files
dist_python_DATA += openldap/openldap.chart.py
dist_pythonconfig_DATA += openldap/openldap.conf

# do not install these files, but include them in the distribution
dist_noinst_DATA += openldap/README.md openldap/Makefile.inc

57 changes: 57 additions & 0 deletions collectors/python.d.plugin/openldap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# openldap

This module provides statistics information from openldap (slapd) server.
Statistics are taken from LDAP monitoring interface. Manual page, slapd-monitor(5) is available.

**Requirement:**
* Follow instructions from https://www.openldap.org/doc/admin24/monitoringslapd.html to activate monitoring interface.
* Install python ldap module `pip install ldap` or `yum install python-ldap`
* Modify openldap.conf with your credentials

### Module gives information with following charts:

1. **connections**
* total connections number

2. **Bytes**
* sent

3. **operations**
* completed
* initiated

4. **referrals**
* sent

5. **entries**
* sent

6. **ldap operations**
* bind
* search
* unbind
* add
* delete
* modify
* compare

7. **waiters**
* read
* write



### configuration

Sample:

```yaml
openldap:
name : 'local'
username : "cn=monitor,dc=superb,dc=eu"
password : "testpass"
server : 'localhost'
port : 389
```
---
204 changes: 204 additions & 0 deletions collectors/python.d.plugin/openldap/openldap.chart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# -*- coding: utf-8 -*-
# Description: openldap netdata python.d module
# Author: Manolis Kartsonakis (ekartsonakis)
# SPDX-License-Identifier: GPL-3.0+

try:
import ldap
HAS_LDAP = True
except ImportError:
HAS_LDAP = False

from bases.FrameworkServices.SimpleService import SimpleService

# default module values (can be overridden per job in `config`)
priority = 60000

DEFAULT_SERVER = 'localhost'
DEFAULT_PORT = '389'
DEFAULT_TIMEOUT = 1

ORDER = [
'total_connections',
'bytes_sent',
'operations',
'referrals_sent',
'entries_sent',
'ldap_operations',
'waiters'
]

CHARTS = {
'total_connections': {
'options': [None, 'Total Connections', 'connections/s', 'ldap', 'openldap.total_connections', 'line'],
'lines': [
['total_connections', 'connections', 'incremental']
]
},
'bytes_sent': {
'options': [None, 'Traffic', 'KB/s', 'ldap', 'openldap.traffic_stats', 'line'],
'lines': [
['bytes_sent', 'sent', 'incremental', 1, 1024]
]
},
'operations': {
'options': [None, 'Operations Status', 'ops/s', 'ldap', 'openldap.operations_status', 'line'],
'lines': [
['completed_operations', 'completed', 'incremental'],
['initiated_operations', 'initiated', 'incremental']
]
},
'referrals_sent': {
'options': [None, 'Referrals', 'referals/s', 'ldap', 'openldap.referrals', 'line'],
'lines': [
['referrals_sent', 'sent', 'incremental']
]
},
'entries_sent': {
'options': [None, 'Entries', 'entries/s', 'ldap', 'openldap.entries', 'line'],
'lines': [
['entries_sent', 'sent', 'incremental']
]
},
'ldap_operations': {
'options': [None, 'Operations', 'ops/s', 'ldap', 'openldap.ldap_operations', 'line'],
'lines': [
['bind_operations', 'bind', 'incremental'],
['search_operations', 'search', 'incremental'],
['unbind_operations', 'unbind', 'incremental'],
['add_operations', 'add', 'incremental'],
['delete_operations', 'delete', 'incremental'],
['modify_operations', 'modify', 'incremental'],
['compare_operations', 'compare', 'incremental']
]
},
'waiters': {
'options': [None, 'Waiters', 'waiters/s', 'ldap', 'openldap.waiters', 'line'],
'lines': [
['write_waiters', 'write', 'incremental'],
['read_waiters', 'read', 'incremental']
]
},
}

# Stuff to gather - make tuples of DN dn and attrib to get
SEARCH_LIST = {
'total_connections': (
'cn=Total,cn=Connections,cn=Monitor', 'monitorCounter',
),
'bytes_sent': (
'cn=Bytes,cn=Statistics,cn=Monitor', 'monitorCounter',
),
'completed_operations': (
'cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'initiated_operations': (
'cn=Operations,cn=Monitor', 'monitorOpInitiated',
),
'referrals_sent': (
'cn=Referrals,cn=Statistics,cn=Monitor', 'monitorCounter',
),
'entries_sent': (
'cn=Entries,cn=Statistics,cn=Monitor', 'monitorCounter',
),
'bind_operations': (
'cn=Bind,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'unbind_operations': (
'cn=Unbind,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'add_operations': (
'cn=Add,cn=Operations,cn=Monitor', 'monitorOpInitiated',
),
'delete_operations': (
'cn=Delete,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'modify_operations': (
'cn=Modify,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'compare_operations': (
'cn=Compare,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'search_operations': (
'cn=Search,cn=Operations,cn=Monitor', 'monitorOpCompleted',
),
'write_waiters': (
'cn=Write,cn=Waiters,cn=Monitor', 'monitorCounter',
),
'read_waiters': (
'cn=Read,cn=Waiters,cn=Monitor', 'monitorCounter',
),
}


class Service(SimpleService):
def __init__(self, configuration=None, name=None):
SimpleService.__init__(self, configuration=configuration, name=name)
self.order = ORDER
self.definitions = CHARTS

self.server = configuration.get('server', DEFAULT_SERVER)
self.port = configuration.get('port', DEFAULT_PORT)
self.username = configuration.get('username')
self.password = configuration.get('password')
self.timeout = configuration.get('timeout', DEFAULT_TIMEOUT)

self.alive = False
self.conn = None

def disconnect(self):
if self.conn:
self.conn.unbind()
self.conn = None
self.alive = False

def connect(self):
try:
self.conn = ldap.initialize('ldap://%s:%s' % (self.server, self.port))
self.conn.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
if self.username and self.password:
self.conn.simple_bind(self.username, self.password)
except ldap.LDAPError as error:
self.error(error)
return False

self.alive = True
return True

def reconnect(self):
self.disconnect()
return self.connect()

def check(self):
if not HAS_LDAP:
self.error("'python-ldap' package is needed")
return None

return self.connect() and self.get_data()

def get_data(self):
if not self.alive and not self.reconnect():
return None

data = dict()
for key in SEARCH_LIST:
dn = SEARCH_LIST[key][0]
attr = SEARCH_LIST[key][1]
try:
num = self.conn.search(dn, ldap.SCOPE_BASE, 'objectClass=*', [attr, ])
result_type, result_data = self.conn.result(num, 1)
except ldap.LDAPError as error:
self.error("Empty result. Check bind username/password. Message: ",error)
self.alive = False
return None

try:
if result_type == 101:
val = int(result_data[0][1].values()[0][0])
except (ValueError, IndexError) as error:
self.debug(error)
continue

data[key] = val

return data
74 changes: 74 additions & 0 deletions collectors/python.d.plugin/openldap/openldap.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# netdata python.d.plugin configuration for openldap
#
# This file is in YaML format. Generally the format is:
#
# name: value
#
# There are 2 sections:
# - global variables
# - one or more JOBS
#
# JOBS allow you to collect values from multiple sources.
# Each source will have its own set of charts.
#
# JOB parameters have to be indented (using spaces only, example below).

# ----------------------------------------------------------------------
# Global Variables
# These variables set the defaults for all JOBs, however each JOB
# may define its own, overriding the defaults.

# update_every sets the default data collection frequency.
# If unset, the python.d.plugin default is used.
# postfix is slow, so once every 10 seconds
update_every: 10

# priority controls the order of charts at the netdata dashboard.
# Lower numbers move the charts towards the top of the page.
# If unset, the default for python.d.plugin is used.
# priority: 60000

# retries sets the number of retries to be made in case of failures.
# If unset, the default for python.d.plugin is used.
# Attempts to restore the service are made once every update_every
# and only if the module has collected values in the past.
# retries: 60

# autodetection_retry sets the job re-check interval in seconds.
# The job is not deleted if check fails.
# Attempts to start the job are made once every autodetection_retry.
# This feature is disabled by default.
# autodetection_retry: 0

# ----------------------------------------------------------------------
# JOBS (data collection sources)
#
# The default JOBS share the same *name*. JOBS with the same name
# are mutually exclusive. Only one of them will be allowed running at
# any time. This allows autodetection to try several alternatives and
# pick the one that works.
#
# Any number of jobs is supported.
#
# All python.d.plugin JOBS (for all its modules) support a set of
# predefined parameters. These are:
#
# job_name:
# name: myname # the JOB's name as it will appear at the
# # dashboard (by default is the job_name)
# # JOBs sharing a name are mutually exclusive
# update_every: 1 # the JOB's data collection frequency
# priority: 60000 # the JOB's order on the dashboard
# retries: 60 # the JOB's number of restoration attempts
# autodetection_retry: 0 # the JOB's re-check interval in seconds
#
# ----------------------------------------------------------------------
# OPENLDAP EXTRA PARAMETERS

# Set here your LDAP connection settings

#username : "cn=admin,dc=example,dc=com" # The bind user with right to access monitor statistics
#password : "yourpass" # The password for the binded user
#server : 'localhost' # The listening address of the LDAP server
#port : 389 # The listening port of the LDAP server
#timeout : 1 # Seconds to timeout if no connection exists
3 changes: 2 additions & 1 deletion collectors/python.d.plugin/python.d.conf
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ logind: no
nginx_log: no
# nsd: yes
# ntpd: yes
# openldap: yes
# ovpn_status_log: yes
# phpfpm: yes
# postfix: yes
Expand All @@ -96,4 +97,4 @@ unbound: no
# uwsgi: yes
# varnish: yes
# w1sensor: yes
# web_log: yes
# web_log: yes

0 comments on commit c23aed3

Please sign in to comment.