[lc_ldap] plus de propreté
This commit is contained in:
parent
c5ece03aa5
commit
a57f02d0b2
2 changed files with 279 additions and 200 deletions
144
ldap_locks.py
Normal file
144
ldap_locks.py
Normal file
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# LDAP_LOCKS.PY-- Locks for lc_ldap
|
||||
#
|
||||
## Copyright (C) 2010 Cr@ns <roots@crans.org>
|
||||
# Author: Antoine Durand-Gasselin <adg@crans.org>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the Cr@ns nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT
|
||||
# HOLDER> BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import ldap, os
|
||||
|
||||
base_lock = 'ou=lock,dc=crans,dc=org'
|
||||
|
||||
class CransLock:
|
||||
|
||||
def __init__(self, conn):
|
||||
self.conn = conn
|
||||
self.locks = {}
|
||||
self._active = []
|
||||
|
||||
def __enter__(self):
|
||||
self.lock()
|
||||
|
||||
def __exit__(self, *args):
|
||||
# XXX - connecter correctement les tracebacks.
|
||||
print "exiting with exception", args
|
||||
self.release()
|
||||
return True
|
||||
|
||||
def add(self, item, valeur):
|
||||
'''rajoute un lock, après avoir vérifié qu'il peut être posé'''
|
||||
try:
|
||||
locked = self._islocked(item, valeur)
|
||||
if locked:
|
||||
raise EnvironmentError(u'Object déjà locké', locked)
|
||||
except ldap.NO_SUCH_OBJECT:
|
||||
pass
|
||||
|
||||
locked_values = self.locks.get(item, [])
|
||||
if valeur not in locked_values:
|
||||
locked_values.append(valeur)
|
||||
self.locks[item] = locked_values
|
||||
|
||||
def remove(self, item, valeur):
|
||||
'''Enlève un lock'''
|
||||
self.locks[item].remove(valeur)
|
||||
|
||||
def lock(self):
|
||||
'''Essaie de prendre tous les verrous'''
|
||||
items = self.locks.items()
|
||||
items.sort()
|
||||
try:
|
||||
for item, valeurs in items:
|
||||
for valeur in valeurs:
|
||||
self._lockitem(item, valeur)
|
||||
except Exception, e:
|
||||
# XXX - connecter proprement les traceback
|
||||
self.release()
|
||||
raise e
|
||||
|
||||
def release(self):
|
||||
'''Relâche tous les verrous'''
|
||||
exceptions = []
|
||||
print "releasing", self._active
|
||||
for item in self._active[:]:
|
||||
try:
|
||||
self._releaseitem(item)
|
||||
except Exception, e:
|
||||
exceptions.append(e)
|
||||
if len(exceptions) == 1:
|
||||
# XXX - connecter proprement les tracebacks
|
||||
raise exceptions[0]
|
||||
elif len(exceptions) > 1:
|
||||
raise Exception(exceptions)
|
||||
|
||||
def _islocked(self, item, valeur):
|
||||
# XXX - return self.conn.search_s(base_dn, 2, '%s=%s' % (item, valeur))
|
||||
return self.conn.search_s('%s=%s,%s' % (item, valeur, base_lock), 0)
|
||||
|
||||
def _lockitem(self, item, valeur):
|
||||
u"""
|
||||
Lock un item avec la valeur valeur, les items possibles
|
||||
peuvent être :
|
||||
aid $ chbre $ mail $ mailAlias $ canonicalAlias $
|
||||
mid $ macAddress $ host $ hostAlias $ ipHostNumber
|
||||
Retourne le dn du lock
|
||||
"""
|
||||
|
||||
valeur = valeur.encode('utf-8')
|
||||
|
||||
lock_dn = '%s=%s,%s' % (item, valeur, base_lock)
|
||||
lockid = '%s-%s' % ('localhost', os.getpid())
|
||||
modlist = ldap.modlist.addModlist({ 'objectClass': 'lock',
|
||||
'lockid': lockid,
|
||||
item: valeur })
|
||||
print "locking", lock_dn
|
||||
try:
|
||||
self.conn.add_s(lock_dn, modlist)
|
||||
except ldap.ALREADY_EXISTS:
|
||||
# # Pas de chance, le lock est déja pris
|
||||
# try:
|
||||
# res = self.conn.search_s(lock_dn, 2, 'objectClass=lock')[0]
|
||||
# l = res[1]['lockid'][0]
|
||||
# except: l = '%s-1' % hostname
|
||||
# if l != lockid:
|
||||
# # C'est locké par un autre process que le notre
|
||||
# # il tourne encore ?
|
||||
# if l.split('-')[0] == hostname and os.system('ps %s > /dev/null 2>&1' % l.split('-')[1] ):
|
||||
# # Il ne tourne plus
|
||||
# self._releaseitem(res[0]) # delock
|
||||
# return self._lockitem(item, valeur) # relock
|
||||
raise EnvironmentError(u'Objet (%s=%s) locké, patienter.' % (item, valeur), lockid)
|
||||
self._active.append(lock_dn)
|
||||
return lock_dn
|
||||
|
||||
def _releaseitem(self, lockdn):
|
||||
u"""Destruction d'un lock"""
|
||||
# Mettre des verifs ?
|
||||
print "releasing", lockdn
|
||||
self._active.remove(lockdn)
|
||||
self.conn.delete_s(lockdn)
|
Loading…
Add table
Add a link
Reference in a new issue