From 616acdbb7a0fd2313f4dbff1fd78aec36470560c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Elliott=20B=C3=A9cue?= Date: Thu, 30 May 2013 18:44:15 +0200 Subject: [PATCH] =?UTF-8?q?[global]=20On=20diminue=20le=20risque=20de=20lo?= =?UTF-8?q?ck=20r=C3=A9siduel,=20et=20on=20corrige=20une=20faille=20des=20?= =?UTF-8?q?fonctions=20new[A-Z]*?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * En cas d'erreur au create ou au save, on supprime les locks malgré tout * Les fonctions new* modifiaient directement le dico qu'on leur passait en argument, on fait désormais une copie de celui-ci, de façon à ce que test.py n'instancie pas toujours le même objet en croyant instancier des objets différents à chaque fois * Cela permet de trouver une typo dans services.py * crans_utils a été un peu corrigé. --- attributs.py | 6 ++++-- crans_utils.py | 2 +- lc_ldap.py | 20 +++++++++++++------- objets.py | 37 +++++++++++++++++++++++++++++-------- services.py | 2 +- test.py | 6 ++++-- 6 files changed, 52 insertions(+), 21 deletions(-) diff --git a/attributs.py b/attributs.py index 7737934..962be90 100644 --- a/attributs.py +++ b/attributs.py @@ -664,7 +664,6 @@ class macAddress(Attr): def parse_value(self, mac): self.value = format_mac(mac) - # XXX self.parent['ip6HostNumber'] = cequ'ilfaut def __unicode__(self): return unicode(self.value).lower() @@ -700,7 +699,10 @@ class ip6HostNumber(Attr): ldap_name = "ip6HostNumber" def parse_value(self, ip6): - ip = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0]))) + if self.parent != None: + ip = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0]))) + else: + ip = ip6 self.value = netaddr.ip.IPAddress(ip) def __unicode__(self): diff --git a/crans_utils.py b/crans_utils.py index 78ca065..52e16d2 100644 --- a/crans_utils.py +++ b/crans_utils.py @@ -136,7 +136,7 @@ def ip6_of_mac(mac, rid): if net != "special": return netaddr.IPAddress(netaddr.IPNetwork(config.prefix[net][0]).first + int(euid64v6, 16)) else: - return config.ipv6_machines_speciales[rid] + return netaddr.IPAddress(config.ipv6_machines_speciales[rid]) def strip_accents(a): """ Supression des accents de la chaîne fournie""" diff --git a/lc_ldap.py b/lc_ldap.py index 490afbd..01b685e 100644 --- a/lc_ldap.py +++ b/lc_ldap.py @@ -47,6 +47,7 @@ import attributs import objets import ldap_locks import variables +import copy import itertools ## import de /usr/scripts/ @@ -218,10 +219,13 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): _, adherents = self.allMachinesAdherents(mode) return adherents - def newMachine(self, parent, realm, uldif, login=None): + def newMachine(self, parent, realm, mldif, login=None): """Crée une nouvelle machine: ``realm`` peut être: fil, fil-v6, wifi, wifi-v6, adm, gratuit, personnel-ens, special + mldif est un uldif pour la machine --Partiellement implémenté""" + # On ne veut pas modifier mldif directement + uldif = copy.deepcopy(mldif) if login is None: login = self.current_login #adm, serveurs, bornes, wifi, adherents, gratuit ou personnel-ens""" @@ -239,7 +243,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): uldif['objectClass'] = [u'machineWifi'] assert isinstance(owner, objets.adherent) or isinstance(owner, objets.club) - elif realm in ["adherents", "adherents-v6", "personnel-ens"]: + elif realm in ["adherents", "fil-v6", "personnel-ens"]: uldif['objectClass'] = [u'machineFixe'] assert isinstance(owner, objets.adherent) or isinstance(owner, objets.club) @@ -249,7 +253,7 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): # On récupère la plage des mids plage = itertools.chain(*[xrange(a,b+1) for (a,b) in config.rid_primaires[realm]]) # On récupère le premier id libre dans la plages s'il n'est pas - # déjà précisé dans le ldiff + # déjà précisé dans le ldif rid = uldif.setdefault('rid', [unicode(self._find_id('rid', plage)) ]) # La machine peut-elle avoir une ipv4 ? @@ -262,14 +266,14 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): # Tout doit disparaître !! machine = self._create_entity('mid=%s,%s' % (uldif['mid'][0], parent), uldif) - machine.history_add(login, u"inscription") if machine.may_be(variables.created, self.droits + self._check_parent(machine.dn)): return machine else: raise EnvironmentError("Vous n'avez pas le droit de créer cette machine.") - def newAdherent(self, uldif): + def newAdherent(self, aldif): """Crée un nouvel adhérent""" + uldif = copy.deepcopy(aldif) aid = uldif.setdefault('aid', [ unicode(self._find_id('aid')) ]) uldif['objectClass'] = [u'adherent'] adherent = self._create_entity('aid=%s,%s' % (aid[0], variables.base_dn), uldif) @@ -278,8 +282,9 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): else: raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.") - def newClub(self, uldif): + def newClub(self, cldif): """Crée un nouveau club""" + uldif = copy.deepcopy(cldif) cid = uldif.setdefault('cid', [ unicode(self._find_id('cid')) ]) uldif['objectClass'] = [u'club'] club = self._create_entity('cid=%s,%s' % (cid[0], variables.base_dn), uldif) @@ -288,9 +293,10 @@ class lc_ldap(ldap.ldapobject.LDAPObject, object): else: raise EnvironmentError("Vous n'avez pas le droit de créer cet adhérent.") - def newFacture(self, uldif): + def newFacture(self, fldif): """Crée une nouvelle facture --Non implémenté !""" + uldif = copy.deepcopy(fldif) raise NotImplementedError() def _create_entity(self, dn, uldif): diff --git a/objets.py b/objets.py index 9cc1d0f..2c65f06 100644 --- a/objets.py +++ b/objets.py @@ -44,6 +44,7 @@ import re import datetime import time import ldap +import traceback from ldap.modlist import addModlist, modifyModlist ## import locaux @@ -189,24 +190,36 @@ class CransLdapObject(object): faite""" pass - def create(self): + def create(self, login=None): """Crée l'objet dans la base ldap, cette méthode vise à faire en sorte que l'objet se crée lui-même, si celui qui essaye de le modifier a les droits de le faire.""" + if login is None: + login = self.conn.current_login self._check_optionnal(comment="créez") + + self.history_add(login, u"Inscription") # Création de la requête LDAP modlist = addModlist(self._modifs.to_ldif()) # Requête LDAP de création de l'objet - self.conn.add_s(self.dn, modlist) + try: + self.conn.add_s(self.dn, modlist) + except Exception: + print traceback.format_exc() + return # On nettoie les locks for key, values in self._modifs.to_ldif().iteritems(): for value in values: self.conn.lockholder.removelock(key, value) self.conn.lockholder.purge(id(self)) + # Services à relancer services.services_to_restart(self.conn, {}, self._modifs) self._post_creation() + + # Vérifications après insertion. + self.check_modifs() def bury(self, comm, login): """Sauvegarde l'objet dans un fichier dans le cimetière.""" @@ -251,25 +264,33 @@ class CransLdapObject(object): try: self.conn.modify_s(self.dn, modlist) except: + # On nettoie les locks + self.conn.lockholder.purge(id(self)) + self._modifs = self.attrs raise EnvironmentError("Impossible de modifier l'objet, peut-être n'existe-t-il pas ?") # On programme le redémarrage des services services.services_to_restart(self.conn, self.attrs, self._modifs) - # On nettoie les locks - self.conn.lockholder.purge(id(self)) + # Vérification des modifications. + self.check_modifs() + def check_modifs(self): + """ + Fonction qui vérifie que les modifications se sont bien + passées. + """ # Vérification des modifications - old_ldif = self.conn.search_s(self.dn, ldap.SCOPE_BASE)[0][1] - old_uldif = lc_ldap.ldif_to_uldif(old_ldif) + old_uldif = lc_ldap.ldif_to_uldif(self.conn.search_s(self.dn, ldap.SCOPE_BASE)[0][1]) self.attrs = attributs.AttrsDict(self.conn, old_uldif, Parent=self) differences = [] # On fait les différences entre les deux dicos for attr in set(self.attrs.keys()).union(set(self._modifs.keys())): - exp_vals = set([unicode(i) for i in self.attrs.get(attr, [])]) - new_vals = set([unicode(i) for i in self._modifs.get(attr, [])]) + exp_vals = set([str(i) for i in self.attrs.get(attr, [])]) + new_vals = set([str(i) for i in self._modifs.get(attr, [])]) if exp_vals != new_vals: differences.append({"missing": exp_vals - new_vals, "having": new_vals - exp_vals}) + print differences[-1] if differences: raise EnvironmentError("Les modifications apportées à l'objet %s n'ont pas été correctement sauvegardées\n%s" % (self.dn, differences)) diff --git a/services.py b/services.py index 67fbd9f..5f67873 100644 --- a/services.py +++ b/services.py @@ -31,7 +31,7 @@ services_to_attrs['mail_modif'] = [] # génération des arguments du service à redémarrer (par defaut []) services_to_args={} -services_to_args['macip']=lambda x: issubclass(type(x.parent), objets.machine) and ([str(x)] if isinstance(x, attributs.ipHostNumber) else [ str(ip) for ip in x.parent.get('ipHostNumber',[]) ]) or ([ str(ip) for m in x.parent.machines() for ip in m.get('ipHostNumber',[])] if issubclass(type(x.parent), lc_ldap.proprio) else []) +services_to_args['macip']=lambda x: issubclass(type(x.parent), objets.machine) and ([str(x)] if isinstance(x, attributs.ipHostNumber) else [ str(ip) for ip in x.parent.get('ipHostNumber',[]) ]) or ([ str(ip) for m in x.parent.machines() for ip in m.get('ipHostNumber',[])] if issubclass(type(x.parent), objets.proprio) else []) ## Inutile pour blackliste pour le moment #services_to_args['blacklist']=lambda x: issubclass(type(x.parent), lc_ldap.machine) and [ str(ip) for m in x.parent.proprio().machines() for ip in m['ipHostNumber'] ] or [ str(ip) for m in x.parent.machines() for ip in m['ipHostNumber'] ] services_to_args['port']=lambda x: [str(x)] if isinstance(x, attributs.ipHostNumber) or isinstance(x, attributs.ip6HostNumber) else [ str(ip) for ip in x.parent.get('ipHostNumber',[]) ] diff --git a/test.py b/test.py index 7ce1db9..77606f5 100755 --- a/test.py +++ b/test.py @@ -51,9 +51,10 @@ machine_ldif = { borne_ldif = { 'macAddress' : [randomMAC()], - 'host' : ["autotest-%s.crans.org" % randomStr() ], - 'canal' : ["11"], + 'host' : [u"autotest-%s.crans.org" % randomStr() ], + 'canal' : [u"11"], 'puissance' : [u"52"], + 'hotspot' : [u'FALSE'], } club_ldif = { @@ -132,6 +133,7 @@ def tests_machines(parent_dn, realm_list, ipsec=False): try: machine = conn.search('mid=%s' % machine['mid'][0], mode='rw')[0] machine.delete() + del(machine) except Exception as error: print ERREUR if show_traceback: print traceback.format_exc()