From a9ed9d23832d0516eefcf105713c42e3ae812a63 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sven=20M=C3=A4der?= <maeder@phys.ethz.ch>
Date: Thu, 12 Apr 2018 11:40:38 +0200
Subject: [PATCH] Add locking mechanism

---
 bin/deltalogparse.py | 80 +++++++++++++++++++++++++++++++-------------
 1 file changed, 56 insertions(+), 24 deletions(-)

diff --git a/bin/deltalogparse.py b/bin/deltalogparse.py
index 155e758..9abff03 100755
--- a/bin/deltalogparse.py
+++ b/bin/deltalogparse.py
@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 
 import sys
+import fcntl
 import time
 import datetime
 import re
@@ -13,32 +14,22 @@ import lib_path
 import lib
 import dphysldap
 
-update_every = 1
-#log_level = logging.WARNING
+# log levels: CRITICAL | ERROR | WARNING | INFO | DEBUG | NOTSET
+# default:    WARNING
 log_level = logging.INFO
-#log_level = logging.DEBUG
-log_datefmt = '%Y-%m-%d %H:%M:%S'
+
+script_name = 'deltalogparse'
+deltalog_name = 'delta'
 log_path = '/var/log/ldap/'
-log_file_log = log_path + 'logparse.log'
-log_file_deltalog = log_path + 'delta.log'
+update_every = 1
+lock_file = '/var/run/' + script_name + '.lock'
+log_datefmt = '%Y-%m-%d %H:%M:%S'
+log_file_log = log_path + script_name + '.log'
+log_file_deltalog = log_path + deltalog_name + '.log'
 search_base = 'cn=deltalog'
 object_classes = '(|(objectClass=auditModify)(objectClass=auditAdd)(objectClass=auditDelete)(objectClass=auditModRDN))'
-
-log = logging.getLogger('log')
-log.setLevel(log_level)
-log_fh = logging.FileHandler(log_file_log)
-log_fh.setLevel(log_level)
-log_formatter = logging.Formatter(fmt='{asctime} {levelname}: {message}', style='{', datefmt=log_datefmt)
-log_fh.setFormatter(log_formatter)
-log.addHandler(log_fh)
-
-deltalog = logging.getLogger('deltalog')
-deltalog.setLevel(logging.INFO)
-deltalog_fh = logging.FileHandler(log_file_deltalog)
-deltalog_fh.setLevel(logging.INFO)
-deltalog_formatter = logging.Formatter(fmt='{asctime}: {message}', style='{', datefmt=log_datefmt)
-deltalog_fh.setFormatter(deltalog_formatter)
-deltalog.addHandler(deltalog_fh)
+log = None
+deltalog = None
 
 rgx_skip = re.compile(
     r'^('
@@ -65,6 +56,41 @@ rgx_redacted = re.compile(
 
 rgx_attr_key = re.compile(r'^(?P<key>.*?)(?P<delimiter>:[=+-:]? ?)')
 
+
+def lock(lock_file):
+    flock = open(lock_file, 'w')
+
+    try:
+        fcntl.lockf(flock, fcntl.LOCK_EX | fcntl.LOCK_NB)
+        return flock
+    except (IOError, OSError):
+        print('error: another instance is running')
+        sys.exit(1)
+
+
+def unlock(lock):
+    fcntl.flock(lock, fcntl.LOCK_UN)
+
+
+def init_log():
+    global log, deltalog
+    log = logging.getLogger('log')
+    log.setLevel(log_level)
+    log_fh = logging.FileHandler(log_file_log)
+    log_fh.setLevel(log_level)
+    log_formatter = logging.Formatter(fmt='{asctime} {levelname}: {message}', style='{', datefmt=log_datefmt)
+    log_fh.setFormatter(log_formatter)
+    log.addHandler(log_fh)
+    
+    deltalog = logging.getLogger('deltalog')
+    deltalog.setLevel(logging.INFO)
+    deltalog_fh = logging.FileHandler(log_file_deltalog)
+    deltalog_fh.setLevel(logging.INFO)
+    deltalog_formatter = logging.Formatter(fmt='{asctime}: {message}', style='{', datefmt=log_datefmt)
+    deltalog_fh.setFormatter(deltalog_formatter)
+    deltalog.addHandler(deltalog_fh)
+
+
 def getlastline(fname):
     """Using mmap to return a copy of the last line of a file"""
     with open(fname) as source:
@@ -79,7 +105,7 @@ def is_skipped(entry):
             if not rgx_skip.search(attribute):
                 log.info('interesting attribute: {}'.format(attribute))
                 return False
-        except TypeError:
+        except:
             log.debug('caught exception: while checking skipped, assume interesting attribute: {}'.format(attribute))
             return False
 
@@ -160,7 +186,7 @@ def filtered(entry):
                         log.error('bytes attribute, using full base64 encoding: {}'.format(encoded_base64))
                         entry['attributes']['reqMod'][index] = encoded_base64
 
-            except TypeError:
+            except:
                 log.exception('error: caught exception: while filtering attribute: {}'.format(attribute))
 
     del entry['raw_dn']
@@ -217,6 +243,10 @@ def sleep(start_time):
 
 def main():
     """Connect to slapd socket, search accesslog, write interesting changes"""
+    flock = lock(lock_file)
+
+    init_log()
+
     slapd = dphysldap.Slapd()
     try:
         slapd.connect()
@@ -274,6 +304,8 @@ def main():
 
         sleep(start_time)
 
+    unlock(flock)
+
 
 if __name__ == '__main__':
     main()
-- 
GitLab