[ldap_locks] Renommage des erreurs ldap en erreur de Lock, factorisation, reformatage

This commit is contained in:
Valentin Samir 2014-02-24 21:31:16 +01:00
parent 320300d85c
commit 4f88ae824a

View file

@ -53,6 +53,12 @@ class LdapLockedByYou(LockError):
"""
pass
class LdapLockedByMySelf(LockError):
"""
Classe d'erreur pour les locks par l'idlock courant
"""
pass
class LdapLockedByOther(LockError):
"""
Erreur car le lock est occupé par un autre process.
@ -65,6 +71,9 @@ class LockFormatError(LockError):
"""
pass
class LockNotFound(LockError):
"""Le lock n'a pas été trouvé"""
LOCKS_DN = 'ou=lock,dc=crans,dc=org'
class LdapLockHolder:
@ -75,36 +84,38 @@ class LdapLockHolder:
"""
On crée la connexion, et on crée un dico vide.
"""
self.locks = collections.defaultdict(dict, {})
# On crée un Id => (item => set())
self.locks = collections.defaultdict(lambda:collections.defaultdict(set))
self.host = socket.gethostname()
self.pid = os.getpid()
self.conn = conn
self.time = 600.0
self.timeout = 600.0
def purge(self, Id=None):
def newid(self):
id = 'id_%s' % time.time()
if id in self.locks:
return self.newid()
else:
return id
def purge(self, Id, purgeAll=False):
"""
On essaye de détruire tous les verrous hébergés par
l'objet.
"""
if Id == None:
for key, subdict in self.locks['default'].items():
for item, value in subdict.items():
try:
self.removelock(item, value, key)
except:
pass
else:
for item, value in self.locks[Id].items():
try:
if not purgeAll:
for item, values in self.locks[Id].items():
for value in values.copy():
self.removelock(item, value, Id)
except:
pass
else:
for Id in self.locks:
self.purge(Id)
def __del__(self):
"""
En cas de destruction du lockholder
"""
self.purge()
self.purge(purgeAll=True)
def addlock(self, item, value, Id='default'):
"""
@ -119,27 +130,23 @@ class LdapLockHolder:
"""
try:
host, pid, begin = self.getlock(item, value)
if time.time() - begin >= self.time:
time_left = self.timeout - (time.time() - begin)
if time_left <= 0:
self.removelock(item, value, Id, True)
elif Id!='default' and str(value) in self.locks[Id][item]:
raise LdapLockedByMySelf("La donnée %r=%r est lockée par vous-même pour encore %ds." % (item, value, time_left))
elif host == self.host and pid == self.pid:
time_left = self.time - (time.time() - begin)
raise LdapLockedByYou("La donnée %r=%r est lockée par vous-même pour encore %ds." % (item, value, time_left))
elif host == self.host:
status = crans_utils.process_status(pid)
if status:
time_left = self.time - (time.time() - begin)
raise LdapLockedByOther("La donnée %r=%r est lockée par un processus actif pour encore %ds." % (item, value, time_left))
else:
self.removelock(item, value, Id, True)
else:
time_left = self.time - (time.time() - begin)
raise LdapLockedByOther("La donnée %r=%r est lockée depuis une autre machine pour encore %ds." % (item, value, time_left))
except ldap.NO_SUCH_OBJECT:
except LockNotFound:
pass
except LockFormatError:
self.removelock(item, value, Id)
except Exception:
raise
dn = "%s=%s,%s" % (item, value, LOCKS_DN)
lockid = "%s-%s-%s" % (self.host, self.pid, time.time())
@ -151,36 +158,28 @@ class LdapLockHolder:
try:
self.conn.add_s(dn, modlist)
self.locks[Id][item] = value
self.locks[Id][item].add(str(value))
except ldap.ALREADY_EXISTS:
status = crans_utils.process_status(pid)
if status:
raise LdapLockedByOther("La donnée %r=%r est lockée par un processus actif." % (item, value))
else:
self.removelock(item, value, Id)
try:
self.conn.add_s(dn, modlist)
# Si on a un pointeur vers l'id de l'objet, on en tient compte
self.locks[Id][item] = value
except:
raise StandardError("Quelque chose a planté durant la pose du lock %s=%s" % (item, value))
# Quelqu'un à eu le lock avant nous, on réessaye
# S'il a été libéré, banzai, sinon, ça lèvera une exception
return self.addlock(item, value, Id)
def removelock(self, item, value, Id='default', force=False):
"""
Libère le lock "$item=$value,$LOCKS_DN".
"""
if not force:
if self.locks[Id].get(item, "") == str(value):
_ = self.locks[Id].pop(item)
self.conn.delete_s("%s=%s,%s" % (item, value, LOCKS_DN))
else:
pass
else:
try:
if force or str(value) in self.locks[Id][item]:
self.conn.delete_s("%s=%s,%s" % (item, value, LOCKS_DN))
except:
except ldap.NO_SUCH_OBJECT:
pass
finally:
try:
self.locks[Id][item].remove(value)
except KeyError:
pass
if not self.locks[Id][item]:
self.locks[Id].pop(item)
def getlock(self, item, value):
"""
@ -188,13 +187,12 @@ class LdapLockHolder:
via un triplet host, pid, begin
"""
try:
result = self.conn.search_s('%s=%s,%s' % (item, value, LOCKS_DN), 0)
try:
try:
host, pid, begin = result[0][1]['lockid'][0].split('-')
except:
host, pid = result[0][1]['lockid'][0].split('-')
begin = time.time()
return host, int(pid), float(begin)
except:
raise LockFormatError
except ldap.NO_SUCH_OBJECT:
raise LockNotFound()
except ValueError as e:
self.removelock(item, value, Id, force=True)
raise LockNotFound()