[ldapcertfs] fallback sur un cache local si des erreurs ldap surviennent

This commit is contained in:
Valentin Samir 2014-12-02 15:20:50 +01:00
parent b209f8f4f0
commit 08f4d259b7

View file

@ -48,6 +48,8 @@ import ldap
import time import time
import fuse import fuse
import errno import errno
import pickle
import hashlib
import getpass import getpass
from OpenSSL import crypto from OpenSSL import crypto
@ -59,12 +61,61 @@ import gestion.secrets_new as secrets
fuse.fuse_python_api = (0, 2) fuse.fuse_python_api = (0, 2)
import logging import logging
LOG_FILENAME = 'ldapcertfs.log' import logging.handlers
logging.basicConfig(filename=LOG_FILENAME,level=logging.WARNING) 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 = {}
CACHE_TIMEOUT = 60 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): def set_to_cache(keys, value, now=None, null=False):
global CACHE global CACHE
@ -116,6 +167,21 @@ class Item(object):
else: else:
self.data = '' 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): def read(self, offset, length):
return self.data[offset:offset+length] return self.data[offset:offset+length]
@ -189,16 +255,16 @@ class LdapCertFS(fuse.Fuse):
try: try:
self.conn = lc_ldap.shortcuts.lc_ldap_readonly() self.conn = lc_ldap.shortcuts.lc_ldap_readonly()
if not rec: if not rec:
logger.warning("[ldapcertfs] ldap down, retrying") logger.warning("ldap down, retrying")
kwargs['rec'] = True kwargs['rec'] = True
self.func_cache(func, *args, **kwargs) self.func_cache(func, *args, **kwargs)
except Exception as e: 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 # Si le serveur est down on essaye de fournir un ancienne valeur du cache
try: try:
return get_from_cache(serial, expire=-1) return get_from_cache(serial, expire=-1)
except ValueError: 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 [] return []
def search_cache(self, filter, **kwargs): def search_cache(self, filter, **kwargs):
@ -358,9 +424,20 @@ class LdapCertFS(fuse.Fuse):
elif machine_host and xid and file: elif machine_host and xid and file:
self.make_file(xid, file) self.make_file(xid, file)
set_to_cache(path, True) set_to_cache(path, True)
set_to_static_cache(path, self._storage[path])
# --- Metadata ----------------------------------------------------------- # --- Metadata -----------------------------------------------------------
def getattr(self, path): def getattr(self, path):
try:
self.build_path(path) 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: if not path in self._storage:
return -errno.ENOENT return -errno.ENOENT