From 0b50c9f4873148c441403bf09d9458ba22473876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20M=C3=A4der?= <maeder@phys.ethz.ch> Date: Wed, 11 Apr 2018 00:43:46 +0200 Subject: [PATCH] Add slapd to lib, add logging --- bin/deltalogparse.py | 70 +++++++++++++++++--------------------------- lib/isg/dphysldap.py | 48 ++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 43 deletions(-) diff --git a/bin/deltalogparse.py b/bin/deltalogparse.py index d4bdab8..5f4e678 100755 --- a/bin/deltalogparse.py +++ b/bin/deltalogparse.py @@ -5,18 +5,25 @@ import time import datetime import re import pprint +import logging import lib_path import lib -import ldap3 +import dphysldap +process_name = 'deltalogparse' debug = 2 +loglevel = logging.DEBUG update_every = 1 log_path = '/var/log/ldap/delta.log' search_base = 'cn=deltalog' -search_filter = '(|(objectClass=auditModify)(objectClass=auditAdd)(objectClass=auditDelete))' -search_scope = ldap3.SUBTREE -attributes = [ldap3.ALL_ATTRIBUTES, ldap3.ALL_OPERATIONAL_ATTRIBUTES] +object_classes = '(|(objectClass=auditModify)(objectClass=auditAdd)(objectClass=auditDelete))' +logging.basicConfig( + filename='/var/log/ldap/deltalogparse.log', + level=loglevel, + format='%(asctime)s ' + process_name + '[%(process)d]:%(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) rgx_skip = re.compile( r'^(' @@ -40,8 +47,7 @@ rgx_filter = re.compile( def is_skipped(attributes): for attribute in attributes: if not rgx_skip.search(attribute): - if debug > 0: - print('hmm... interesting attribute: %s' % attribute) + logging.info('hmm... interesting attribute: %s' % attribute) return False return True @@ -55,11 +61,8 @@ def log(entry): entry['attributes'] = attributes del entry['raw_attributes'] - if debug > 1: - pprint.pprint(entry, indent=4) - - if debug > 0: - print('log: %s %s' % (req_type, req_dn)) + logging.debug(pprint.pformat(entry, indent=4)) + logging.info('log: %s %s' % (req_type, req_dn)) def sleep(start_time): @@ -67,8 +70,7 @@ def sleep(start_time): elapsed_time = current_time - start_time sleep_time = update_every - elapsed_time - if debug > 0: - print('\nruntime %0.3fs, sleeping %0.3fs' % (elapsed_time, sleep_time)) + logging.info('runtime %0.3fs, sleeping %0.3fs' % (elapsed_time, sleep_time)) if sleep_time > 0: time.sleep(sleep_time) @@ -76,40 +78,24 @@ def sleep(start_time): def main(): """Connect to slapd socket and parse accesslog""" - server = ldap3.Server( - 'ldapi:///var/run/slapd/ldapi', - get_info=[ - ldap3.ALL, - ldap3.OFFLINE_SLAPD_2_4 - ] - ) - - connection = ldap3.Connection( - server, - authentication=ldap3.SASL, - sasl_mechanism=ldap3.EXTERNAL, - sasl_credentials='', - auto_bind='NONE', - version=3, - client_strategy='SYNC' - ) - - connection.bind() + slapd = dphysldap.Slapd() req_start = datetime.datetime.utcnow().strftime('%Y%m%d%H%M%S.%fZ') while True: start_time = time.perf_counter() - response = connection.search( - search_base=search_base, - search_filter=''.join(['(&', search_filter, '(reqStart>=', req_start, ')',')']), - search_scope=search_scope, - attributes=attributes - ) + search_filter=''.join(['(&', object_classes, '(reqStart>=', req_start, ')',')']) + + try: + response = slapd.search(search_base, search_filter) + except: + logging.error('socket error!') + if slapd.reconnect(): + logging.error('socket reconnected.') if response: - for entry in connection.response: + for entry in slapd.response(): if entry['attributes']['reqStart'][0] == req_start: continue @@ -117,14 +103,12 @@ def main(): req_type = entry['attributes']['reqType'][0] req_dn = entry['attributes']['reqDN'][0] - if debug > 0: - print(' '.join(['\nprocessing:', req_start, entry['dn']])) + logging.info(' '.join(['processing:', req_start, entry['dn']])) if req_type == 'modify': req_mods = entry['attributes']['reqMod'] if is_skipped(req_mods): - if debug > 0: - print('skip: %s %s' % (req_type, req_dn)) + logging.info('skip: %s %s' % (req_type, req_dn)) continue log(entry) diff --git a/lib/isg/dphysldap.py b/lib/isg/dphysldap.py index 171b160..123a5b9 100644 --- a/lib/isg/dphysldap.py +++ b/lib/isg/dphysldap.py @@ -2,6 +2,7 @@ import ssl import collections +import time import lib_path import lib import ldap3 @@ -11,6 +12,10 @@ FMT = 'simple' SERVERS = ['phd-aa1.ethz.ch', 'phd-aa2.ethz.ch', 'phd-aa3.ethz.ch'] BASE = 'dc=phys,dc=ethz,dc=ch' CA_CERTS = '/etc/ssl/certs/ca-certificates.crt' +SLAPD_SOCKET = 'ldapi:///var/run/slapd/ldapi' +SLAPD_INFO = [ldap3.ALL, ldap3.OFFLINE_SLAPD_2_4] +SLAPD_SEARCH_SCOPE = ldap3.SUBTREE +SLAPD_SEARCH_ATTRS = [ldap3.ALL_ATTRIBUTES, ldap3.ALL_OPERATIONAL_ATTRIBUTES] class AttributeValue(list): @@ -85,6 +90,49 @@ class User(Entry): Entry.__init__(self, *args, **kwargs) +class Slapd(object): + """ + SLAPD connection to socket + """ + def __init__(self, socket=SLAPD_SOCKET, get_info=SLAPD_INFO): + self.server = ldap3.Server(socket, get_info=get_info) + self.connect() + + def connect(self): + self.connection = ldap3.Connection( + self.server, + authentication=ldap3.SASL, + sasl_mechanism=ldap3.EXTERNAL, + sasl_credentials='', + auto_bind='NONE', + version=3, + client_strategy='SYNC' + ) + self.connection.bind() + + def search(self, search_base, search_filter, search_scope=SLAPD_SEARCH_SCOPE, + attributes=SLAPD_SEARCH_ATTRS): + response = self.connection.search(search_base, search_filter, + search_scope=search_scope, + attributes=attributes) + return response + + def response(self): + return self.connection.response + + def reconnect(self, interval=1, retries=0): + forever = True if not retries else False + + while forever or retries > 0: + try: + self.connect() + return True + except ldap3.core.exceptions.LDAPSocketOpenError: + retries -= 1 + time.sleep(interval) + + return False + class Ldap(object): """ LDAP connection to random server in pool -- GitLab