mirror of
https://github.com/netdata/netdata.git
synced 2025-04-23 04:50:22 +00:00

* Added TLS connection support for openldap collector * More readable name for tls variable
209 lines
6.6 KiB
Python
209 lines
6.6 KiB
Python
# -*- 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_SERVER = 'localhost'
|
|
DEFAULT_PORT = '389'
|
|
DEFAULT_TLS = False
|
|
DEFAULT_CERT_CHECK = True
|
|
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', 'KiB/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.use_tls = configuration.get('use_tls', DEFAULT_TLS)
|
|
self.cert_check = configuration.get('cert_check', DEFAULT_CERT_CHECK)
|
|
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:
|
|
if self.use_tls:
|
|
self.conn = ldap.initialize('ldaps://%s:%s' % (self.server, self.port))
|
|
else:
|
|
self.conn = ldap.initialize('ldap://%s:%s' % (self.server, self.port))
|
|
self.conn.set_option(ldap.OPT_NETWORK_TIMEOUT, self.timeout)
|
|
if self.use_tls and not self.cert_check:
|
|
self.conn.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
|
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
|