From 08f4d259b7d9068982e15a0e99deba49654fb70d Mon Sep 17 00:00:00 2001 From: Valentin Samir Date: Tue, 2 Dec 2014 15:20:50 +0100 Subject: [PATCH] [ldapcertfs] fallback sur un cache local si des erreurs ldap surviennent --- utils/ldapcertfs.py | 89 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/utils/ldapcertfs.py b/utils/ldapcertfs.py index dc218fae..ceeade11 100755 --- a/utils/ldapcertfs.py +++ b/utils/ldapcertfs.py @@ -48,6 +48,8 @@ import ldap import time import fuse import errno +import pickle +import hashlib import getpass from OpenSSL import crypto @@ -59,12 +61,61 @@ import gestion.secrets_new as secrets fuse.fuse_python_api = (0, 2) import logging -LOG_FILENAME = 'ldapcertfs.log' -logging.basicConfig(filename=LOG_FILENAME,level=logging.WARNING) +import logging.handlers +logger = logging.getLogger('ldapcertfs') +logger.setLevel(logging.DEBUG) +formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s') +handler = logging.handlers.SysLogHandler(address = '/dev/log') +try: + handler.addFormatter(formatter) +except AttributeError: + handler.formatter = formatter +logger.addHandler(handler) CACHE = {} CACHE_TIMEOUT = 60 +CACHE_DIR = "/var/lib/ldapcertfs/" +CACHE_STATIC_UPDATE = 3600 +CACHE_STATIC_EXPIRE = 3600 * 24 * 30 +LAST_CLEAN = 0 + +try: + os.mkdir(CACHE_DIR, 0700) +except OSError as e: + if e.errno != 17: # File exists + raise + os.chmod(CACHE_DIR, 0700) + +def clean_static_cache(storage={}): + global LAST_CLEAN + if time.time() - LAST_CLEAN > CACHE_STATIC_UPDATE: + LAST_CLEAN = time.time() + for file in os.listdir(CACHE_DIR): + path = os.path.join(CACHE_DIR, file) + if time.time() - os.path.getmtime(path) > CACHE_STATIC_EXPIRE and not path in storage: + os.remove(path) + +clean_static_cache() + +def get_from_static_cache(key): + path = os.path.join(CACHE_DIR, hashlib.md5(key).hexdigest()) + if os.path.isfile(path): + with open(path) as f: + return (os.path.getmtime(path), pickle.load(f)) + else: + raise ValueError("Not Found") + +def set_to_static_cache(key, value): + try: + (mtime, old_value) = get_from_static_cache(key) + except ValueError: + old_value = None + if old_value != value: + path = os.path.join(CACHE_DIR, hashlib.md5(key).hexdigest()) + with open(path, 'w+') as f: + pickle.dump(value, f) + os.chmod(path, 0600) def set_to_cache(keys, value, now=None, null=False): global CACHE @@ -116,6 +167,21 @@ class Item(object): else: self.data = '' + def __eq__(self, obj): + if isinstance(obj, Item): + return self.dev == obj.dev and \ + self.mode == obj.mode and \ + self.uid == obj.uid and \ + self.gid == obj.gid and \ + self.xattr == obj.xattr and \ + self.data == obj.data and \ + abs(self.mtime - obj.mtime) < CACHE_STATIC_UPDATE + else: + return False + + def __ne__(self, obj): + return not self == obj + def read(self, offset, length): return self.data[offset:offset+length] @@ -189,16 +255,16 @@ class LdapCertFS(fuse.Fuse): try: self.conn = lc_ldap.shortcuts.lc_ldap_readonly() if not rec: - logger.warning("[ldapcertfs] ldap down, retrying") + logger.warning("ldap down, retrying") kwargs['rec'] = True self.func_cache(func, *args, **kwargs) except Exception as e: - logger.error("[ldapcertfs] uncaught exception %r" % e) + logger.error("uncaught exception %r" % e) # Si le serveur est down on essaye de fournir un ancienne valeur du cache try: return get_from_cache(serial, expire=-1) except ValueError: - logger.critical("[ldapcertfs] fail to return a valid result, I will probably crash next to this") + logger.critical("fail to return a valid result, I will probably crash next to this") return [] def search_cache(self, filter, **kwargs): @@ -358,9 +424,20 @@ class LdapCertFS(fuse.Fuse): elif machine_host and xid and file: self.make_file(xid, file) set_to_cache(path, True) + set_to_static_cache(path, self._storage[path]) # --- Metadata ----------------------------------------------------------- def getattr(self, path): - self.build_path(path) + try: + self.build_path(path) + clean_static_cache(self._storage) + except Exception as e: + logger.warning("Erreur : %s\n%s" % (e, traceback.format_exc())) + if not path in self._storage: + try: + (ts, v) = get_from_static_cache(path) + self._storage[path] = v + except ValueError: + pass if not path in self._storage: return -errno.ENOENT