On utilise un champ ldap_name pour savoir quelle classe doit être utilisée pour instancier quel objet/attribut LDAP.

Et comme ça on fiche à la poubelle le dégueulasse globals() et on décorrelle les noms
des classes des noms LDAP.
This commit is contained in:
Vincent Le Gallic 2013-05-15 23:00:17 +02:00
parent 294f7ce949
commit c392a2a986
3 changed files with 391 additions and 170 deletions

View file

@ -37,6 +37,10 @@ import re
import sys import sys
import netaddr import netaddr
import time import time
import functools
import smtplib
import random
import string
from unicodedata import normalize from unicodedata import normalize
from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac from crans_utils import format_tel, format_mac, mailexist, validate_name, ip4_of_rid, ip6_of_mac
@ -44,48 +48,67 @@ sys.path.append("/usr/scripts/gestion")
import config import config
import config.impression import config.impression
import annuaires_pg import annuaires_pg
import smtplib
import random
import string
### SMTP #: Serveur SMTP
smtpserv = "smtp.crans.org" smtpserv = "smtp.crans.org"
### Les droits ### Les droits
# en cas de typo, l'appel d'une variable plante, on préfèrera donc les utiliser en lieu et place # en cas de typo, l'appel d'une variable plante, on préfèrera donc les utiliser en lieu et place
# des chaînes de caractères # des chaînes de caractères
#: Chaine de caractère des droits nounou
nounou = u"Nounou" nounou = u"Nounou"
#: Droit cableur
cableur = u"Cableur" cableur = u"Cableur"
#: Droit apprenti
apprenti = u"Apprenti" apprenti = u"Apprenti"
#: Droit trésorier
tresorier = u"Tresorier" tresorier = u"Tresorier"
#: Droit bureau
bureau = u"Bureau" bureau = u"Bureau"
#: Droit imprimeur
imprimeur = u"Imprimeur" imprimeur = u"Imprimeur"
#: Droit modérateur
moderateur = u"Moderateur" moderateur = u"Moderateur"
#: Droit multimachine
multimachines = u"Multimachines" multimachines = u"Multimachines"
#: Droit Webmaster
webmaster = u"Webmaster" webmaster = u"Webmaster"
#: Droit Webradio
webradio = u"Webradio" webradio = u"Webradio"
#: On peut faire subir des choses à un objet si on est son parent
parent = u"parent" parent = u"parent"
#: On peut faire subir des choses à un objet si on est cet objet
soi = u"soi" soi = u"soi"
#: Le responsable d'un club peut lui faire subir des choses
respo = u"responsable" respo = u"responsable"
#: Liste de tous les droits
TOUS_DROITS = [nounou, apprenti, bureau, tresorier, imprimeur, moderateur, multimachines, cableur, webmaster] TOUS_DROITS = [nounou, apprenti, bureau, tresorier, imprimeur, moderateur, multimachines, cableur, webmaster]
#: Liste des droits forts
DROITS_ELEVES = [nounou, bureau] DROITS_ELEVES = [nounou, bureau]
#: Liste des droits intérmédiaires
DROITS_MOYEN = [apprenti, moderateur] DROITS_MOYEN = [apprenti, moderateur]
#: Liste des droits moins sensibles
DROITS_FAIBLES = [cableur, imprimeur, multimachines] DROITS_FAIBLES = [cableur, imprimeur, multimachines]
#: Qui a le droit de modifier quels droits
DROITS_SUPERVISEUR = { nounou : TOUS_DROITS, DROITS_SUPERVISEUR = { nounou : TOUS_DROITS,
bureau : DROITS_FAIBLES + [bureau, tresorier], bureau : DROITS_FAIBLES + [bureau, tresorier],
} }
class SingleValueError(ValueError): class SingleValueError(ValueError):
"""Erreur levée si on essaye de multivaluer un champ monovalué."""
pass pass
class UniquenessError(EnvironmentError): class UniquenessError(EnvironmentError):
"""Erreur levée si on essaye de créer un objet dont le ``dn`` existe déjà."""
pass pass
class OptionalError(EnvironmentError): class OptionalError(EnvironmentError):
"""Erreur levée si on essaye de créer un objet sans fournir un attribut obligatoire."""
pass pass
def attrify(val, attr, conn, Parent=None): def attrify(val, attr, conn, Parent=None):
"""Transforme un n'importe quoi en :py:class:`Attr`. """Transforme un n'importe quoi en :py:class:`Attr`.
@ -98,7 +121,7 @@ def attrify(val, attr, conn, Parent=None):
else: else:
if not isinstance(val, unicode): if not isinstance(val, unicode):
val = val.decode('utf-8') val = val.decode('utf-8')
return CRANS_ATTRIBUTES.get(attr, Attr)(val, conn, Parent) return AttributeFactory.get(attr, fallback=Attr)(val, conn, Parent)
class AttrsDict(dict): class AttrsDict(dict):
@ -123,8 +146,8 @@ class AttrsDict(dict):
if not isinstance(values, list): if not isinstance(values, list):
values = [ values ] values = [ values ]
if self._parent.mode in ['w', 'rw']: if self._parent.mode in ['w', 'rw']:
if CRANS_ATTRIBUTES.get(attr, Attr).singlevalue and len(values) > 1: if AttributeFactory.get(attr, fallback=Attr).singlevalue and len(values) > 1:
raise SingleValueError("L'attribut %s doit être monovalué." % CRANS_ATTRIBUTES.get(attr, Attr).__name__) raise SingleValueError("L'attribut %s doit être monovalué." % (attr,))
super(AttrsDict, self).__setitem__(attr, values) super(AttrsDict, self).__setitem__(attr, values)
else: else:
super(AttrsDict, self).__setitem__(attr, values) super(AttrsDict, self).__setitem__(attr, values)
@ -151,6 +174,8 @@ class Attr(object):
optional = True optional = True
conn = None conn = None
unique = False unique = False
#: Le nom de l'attribut dans le schéma LDAP
ldap_name = None
"""La liste des droits qui suffisent à avoir le droit de modifier la valeur""" """La liste des droits qui suffisent à avoir le droit de modifier la valeur"""
can_modify = [nounou] can_modify = [nounou]
@ -205,10 +230,44 @@ class Attr(object):
""" """
return not set(liste_droits).isdisjoint(self.can_modify) return not set(liste_droits).isdisjoint(self.can_modify)
class AttributeFactory(object):
"""Utilisée pour enregistrer toutes les classes servant à instancier un attribut LDAP.
Elle sert à les récupérer à partir de leur nom LDAP.
Cette classe n'est jamais instanciée.
"""
_classes = {}
@classmethod
def register(cls, name, classe):
"""Enregistre l'association ``name`` -> ``classe``"""
cls._classes[name] = classe
@classmethod
def get(cls, name, fallback=Attr):
"""Retourne la classe qui a ``name`` pour ``ldap_name``.
Si elle n'existe pas, renvoie :py:class:`Attr` (peut être override en précisant ``fallback``)
"""
return cls._classes.get(name, fallback)
def crans_attribute(classe):
"""Pour décorer les classes permettant d'instancier des attributs LDAP,
afin de les enregistrer dans :py:class:`AttributeFactory`.
"""
AttributeFactory.register(classe.ldap_name, classe)
return classe
@crans_attribute
class objectClass(Attr): class objectClass(Attr):
singlevalue = False singlevalue = False
optional = False optional = False
legend = "entité" legend = "entité"
ldap_name = "objectClass"
""" Personne ne doit modifier de classe """ """ Personne ne doit modifier de classe """
can_modify = [] can_modify = []
@ -249,12 +308,14 @@ class boolAttr(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value).upper() return unicode(self.value).upper()
@crans_attribute
class aid(intAttr): class aid(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Identifiant de l'adhérent" legend = u"Identifiant de l'adhérent"
category = 'id' category = 'id'
unique = True unique = True
ldap_name = "aid"
""" Personne ne devrait modifier un attribut d'identification """ """ Personne ne devrait modifier un attribut d'identification """
can_modify = [] can_modify = []
@ -264,19 +325,23 @@ class aid(intAttr):
def parse_value(self, aid): def parse_value(self, aid):
self.value = int(aid) self.value = int(aid)
@crans_attribute
class uid(Attr): class uid(Attr):
singlevalue = True singlevalue = True
option = False option = False
legend = u"L'identifiant canonique de l'adhérent" legend = u"L'identifiant canonique de l'adhérent"
category = 'perso' category = 'perso'
unique = True unique = True
ldap_name = "uid"
@crans_attribute
class nom(Attr): class nom(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
legend = "Nom" legend = "Nom"
category = 'perso' category = 'perso'
can_modify = [nounou, cableur] can_modify = [nounou, cableur]
ldap_name = "nom"
def parse_value(self, nom): def parse_value(self, nom):
if self.parent != None: if self.parent != None:
@ -287,33 +352,39 @@ class nom(Attr):
else: else:
self.value = validate_name(nom) self.value = validate_name(nom)
@crans_attribute
class prenom(Attr): class prenom(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
legend = u"Prénom" legend = u"Prénom"
category = 'perso' category = 'perso'
can_modify = [nounou, cableur] can_modify = [nounou, cableur]
ldap_name = "prenom"
def parse_value(self, prenom): def parse_value(self, prenom):
self.value = validate_name(prenom) self.value = validate_name(prenom)
@crans_attribute
class compteWiki(Attr): class compteWiki(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Compte WiKi" legend = u"Compte WiKi"
category = 'perso' category = 'perso'
can_modify = [nounou, cableur, soi] can_modify = [nounou, cableur, soi]
ldap_name = "compteWiki"
def parse_value(self, compte): def parse_value(self, compte):
self.value = validate_name(compte) self.value = validate_name(compte)
# TODO: validate with mdp for user definition here ? # TODO: validate with mdp for user definition here ?
@crans_attribute
class tel(Attr): class tel(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
legend = u"Téléphone" legend = u"Téléphone"
category = 'perso' category = 'perso'
can_modify = [soi, nounou, cableur] can_modify = [soi, nounou, cableur]
ldap_name = "tel"
def parse_value(self, tel): def parse_value(self, tel):
self.value = format_tel(tel) self.value = format_tel(tel)
@ -330,20 +401,27 @@ class yearAttr(intAttr):
raise ValueError("Année invalide (%r)" % annee) raise ValueError("Année invalide (%r)" % annee)
self.value = annee self.value = annee
@crans_attribute
class paiement(yearAttr): class paiement(yearAttr):
legend = u"Paiement" legend = u"Paiement"
can_modify = [cableur, nounou, tresorier] can_modify = [cableur, nounou, tresorier]
category = 'perso' category = 'perso'
ldap_name = "paiement"
@crans_attribute
class carteEtudiant(yearAttr): class carteEtudiant(yearAttr):
legend = u"Carte d'étudiant" legend = u"Carte d'étudiant"
category = 'perso' category = 'perso'
can_modify = [cableur, nounou, tresorier] can_modify = [cableur, nounou, tresorier]
ldap_name = "carteEtudiant"
@crans_attribute
class derniereConnexion(intAttr): class derniereConnexion(intAttr):
legend = u"Dernière connexion" legend = u"Dernière connexion"
can_modify = [] can_modify = []
ldap_name = "derniereConnexion"
@crans_attribute
class mail(Attr): class mail(Attr):
singlevalue = False singlevalue = False
optional = False optional = False
@ -351,6 +429,7 @@ class mail(Attr):
legend = "Le mail de l'adhérent" legend = "Le mail de l'adhérent"
can_modify = [soi, nounou, cableur] can_modify = [soi, nounou, cableur]
category = 'mail' category = 'mail'
ldap_name = "mail"
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
attr = self.__class__.__name__ attr = self.__class__.__name__
@ -380,12 +459,14 @@ class mail(Attr):
self.value = mail self.value = mail
@crans_attribute
class canonicalAlias(mail): class canonicalAlias(mail):
singlevalue = True singlevalue = True
optional = False optional = False
unique = True unique = True
legend = u"Alias mail canonique" legend = u"Alias mail canonique"
category = 'mail' category = 'mail'
ldap_name = "canonicalAlias"
def parse_value(self, mail): def parse_value(self, mail):
mail = u".".join([ a.capitalize() for a in mail.split(u'.', 1) ]) mail = u".".join([ a.capitalize() for a in mail.split(u'.', 1) ])
@ -393,6 +474,7 @@ class canonicalAlias(mail):
raise ValueError("Alias mail invalide (%s)" % mail) raise ValueError("Alias mail invalide (%s)" % mail)
self.value = mail self.value = mail
@crans_attribute
class mailAlias(mail): class mailAlias(mail):
singlevalue = False singlevalue = False
optional = True optional = True
@ -400,6 +482,7 @@ class mailAlias(mail):
legend = u"Alias mail" legend = u"Alias mail"
can_modify = [soi, cableur, nounou] can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailAlias"
def parse_value(self, mail): def parse_value(self, mail):
mail = mail.lower() mail = mail.lower()
@ -407,6 +490,7 @@ class mailAlias(mail):
raise ValueError("Alias mail invalide (%r)" % mail) raise ValueError("Alias mail invalide (%r)" % mail)
self.value = mail self.value = mail
@crans_attribute
class mailExt(mail): class mailExt(mail):
singlevalue = False singlevalue = False
optional = True optional = True
@ -414,6 +498,7 @@ class mailExt(mail):
legend = u"Mail externe" legend = u"Mail externe"
can_modify = [soi, cableur, nounou] can_modify = [soi, cableur, nounou]
category = 'mail' category = 'mail'
ldap_name = "mailExt"
def parse_value(self, mail): def parse_value(self, mail):
mail = mail.lower() mail = mail.lower()
@ -421,31 +506,38 @@ class mailExt(mail):
raise ValueError("Mail externe invalide (%r)" % mail) raise ValueError("Mail externe invalide (%r)" % mail)
self.value = mail self.value = mail
@crans_attribute
class mailInvalide(boolAttr): class mailInvalide(boolAttr):
optional = True optional = True
legend = u"Mail invalide" legend = u"Mail invalide"
can_modify = [bureau, nounou] can_modify = [bureau, nounou]
ldap_name = "mailInvalide"
@crans_attribute
class contourneGreylist(boolAttr): class contourneGreylist(boolAttr):
optionnal = True optionnal = True
legend = u"Contourner la greylist" legend = u"Contourner la greylist"
category = 'mail' category = 'mail'
can_modify = [soi] can_modify = [soi]
ldap_name = "contourneGreylist"
def __unicode__(self): def __unicode__(self):
return u"OK" return u"OK"
@crans_attribute
class etudes(Attr): class etudes(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Études" legend = u"Études"
can_modify = [soi, cableur, nounou] can_modify = [soi, cableur, nounou]
category = 'perso' category = 'perso'
ldap_name = "etudes"
def parse_value(self, etudes): def parse_value(self, etudes):
# who cares # who cares
self.value = etudes self.value = etudes
@crans_attribute
class chbre(Attr): class chbre(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
@ -453,6 +545,7 @@ class chbre(Attr):
legend = u"Chambre sur le campus" legend = u"Chambre sur le campus"
can_modify = [soi, cableur, nounou] can_modify = [soi, cableur, nounou]
category = 'perso' category = 'perso'
ldap_name = "chbre"
def parse_value(self, chambre): def parse_value(self, chambre):
if self.parent != None: if self.parent != None:
@ -475,12 +568,14 @@ class chbre(Attr):
self.value = chambre self.value = chambre
@crans_attribute
class droits(Attr): class droits(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Droits sur les serveurs" legend = u"Droits sur les serveurs"
can_modify = [nounou, bureau] #ne sert à rien ici, mais c'est tout à fait exceptionnel can_modify = [nounou, bureau] #ne sert à rien ici, mais c'est tout à fait exceptionnel
category = 'perso' category = 'perso'
ldap_name = "droits"
def parse_value(self, droits): def parse_value(self, droits):
# if val.lower() not in [i.lower() for i in TOUS_DROITS]: # if val.lower() not in [i.lower() for i in TOUS_DROITS]:
@ -498,11 +593,13 @@ class droits(Attr):
return self.value in modifiables return self.value in modifiables
@crans_attribute
class solde(Attr): class solde(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Solde d'impression" legend = u"Solde d'impression"
can_modify = [imprimeur, nounou, tresorier] can_modify = [imprimeur, nounou, tresorier]
ldap_name = "solde"
def parse_value(self, solde): def parse_value(self, solde):
# on évite les dépassements, sauf si on nous dit de ne pas vérifier # on évite les dépassements, sauf si on nous dit de ne pas vérifier
@ -512,6 +609,7 @@ class solde(Attr):
class dnsAttr(Attr): class dnsAttr(Attr):
category = 'dns' category = 'dns'
ldap_name = "dnsAttr"
def parse_value(self, val): def parse_value(self, val):
val = val.lower() val = val.lower()
names = val.split('.') names = val.split('.')
@ -520,12 +618,14 @@ class dnsAttr(Attr):
raise ValueError("Nom d'hote invalide %r" % val) raise ValueError("Nom d'hote invalide %r" % val)
self.value = val self.value = val
@crans_attribute
class host(dnsAttr): class host(dnsAttr):
singlevalue = True singlevalue = True
optional = False optional = False
hname = legend = u"Nom d'hôte" hname = legend = u"Nom d'hôte"
can_modify = [parent, nounou, cableur] can_modify = [parent, nounou, cableur]
category = 'base_tech' category = 'base_tech'
ldap_name = "host"
def check_uniqueness(self, liste_exclue): def check_uniqueness(self, liste_exclue):
attr = self.__class__.__name__ attr = self.__class__.__name__
@ -536,14 +636,16 @@ class host(dnsAttr):
if res: if res:
raise ValueError("Hôte déjà existant", [r.dn for r in res]) raise ValueError("Hôte déjà existant", [r.dn for r in res])
@crans_attribute
class hostAlias(host): class hostAlias(host):
singlevalue = False singlevalue = False
unique = True unique = True
optional = True optional = True
legend = u'Alias de nom de machine' legend = u'Alias de nom de machine'
can_modify = [nounou, cableur] can_modify = [nounou, cableur]
ldap_name = "hostAlias"
@crans_attribute
class macAddress(Attr): class macAddress(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
@ -551,6 +653,7 @@ class macAddress(Attr):
hname = "Adresse MAC" hname = "Adresse MAC"
category = 'base_tech' category = 'base_tech'
can_modify = [parent, nounou, cableur] can_modify = [parent, nounou, cableur]
ldap_name = "macAddress"
def parse_value(self, mac): def parse_value(self, mac):
self.value = format_mac(mac) self.value = format_mac(mac)
@ -559,6 +662,7 @@ class macAddress(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value).lower() return unicode(self.value).lower()
@crans_attribute
class ipHostNumber(Attr): class ipHostNumber(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
@ -567,6 +671,7 @@ class ipHostNumber(Attr):
hname = "IPv4" hname = "IPv4"
category = 'base_tech' category = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "ipHostNumber"
def parse_value(self, ip): def parse_value(self, ip):
if ip == '<automatique>': if ip == '<automatique>':
@ -576,6 +681,7 @@ class ipHostNumber(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@crans_attribute
class ip6HostNumber(Attr): class ip6HostNumber(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
@ -584,6 +690,7 @@ class ip6HostNumber(Attr):
hname = "IPv6" hname = "IPv6"
category = 'base_tech' category = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "ip6HostNumber"
def parse_value(self, ip6): def parse_value(self, ip6):
ip = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0]))) ip = ip6_of_mac(str(self.parent['macAddress'][0]), int(str(self.parent['rid'][0])))
@ -592,12 +699,14 @@ class ip6HostNumber(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@crans_attribute
class mid(Attr): class mid(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
unique = True unique = True
legend = u"Identifiant de machine" legend = u"Identifiant de machine"
category = 'id' category = 'id'
ldap_name = "mid"
def parse_value(self, mid): def parse_value(self, mid):
self.value = int(mid) self.value = int(mid)
@ -605,6 +714,7 @@ class mid(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@crans_attribute
class rid(Attr): class rid(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
@ -612,6 +722,7 @@ class rid(Attr):
legend = u"Identifiant réseau de machine" legend = u"Identifiant réseau de machine"
category = 'id' category = 'id'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "rid"
def parse_value(self, rid): def parse_value(self, rid):
rid = int(rid) rid = int(rid)
@ -635,11 +746,13 @@ class rid(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value) return unicode(self.value)
@crans_attribute
class ipsec(Attr): class ipsec(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u'Clef wifi' legend = u'Clef wifi'
category = 'wifi' category = 'wifi'
ldap_name = "ipsec"
def parse_value(self, val): def parse_value(self, val):
if len(val) in [10, 22]: if len(val) in [10, 22]:
@ -649,41 +762,51 @@ class ipsec(Attr):
if val == u"auto": if val == u"auto":
self.value = u''.join( random.choice(filter(lambda x: x != 'l' and x != 'o', string.lowercase) + filter(lambda x: x != '1' and x != '0', string.digits)) for i in range(10)) self.value = u''.join( random.choice(filter(lambda x: x != 'l' and x != 'o', string.lowercase) + filter(lambda x: x != '1' and x != '0', string.digits)) for i in range(10))
@crans_attribute
class puissance(Attr): class puissance(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"puissance d'émission pour les bornes wifi" legend = u"puissance d'émission pour les bornes wifi"
category = 'wifi' category = 'wifi'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "puissance"
@crans_attribute
class canal(intAttr): class canal(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u'Canal d\'émission de la borne' legend = u'Canal d\'émission de la borne'
category = 'wifi' category = 'wifi'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "canal"
@crans_attribute
class hotspot(boolAttr): class hotspot(boolAttr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u'Hotspot' legend = u'Hotspot'
category = 'wifi' category = 'wifi'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "hotspot"
@crans_attribute
class positionBorne(Attr): class positionBorne(Attr):
legend = u"Position de la borne" legend = u"Position de la borne"
category = "wifi" category = "wifi"
can_modify = [nounou] can_modify = [nounou]
singlevalue = True singlevalue = True
optional = True optional = True
ldap_name = "positionBorne"
def parse_value(self, pos): def parse_value(self, pos):
self.value = unicode(pos) self.value = unicode(pos)
@crans_attribute
class nvram(Attr): class nvram(Attr):
legend = u"Configuration speciale" legend = u"Configuration speciale"
optional = True optional = True
can_modify = [nounou] can_modify = [nounou]
ldap_name = "nvram"
def parse_value(self, nvr): def parse_value(self, nvr):
# XXX - on fait quoi ici ? # XXX - on fait quoi ici ?
@ -695,7 +818,7 @@ class portAttr(Attr):
legend = u'Ouverture de port' legend = u'Ouverture de port'
category = 'firewall' category = 'firewall'
can_modify = [nounou] can_modify = [nounou]
def parse_value(self, port): def parse_value(self, port):
if ":" in port: if ":" in port:
a,b = port.split(":", 1) a,b = port.split(":", 1)
@ -724,55 +847,73 @@ class portAttr(Attr):
else: else:
return unicode(self.value[0]) return unicode(self.value[0])
@crans_attribute
class portTCPout(portAttr): class portTCPout(portAttr):
legend = u'Port TCP ouvert vers l\'extérieur' legend = u'Port TCP ouvert vers l\'extérieur'
ldap_name = "portTCPout"
@crans_attribute
class portTCPin(portAttr): class portTCPin(portAttr):
legend = u"Port TCP ouvert depuis l'extérieur" legend = u"Port TCP ouvert depuis l'extérieur"
ldap_name = "portTCPin"
@crans_attribute
class portUDPout(portAttr): class portUDPout(portAttr):
legend = u"Port UDP ouvert vers l'extérieur" legend = u"Port UDP ouvert vers l'extérieur"
ldap_name = "portUDPout"
@crans_attribute
class portUDPin(portAttr): class portUDPin(portAttr):
legend = u"Port UDP ouvert depuis l'extérieur" legend = u"Port UDP ouvert depuis l'extérieur"
ldap_name = "portUDPin"
@crans_attribute
class exempt(Attr): class exempt(Attr):
legend = u"Exemption vers une IP" legend = u"Exemption vers une IP"
ldap_name = "exempt"
@crans_attribute
class nombrePrises(intAttr): class nombrePrises(intAttr):
legend = u"Nombre de prises ethernet de la machine" legend = u"Nombre de prises ethernet de la machine"
singlevalue = True singlevalue = True
optional = True optional = True
categoriy = 'base_tech' categoriy = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "nombrePrises"
@crans_attribute
class prise(Attr): class prise(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Prise sur laquelle est branchée la machine" legend = u"Prise sur laquelle est branchée la machine"
category = 'base_tech' category = 'base_tech'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "prise"
def parse_value(self, prise): def parse_value(self, prise):
### Tu es Beau, je te fais confiance ### Tu es Beau, je te fais confiance
self.value = prise self.value = prise
@crans_attribute
class cid(intAttr): class cid(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
unique = True unique = True
legend = u"Identifiant du club" legend = u"Identifiant du club"
category = 'id' category = 'id'
ldap_name = "cid"
def parse_value(self, val): def parse_value(self, val):
self.value = int(val) self.value = int(val)
@crans_attribute
class responsable(Attr): class responsable(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Responsable du club" legend = u"Responsable du club"
category = 'perso' category = 'perso'
can_modify = [cableur, nounou] can_modify = [cableur, nounou]
ldap_name = "responsable"
def nonefunction(self, resp): def nonefunction(self, resp):
""" """
@ -805,11 +946,13 @@ class responsable(Attr):
def __unicode__(self): def __unicode__(self):
return self.__value return self.__value
@crans_attribute
class imprimeurClub(Attr): class imprimeurClub(Attr):
optional = True optional = True
legend = u"Imprimeur du club" legend = u"Imprimeur du club"
category = "perso" category = "perso"
can_modify = [cableur, nounou] can_modify = [cableur, nounou]
ldap_name = "imprimeurClub"
def nonefunction(self, imprimeur): def nonefunction(self, imprimeur):
""" """
@ -839,12 +982,14 @@ class imprimeurClub(Attr):
def __unicode__(self): def __unicode__(self):
return unicode(self.value['aid'][0]) return unicode(self.value['aid'][0])
@crans_attribute
class blacklist(Attr): class blacklist(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Blackliste" legend = u"Blackliste"
category = 'info' category = 'info'
can_modify = [nounou] can_modify = [nounou]
ldap_name = "blacklist"
def parse_value(self, blacklist): def parse_value(self, blacklist):
bl_debut, bl_fin, bl_type, bl_comm = blacklist.split('$') bl_debut, bl_fin, bl_type, bl_comm = blacklist.split('$')
@ -865,43 +1010,53 @@ class blacklist(Attr):
def __unicode__(self): def __unicode__(self):
return u'%(debut)s$%(fin)s$%(type)s$%(comm)s' % self.value return u'%(debut)s$%(fin)s$%(type)s$%(comm)s' % self.value
@crans_attribute
class historique(Attr): class historique(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Historique de l'objet" legend = u"Historique de l'objet"
category = 'info' category = 'info'
ldap_name = "historique"
@crans_attribute
class info(Attr): class info(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = u"Quelques informations" legend = u"Quelques informations"
category = 'info' category = 'info'
can_modify = [nounou, cableur, bureau] can_modify = [nounou, cableur, bureau]
ldap_name = "info"
@crans_attribute
class homepageAlias(Attr): class homepageAlias(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u'Un alias pour la page personnelle' legend = u'Un alias pour la page personnelle'
can_modify = [nounou, cableur] can_modify = [nounou, cableur]
category = 'webpage' category = 'webpage'
ldap_name = "homepageAlias"
@crans_attribute
class charteMA(Attr): class charteMA(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend= "Signale si l'adhérent a signé la charte de membres actifs" legend= "Signale si l'adhérent a signé la charte de membres actifs"
can_modify = [nounou, bureau] can_modify = [nounou, bureau]
category = 'perso' category = 'perso'
ldap_name = "charteMA"
def parse_value(self, charteSignee): def parse_value(self, charteSignee):
if charteSignee.upper() not in ["TRUE", "FALSE"]: if charteSignee.upper() not in ["TRUE", "FALSE"]:
raise ValueError("La charte MA est soit TRUE ou FALSE, pas %r" % charteSignee) raise ValueError("La charte MA est soit TRUE ou FALSE, pas %r" % charteSignee)
self.value = charteSignee.upper() self.value = charteSignee.upper()
@crans_attribute
class homeDirectory(Attr): class homeDirectory(Attr):
singlevalue=True singlevalue=True
optional = True optional = True
unique = True unique = True
legend="Le chemin du home de l'adhérent" legend="Le chemin du home de l'adhérent"
ldap_name = "homeDirectory"
def parse_value(self, home): def parse_value(self, home):
uid = str(self.parent['uid'][0]) uid = str(self.parent['uid'][0])
@ -911,12 +1066,14 @@ class homeDirectory(Attr):
raise ValueError("Le répertoire personnel n'est pas bon: %r (devrait être %r ou %r)" % (home, '/home/%s' % self.parent['uid'][0], '/home/club/%s' % self.parent['uid'][0])) raise ValueError("Le répertoire personnel n'est pas bon: %r (devrait être %r ou %r)" % (home, '/home/%s' % self.parent['uid'][0], '/home/club/%s' % self.parent['uid'][0]))
self.value = home self.value = home
@crans_attribute
class loginShell(Attr): class loginShell(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = "Le shell de l'adherent" legend = "Le shell de l'adherent"
can_modify = [soi, nounou, cableur] can_modify = [soi, nounou, cableur]
ldap_name = "loginShell"
def parse_value(self, shell): def parse_value(self, shell):
#with open('/etc/shells') as f: #with open('/etc/shells') as f:
# shells = [ l.strip() for l in f.readlines() if not l.startswith('#') ] # shells = [ l.strip() for l in f.readlines() if not l.startswith('#') ]
@ -948,95 +1105,113 @@ class loginShell(Attr):
raise ValueError("Shell %r invalide" % shell) raise ValueError("Shell %r invalide" % shell)
self.value = shell self.value = shell
@crans_attribute
class uidNumber(intAttr): class uidNumber(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
unique = True unique = True
legend = "L'uid du compte de l'adherent" legend = "L'uid du compte de l'adherent"
category = 'id' category = 'id'
ldap_name = "uidNumber"
@crans_attribute
class gidNumber(intAttr): class gidNumber(intAttr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = "Le gid du compte de l'adhérent" legend = "Le gid du compte de l'adhérent"
category = 'id' category = 'id'
ldap_name = "gidNumber"
@crans_attribute
class gecos(Attr): class gecos(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = "Le gecos" legend = "Le gecos"
category = 'id' category = 'id'
ldap_name = "gecos"
def parse_value(self, gecos): def parse_value(self, gecos):
self.value = gecos self.value = gecos
@crans_attribute
class sshFingerprint(Attr): class sshFingerprint(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
legend = "Clef ssh de la machine" legend = "Clef ssh de la machine"
can_modify = [parent, nounou] can_modify = [parent, nounou]
ldap_name = "sshFingerprint"
@crans_attribute
class gpgFingerprint(Attr): class gpgFingerprint(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
unique = True unique = True
legend = "Clef gpg d'un adhérent" legend = "Clef gpg d'un adhérent"
can_modify = [soi, nounou] can_modify = [soi, nounou]
ldap_name = "gpgFingerprint"
@crans_attribute
class cn(Attr): class cn(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
category = 'id' category = 'id'
ldap_name = "cn"
@crans_attribute
class dn(Attr): class dn(Attr):
singlevalue = True singlevalue = True
optional = False optional = False
unique = True unique = True
category = 'id' category = 'id'
ldap_name = "dn"
@crans_attribute
class postalAddress(Attr): class postalAddress(Attr):
singlevalue = False singlevalue = False
optional = True optional = True
can_modify = [soi, cableur, nounou, bureau] can_modify = [soi, cableur, nounou, bureau]
legend = u"Adresse" legend = u"Adresse"
category = 'perso' category = 'perso'
ldap_name = "postalAddress"
@crans_attribute
class controle(Attr): class controle(Attr):
singlevalue = True singlevalue = True
optional = True optional = True
legend = u"Contrôle" legend = u"Contrôle"
can_modify = [tresorier, nounou] can_modify = [tresorier, nounou]
category = 'perso' category = 'perso'
ldap_name = "controle"
def parse_value(self, ctrl): def parse_value(self, ctrl):
if ctrl not in [u"", u"c", u"p", u"cp", u"pc"]: if ctrl not in [u"", u"c", u"p", u"cp", u"pc"]:
raise ValueError("control peut prendre les valeurs [c][p]") raise ValueError("control peut prendre les valeurs [c][p]")
self.value = ctrl self.value = ctrl
@crans_attribute
class fid(intAttr): class fid(intAttr):
legend = u"Id de facture" legend = u"Id de facture"
category = 'factures' category = 'factures'
optional = False optional = False
singlevalue = True singlevalue = True
ldap_name = "fid"
@crans_attribute
class modePaiement(Attr): class modePaiement(Attr):
legend = u"Mode de paiement" legend = u"Mode de paiement"
category = 'factures' category = 'factures'
optional = False optional = False
singlevalue = True singlevalue = True
ldap_name = "modePaiement"
@crans_attribute
class recuPaiement(Attr): class recuPaiement(Attr):
pass ldap_name = "recuPaiement"
@crans_attribute
class dnsIpv6(boolAttr): class dnsIpv6(boolAttr):
pass ldap_name = "dnsIpv6"
@crans_attribute
class machineAlias(boolAttr): class machineAlias(boolAttr):
pass ldap_name = "machineAlias"
## Penser à remplacer ça par un dictionnaire en compréhension quand on sera sous wheezy partout
#: Dictionnaire mappant "nom de l'atttribut" -> classe permettant de l'instancier
CRANS_ATTRIBUTES = {}
for (k, v) in locals().items():
if type(v) == type and issubclass(v, Attr):
CRANS_ATTRIBUTES[k] = v

View file

@ -53,9 +53,10 @@ try:
from Levenshtein import jaro from Levenshtein import jaro
except ImportError: except ImportError:
def jaro(a, b): return 0 def jaro(a, b): return 0
sys.path.append('/usr/scripts/gestion')
sys.path.append('/usr/scripts/gestion')
import config import config
import crans_utils import crans_utils
import attributs import attributs
import ldap_locks import ldap_locks
@ -71,9 +72,9 @@ created = 'created'
modified = 'modified' modified = 'modified'
deleted = 'deleted' deleted = 'deleted'
# Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script #: Pour enregistrer dans l'historique, on a besoin de savoir qui exécute le script
# Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo) #: Si le script a été exécuté via un sudo, la variable SUDO_USER (l'utilisateur qui a effectué le sudo)
# est plus pertinente que USER (qui sera root) #: est plus pertinente que USER (qui sera root)
current_user = os.getenv("SUDO_USER") or os.getenv("USER") current_user = os.getenv("SUDO_USER") or os.getenv("USER")
# Quand on a besoin du fichier de secrets # Quand on a besoin du fichier de secrets
@ -84,7 +85,7 @@ def import_secrets():
import secrets import secrets
return secrets return secrets
# Champs à ignorer dans l'historique #: Champs à ignorer dans l'historique
HIST_IGNORE_FIELDS = ["modifiersName", "entryCSN", "modifyTimestamp", "historique"] HIST_IGNORE_FIELDS = ["modifiersName", "entryCSN", "modifyTimestamp", "historique"]
def escape(chaine): def escape(chaine):
@ -453,9 +454,9 @@ class lc_ldap_local(lc_ldap):
def new_cransldapobject(conn, dn, mode='ro', ldif = None): def new_cransldapobject(conn, dn, mode='ro', ldif = None):
"""Crée un objet :py:class:`CransLdap` en utilisant la classe correspondant à """Crée un objet :py:class:`CransLdapObject` en utilisant la classe correspondant à
l'``objectClass`` du ``ldif`` l'``objectClass`` du ``ldif``
--pour usage interne à la libraire uniquement !""" --pour usage interne à la librairie uniquement !"""
classe = None classe = None
@ -464,13 +465,13 @@ def new_cransldapobject(conn, dn, mode='ro', ldif = None):
elif dn == invite_dn: elif dn == invite_dn:
classe = BaseInvites classe = BaseInvites
elif ldif: elif ldif:
classe = globals()[ldif['objectClass'][0]] classe = ObjectFactory.get(ldif['objectClass'][0])
else: else:
res = conn.search_s(dn, 0) res = conn.search_s(dn, 0)
if not res: if not res:
raise ValueError ('objet inexistant: %s' % dn) raise ValueError ('objet inexistant: %s' % dn)
_, attrs = res[0] _, attrs = res[0]
classe = globals()[attrs['objectClass'][0]] classe = ObjectFactory.get(attrs['objectClass'][0])
return classe(conn, dn, mode, ldif) return classe(conn, dn, mode, ldif)
@ -793,6 +794,36 @@ class CransLdapObject(object):
self._modifs.setdefault('blacklist', []).append(bl) self._modifs.setdefault('blacklist', []).append(bl)
class ObjectFactory(object):
"""Utilisée pour enregistrer toutes les classes servant à instancier un objet LDAP.
Elle sert à les récupérer à partir de leur nom LDAP.
Cette classe n'est jamais instanciée.
"""
_classes = {}
@classmethod
def register(cls, name, classe):
"""Enregistre l'association ``name`` -> ``classe``"""
cls._classes[name] = classe
@classmethod
def get(cls, name):
"""Retourne la classe qui a ``name`` pour ``ldap_name``.
Pas de fallback, on ne veut pas instancier des objets de manière hasardeuse.
"""
return cls._classes.get(name)
def crans_object(classe):
"""Pour décorer les classes permettant d'instancier des attributs LDAP,
afin de les enregistrer dans :py:class:`ObjectFactory`.
"""
ObjectFactory.register(classe.ldap_name, classe)
return classe
class proprio(CransLdapObject): class proprio(CransLdapObject):
u""" Un propriétaire de machine (adhérent, club…) """ u""" Un propriétaire de machine (adhérent, club…) """
@ -944,6 +975,7 @@ class BaseInvites(proprio):
pass pass
@crans_object
class adherent(proprio): class adherent(proprio):
u"""Adhérent crans.""" u"""Adhérent crans."""
attribs = proprio.attribs + [attributs.aid, attributs.prenom, attributs.tel, attribs = proprio.attribs + [attributs.aid, attributs.prenom, attributs.tel,
@ -951,6 +983,7 @@ class adherent(proprio):
attributs.derniereConnexion, attributs.gpgFingerprint, attributs.derniereConnexion, attributs.gpgFingerprint,
attributs.carteEtudiant, attributs.droits, attributs.etudes, attributs.carteEtudiant, attributs.droits, attributs.etudes,
attributs.postalAddress, attributs.mailExt, attributs.compteWiki] attributs.postalAddress, attributs.mailExt, attributs.compteWiki]
ldap_name = "adherent"
def __init__(self, conn, dn, mode='ro', ldif = None): def __init__(self, conn, dn, mode='ro', ldif = None):
super(adherent, self).__init__(conn, dn, mode, ldif) super(adherent, self).__init__(conn, dn, mode, ldif)
@ -1028,17 +1061,22 @@ class adherent(proprio):
raise EnvironmentError("L'adhérent n'a pas de compte crans") raise EnvironmentError("L'adhérent n'a pas de compte crans")
@crans_object
class club(proprio): class club(proprio):
u"""Club crans""" u"""Club crans"""
attribs = proprio.attribs + [attributs.cid, attributs.responsable, attributs.imprimeurClub] attribs = proprio.attribs + [attributs.cid, attributs.responsable, attributs.imprimeurClub]
ldap_name = "club"
@crans_object
class machineFixe(machine): class machineFixe(machine):
u"""Machine fixe""" u"""Machine fixe"""
pass ldap_name = "machineFixe"
@crans_object
class machineWifi(machine): class machineWifi(machine):
u"""Machine wifi""" u"""Machine wifi"""
attribs = machine.attribs + [attributs.ipsec] attribs = machine.attribs + [attributs.ipsec]
ldap_name = "machineWifi"
def set_ipv4(self, login=None): def set_ipv4(self, login=None):
u"""Définie une ipv4 à la machine si elle n'est possède pas déjà une.""" u"""Définie une ipv4 à la machine si elle n'est possède pas déjà une."""
@ -1053,13 +1091,16 @@ class machineWifi(machine):
dhcp=dydhcp() dhcp=dydhcp()
dhcp.add_host(str(self['ipHostNumber'][0]), str(self['macAddress'][0]), str(self['host'][0])) dhcp.add_host(str(self['ipHostNumber'][0]), str(self['macAddress'][0]), str(self['host'][0]))
@crans_object
class machineCrans(machine): class machineCrans(machine):
can_be_by = { created: [attributs.nounou], can_be_by = { created: [attributs.nounou],
modified: [attributs.nounou], modified: [attributs.nounou],
deleted: [attributs.nounou], deleted: [attributs.nounou],
} }
attribs = machine.attribs + [attributs.prise, attributs.nombrePrises] attribs = machine.attribs + [attributs.prise, attributs.nombrePrises]
ldap_name = "machineCrans"
@crans_object
class borneWifi(machine): class borneWifi(machine):
can_be_by = { created: [attributs.nounou], can_be_by = { created: [attributs.nounou],
modified: [attributs.nounou], modified: [attributs.nounou],
@ -1067,16 +1108,21 @@ class borneWifi(machine):
} }
attribs = machine.attribs + [attributs.canal, attributs.puissance, attributs.hotspot, attribs = machine.attribs + [attributs.canal, attributs.puissance, attributs.hotspot,
attributs.prise, attributs.positionBorne, attributs.nvram] attributs.prise, attributs.positionBorne, attributs.nvram]
ldap_name = "borneWifi"
@crans_object
class facture(CransLdapObject): class facture(CransLdapObject):
can_be_by = { created: [attributs.nounou, attributs.bureau, attributs.cableur], can_be_by = { created: [attributs.nounou, attributs.bureau, attributs.cableur],
modified: [attributs.nounou, attributs.bureau, attributs.cableur], modified: [attributs.nounou, attributs.bureau, attributs.cableur],
deleted: [attributs.nounou, attributs.bureau, attributs.cableur], deleted: [attributs.nounou, attributs.bureau, attributs.cableur],
} }
attribs = [attributs.fid, attributs.modePaiement, attributs.recuPaiement] attribs = [attributs.fid, attributs.modePaiement, attributs.recuPaiement]
ldap_name = "facture"
@crans_object
class service(CransLdapObject): class service(CransLdapObject):
pass ldap_name = "service"
@crans_object
class lock(CransLdapObject): class lock(CransLdapObject):
pass ldap_name = "lock"

View file

@ -69,162 +69,162 @@ def preattr(val):
# Presque identique à celle dans ldap_crans.py # Presque identique à celle dans ldap_crans.py
def service_to_restart(conn, new=None, args=[], start=0): def service_to_restart(conn, new=None, args=[], start=0):
""" """
start indique la date (en secondes depuis epoch) à partir du start indique la date (en secondes depuis epoch) à partir du
moment cette action sera effectuée. moment cette action sera effectuée.
Si new = None retourne la liste des services à redémarrer. Si new = None retourne la liste des services à redémarrer.
Si new est fourni, mais ne commence pas par '-', on ajoute Si new est fourni, mais ne commence pas par '-', on ajoute
le service à la liste avec les arguments args (args doit être le service à la liste avec les arguments args (args doit être
une liste). une liste).
Si new commence par '-', on supprime le service si son start Si new commence par '-', on supprime le service si son start
est dans le futur. est dans le futur.
Si new commence par '--', on supprime le service sans condition. Si new commence par '--', on supprime le service sans condition.
""" """
if new: new = preattr(new)[1] if new: new = preattr(new)[1]
# Quels services sont déjà à redémarrer ? # Quels services sont déjà à redémarrer ?
serv = {} # { service: [ arguments ] } serv = {} # { service: [ arguments ] }
serv_dates = {} # { service: [ dates de restart ] } serv_dates = {} # { service: [ dates de restart ] }
services = [] services = []
for s in conn.search_s(services_dn, 1, 'objectClass=service'): for s in conn.search_s(services_dn, 1, 'objectClass=service'):
s = s[1] s = s[1]
serv[s['cn'][0]] = s.get('args', []) serv[s['cn'][0]] = s.get('args', [])
serv_dates[s['cn'][0]] = s.get('start', []) serv_dates[s['cn'][0]] = s.get('start', [])
services.append(Service(s['cn'][0], s.get('args', []), s.get('start', []))) services.append(Service(s['cn'][0], s.get('args', []), s.get('start', [])))
# Retourne la liste des services à redémarrer # Retourne la liste des services à redémarrer
if not new: return services if not new: return services
# Effacement d'un service # Effacement d'un service
if new[0] == '-': if new[0] == '-':
if new[1] == '-': if new[1] == '-':
# Double -- on enlève quelque soit la date # Double -- on enlève quelque soit la date
remove_dn = 'cn=%s,%s' % (new[2:], services_dn) remove_dn = 'cn=%s,%s' % (new[2:], services_dn)
else:
# On enlève uniquement si la date est passée
remove_dn = 'cn=%s,%s' % (new[1:], services_dn)
if not serv.has_key(new[1:]):
# Existe pas => rien à faire
return
keep_date = []
for date in serv_dates[new[1:]]:
if time.time() < int(date):
keep_date.append(date)
if keep_date:
mods = [{'start': serv_dates[new[1:]]}, { 'start': keep_date }]
conn.modify_s(remove_dn, ldap.modlist.modifyModlist(*mods))
remove_dn = None
if remove_dn:
# Suppression
try: conn.delete_s(remove_dn)
except: pass
# Si n'existe pas => Erreur mais le résultat est là.
return
serv_dn = 'cn=%s,%s' % (new, services_dn)
# Conversion avant stockage dans la base
if isinstance(args, basestring):
args = [args]
args = map(lambda x:preattr(x)[1], args)
try:
start = [int(start)]
except TypeError:
pass
start = map(lambda x:preattr(x)[1], start)
if new in serv.keys():
modlist = []
new_args = []
# Nouveaux arguments ?
for arg in args:
if arg not in serv[new]:
new_args.append(arg)
if new_args:
modlist += ldap.modlist.modifyModlist({'args': serv[new]},
{'args': serv[new] + new_args})
new_date = []
# Nouvelle date ?
for date in start:
if date not in serv_dates[new]:
new_date.append(date)
if new_date:
modlist += ldap.modlist.modifyModlist({'start': serv_dates[new]},
{'start': serv_dates[new] + new_date})
if modlist:
try:
conn.modify_s(serv_dn, modlist)
except ldap.TYPE_OR_VALUE_EXISTS:
# Pas grave
pass
# else rien à faire
else: else:
# Entrée non présente -> ajout # On enlève uniquement si la date est passée
modlist = ldap.modlist.addModlist({ 'objectClass': 'service', remove_dn = 'cn=%s,%s' % (new[1:], services_dn)
'cn': new, if not serv.has_key(new[1:]):
'args': args, # Existe pas => rien à faire
'start': start }) return
keep_date = []
for date in serv_dates[new[1:]]:
if time.time() < int(date):
keep_date.append(date)
if keep_date:
mods = [{'start': serv_dates[new[1:]]}, { 'start': keep_date }]
conn.modify_s(remove_dn, ldap.modlist.modifyModlist(*mods))
remove_dn = None
if remove_dn:
# Suppression
try: conn.delete_s(remove_dn)
except: pass
# Si n'existe pas => Erreur mais le résultat est là.
return
serv_dn = 'cn=%s,%s' % (new, services_dn)
# Conversion avant stockage dans la base
if isinstance(args, basestring):
args = [args]
args = map(lambda x:preattr(x)[1], args)
try:
start = [int(start)]
except TypeError:
pass
start = map(lambda x:preattr(x)[1], start)
if new in serv.keys():
modlist = []
new_args = []
# Nouveaux arguments ?
for arg in args:
if arg not in serv[new]:
new_args.append(arg)
if new_args:
modlist += ldap.modlist.modifyModlist({'args': serv[new]},
{'args': serv[new] + new_args})
new_date = []
# Nouvelle date ?
for date in start:
if date not in serv_dates[new]:
new_date.append(date)
if new_date:
modlist += ldap.modlist.modifyModlist({'start': serv_dates[new]},
{'start': serv_dates[new] + new_date})
if modlist:
try: try:
conn.add_s(serv_dn, modlist) conn.modify_s(serv_dn, modlist)
except ldap.ALREADY_EXISTS: except ldap.TYPE_OR_VALUE_EXISTS:
# Existe déja => rien à faire # Pas grave
pass pass
# else rien à faire
else:
# Entrée non présente -> ajout
modlist = ldap.modlist.addModlist({ 'objectClass': 'service',
'cn': new,
'args': args,
'start': start })
try:
conn.add_s(serv_dn, modlist)
except ldap.ALREADY_EXISTS:
# Existe déja => rien à faire
pass
def services_to_restart(conn, old_attrs={}, new_attrs={}): def services_to_restart(conn, old_attrs={}, new_attrs={}):
"""Détermine quels sont les services à reconfigurer""" """Détermine quels sont les services à reconfigurer"""
old_attrs_c = dict((attributs.CRANS_ATTRIBUTES[key], value) for key,value in old_attrs.items() if key in attributs.CRANS_ATTRIBUTES.keys() and value) old_attrs_c = dict((attributs.AttributeFactory.get(key), value) for key,value in old_attrs.items() if attributs.AttributeFactory.get(key, fallback=None) != None and value)
new_attrs_c = dict((attributs.CRANS_ATTRIBUTES[key], value) for key,value in new_attrs.items() if key in attributs.CRANS_ATTRIBUTES.keys() and value) new_attrs_c = dict((attributs.AttributeFactory.get(key), value) for key,value in new_attrs.items() if attributs.AttributeFactory.get(key, fallback=None) != None and value)
created_attr = [ attr for name in new_attrs_c.keys() if not name in old_attrs_c.keys() for attr in new_attrs_c[name]] created_attr = [ attr for name in new_attrs_c.keys() if not name in old_attrs_c.keys() for attr in new_attrs_c[name]]
deleted_attr = [ attr for name in old_attrs_c.keys() if not name in new_attrs_c.keys() for attr in old_attrs_c[name]] deleted_attr = [ attr for name in old_attrs_c.keys() if not name in new_attrs_c.keys() for attr in old_attrs_c[name]]
updated_attr = [ (old_attrs_c[name], new_attrs_c[name], updated_attr = [ (old_attrs_c[name], new_attrs_c[name],
[ i for i in old_attrs_c[name] if i.value not in [ j.value for j in new_attrs_c[name]]], [ i for i in old_attrs_c[name] if i.value not in [ j.value for j in new_attrs_c[name]]],
[ i for i in new_attrs_c[name] if i.value not in [ j.value for j in old_attrs_c[name]]], [ i for i in new_attrs_c[name] if i.value not in [ j.value for j in old_attrs_c[name]]],
) for name in set(new_attrs_c.keys()).intersection(old_attrs_c.keys()) if old_attrs_c[name][-1].value != new_attrs_c[name][-1].value ] ) for name in set(new_attrs_c.keys()).intersection(old_attrs_c.keys()) if old_attrs_c[name][-1].value != new_attrs_c[name][-1].value ]
updated_attr_new = [ i for j in updated_attr for i in j[3]] updated_attr_new = [ i for j in updated_attr for i in j[3]]
updated_attr_old = [ i for j in updated_attr for i in j[2]] updated_attr_old = [ i for j in updated_attr for i in j[2]]
services_to_restart = {} services_to_restart = {}
for attr in [ attr for l in [created_attr, deleted_attr, updated_attr_new ] for attr in l]: for attr in [ attr for l in [created_attr, deleted_attr, updated_attr_new ] for attr in l]:
for service in attrs_to_services.get(attr.__class__, []): for service in attrs_to_services.get(attr.__class__, []):
services_to_restart[service] = services_to_restart.get(service, []) + [attr] services_to_restart[service] = services_to_restart.get(service, []) + [attr]
for service in services_to_restart.keys(): for service in services_to_restart.keys():
for attr in services_to_restart[service]: for attr in services_to_restart[service]:
start = 0 start = 0
arg = set() arg = set()
if service in services_to_args.keys(): if service in services_to_args.keys():
arg = arg.union(services_to_args[service](attr)) arg = arg.union(services_to_args[service](attr))
if attr in updated_attr_new: if attr in updated_attr_new:
for old_attr in updated_attr_old: for old_attr in updated_attr_old:
if attr.__class__ == old_attr.__class__: if attr.__class__ == old_attr.__class__:
arg = arg.union(services_to_args[service](old_attr)) arg = arg.union(services_to_args[service](old_attr))
# Cas du dhcp # Cas du dhcp
if attr.__class__ in services_to_attrs['dhcp']: if attr.__class__ in services_to_attrs['dhcp']:
dhcp=dydhcp() dhcp=dydhcp()
if old_attrs.get('ipHostNumber', []) and old_attrs.get('macAddress', []): if old_attrs.get('ipHostNumber', []) and old_attrs.get('macAddress', []):
if new_attrs.get('ipHostNumber', []) and new_attrs.get('macAddress', []): if new_attrs.get('ipHostNumber', []) and new_attrs.get('macAddress', []):
if str(old_attrs['ipHostNumber'][0]) != str(new_attrs['ipHostNumber'][0]) or str(old_attrs['macAddress'][0]) != str(new_attrs['macAddress'][0]): if str(old_attrs['ipHostNumber'][0]) != str(new_attrs['ipHostNumber'][0]) or str(old_attrs['macAddress'][0]) != str(new_attrs['macAddress'][0]):
dhcp.del_host(str(old_attrs['ipHostNumber'][0]), str(old_attrs['macAddress'][0]))
dhcp.add_host(str(new_attrs['ipHostNumber'][0]), str(new_attrs['macAddress'][0]), str(new_attrs['host'][0]))
else:
dhcp.del_host(str(old_attrs['ipHostNumber'][0]), str(old_attrs['macAddress'][0])) dhcp.del_host(str(old_attrs['ipHostNumber'][0]), str(old_attrs['macAddress'][0]))
elif new_attrs.get('ipHostNumber', []) and new_attrs.get('macAddress', []): dhcp.add_host(str(new_attrs['ipHostNumber'][0]), str(new_attrs['macAddress'][0]), str(new_attrs['host'][0]))
dhcp.add_host(str(new_attrs['ipHostNumber'][0]), str(new_attrs['macAddress'][0]), str(new_attrs['host'][0])) else:
dhcp.del_host(str(old_attrs['ipHostNumber'][0]), str(old_attrs['macAddress'][0]))
elif new_attrs.get('ipHostNumber', []) and new_attrs.get('macAddress', []):
dhcp.add_host(str(new_attrs['ipHostNumber'][0]), str(new_attrs['macAddress'][0]), str(new_attrs['host'][0]))
if service in services_to_time.keys(): if service in services_to_time.keys():
start = services_to_time[service](attr) start = services_to_time[service](attr)
#print "%s,%s,%s" % (service, arg, start) #print "%s,%s,%s" % (service, arg, start)
service_to_restart(conn, service, list(arg), start) service_to_restart(conn, service, list(arg), start)