Cette page est en cours d'écriture |
Sommaire
Cette page a pour but de décrire brièvement le nouveau binding ldap (lc_ldap) utilisé par le crans. Cette page se veut introductive afin de pouvoir commencer rapidement à expérimenter avec ipython.
Getting started
La première chose à faire est d'importer le module lc_ldap (lightweight crans ldap):
Il faut ensuite obtenir une connexion (objet lc_ldap.lc_ldap) à la base. Dans le cas de la base de test, ceci se réalise facilement:
Cette connexion est fortement recommandée pour le développement, et c'est de toute façon la seule accessible aux apprentis.
La base ldap de test est une copie de la vraie base ldap, les mots de passes ont tous été effacés et remplacés par un mot de passe unique. Ce mot de passe unique et le même que celui de connexion à la base (voir début du fichier lc_ldap.py en particulier cred='lemotdepasse )
Attention tout de même : des données privées (et déclarées à la CNIL) sont toujours disponibles dans cette base. Les scripts, qui s'en servent doivent rester privés s'ils ne sont pas encore debuggués.
D'autres types de connexions sont possibles, mais nécessitent d'avoir accès au fichier secrets du serveur se trouvant dans /etc/crans/secrets/:
Il est possible de spécifier l'arguement user="MonBelUtilisateur" pour dire qu'il s'agit de MonBelUtilisateur qui utilise la connexion. Cela est ensuite utilisé dans les logs pour savoir qui a fait quelle modification (donc pour des scripts, on aura tendance à utiliser le nom du script). Par défaut, cette valeur vaut le nom de l'utilisateur initiant la connexion.
Effectuer une recherche
Pour rechercher un ensemble d'objet, on utilise simplement la méthode search, on obtient alors une liste d'objets
Le champ de recherche fonctionne à la manière de whos, à la différence près qu'il ne fera pas certains remplacements usuels (rechercher sur les champs habituels lorsque l'on n'en indique pas, les alias mails, etc) et ne vous fera pas de cadeaux en cas d'erreur sur un attribut (pas de message d'erreur). Comme dans le cas de whos, plusieurs objets de types différents peuvent être renvoyés, il faudra soit tester leur type ( objet.__class__), soit filtrer les types d'objets voulus lors de la requête en utilisant l'attribut objectClass (les noms des classes python et ldap correspondent.)
Une liste détaillée des attributs disponibles peut être trouvée dans zamok:/etc/ldap/schema/crans.schema (mais n'est plus totalement à jour). Une description plus complète de la syntaxe de recherche de ldap se trouve à cette adresse.
Il faudrait rajouter la possibilité d'échapper les chaînes de caractères, il semblerait qu'il n'existe pas de fonction clé en main pour faire cela mais elle peut être facilement écrite (cf http://blog.dzhuvinov.com/?p=585 )
Par défaut, le résultat d'une requête ldap est limité à 400 éléménts, si cette limite est dépassée, une erreur est renvoyée :
On peut changer cette limite avec l'argument sizelimit, sachant qu'une valeur nulle annule la limitation (NB : le serveur en possède cependant une autre…) :
Lecture d'un objet
Ses attributs
Pour accéder à un attribut de l'objet, il faut juste utiliser celui-ci comme un dictionnaire, on récupère alors la liste des valeurs de cet attribut :
1 machine = conn.search(u"host=zamok.crans.org")[0]
2 machine['hostAlias']
3 #[<class 'attributs.hostAlias'> : u'ssh.crans.org',
4 # <class 'attributs.hostAlias'> : u'impression.crans.org',
5 # <class 'attributs.hostAlias'> : u'perso.crans.org',
6 # <class 'attributs.hostAlias'> : u'clubs.ens-cachan.fr',
7 # <class 'attributs.hostAlias'> : u'www.clubs.ens-cachan.fr',
8 # <class 'attributs.hostAlias'> : u'mysql.crans.org',
9 # <class 'attributs.hostAlias'> : u'bleu.crans.org',
10 ...
D'une manière générale, vous pouvez manipuler les attributs comme leurs valeurs :
Pour un adhérent :
Les objets enfants
Pour récupérer les objets enfant d'un autre objet (par exemple les machines d'un adhérent, les certificats d'une machine, les factures d'un adhérent), il y a généralement une méthode au nom idoine pour effectuer cela. Par exemple pour les machines de notre adhérent :
Il existe un certain nombre de méthodes sur les objets ldap dont la documentation se trouve sur http://doc.crans.org/lc_ldap/
Écriture
Les locks
Lorsque l'on va vouloir faire une écriture sur un objet, entre le moment où on déclare vouloir utiliser certaines valeurs dans l'objet et le moment où l'objet est effectivement enregistré dans la base ldap, des locks vont être posés pour éviter l'utilisation concurrente de ressource devant être globalement unique dans la base ldap. Aussi, si des locks sont posés, il faut bien faire attention de les libérer lorsque l'on en a plus besoin.
La manière la plus sûr d'être certain de libérer les locks est d'effectuer tout ce que l'on a besoin de faire comme modifications à l'intérieur d'un context manager :
À la sortie du context, l'objet repasse en lecture seule et les locks qui ont pu éventuellement lui être attribué sont libérés. Dans l'exemple ci-dessus, la ressource ipHostNumber devant être globalement unique dans la base ldap, un lock est posé lors de son affectation. Il ne sera normalement libéré qu'une fois la modification enregistrée dans le base ldap en faisant :
1 machine.save()
mais imaginons que quelque chose plante avant que je n'ai eu l'occasion (à l'aide des méthodes save() create() ou delete()) d'enregistrer les modifications dans la base ldap. Alors, les locks acquis resteraient en place. Utiliser un context manager permet d'être certain que, dans tous les cas les locks seront libérés.
Il faut donc retenir, qu'utiliser des context manager, c'est bien.
Si vous ne pouvez absolument pas utiliser de context manager, vous devez faire attention de bien libérer les locks à la main.
Pour libérer les locks d'un objet, il faut :
enregistrer l'objet dans la base ldap (à l'aide des méthodes save() create() ou delete())
- appeler manuellement
1 machine.__exit__(None, None, None)
C'est la methode qui est en fait appelée automatiquement par python lorsque l'on sort d'un context (pour les arguments, voir la doc python). Une fois appelée, l'objet repasse en lecture seule.
libérer explicitement les locks (il ne faut alors absolument plus utiliser l'objet en écriture pour éviter tout conflit cette méthode est très fortement déconseillée ) :
1 conn.lockholder.purge(mon_objet.lockId)
Si vous avez perdu le pointeur vers la connexion ldap en cours ( conn dans les exemples) ou qu'il ne fonctionne plus, il est alors impossible de libérer les locks. Vous ne pouvez attendre qu'ils soient effacés automatiquement.
Un lock précédemment oublié est effacé automatiquement lorsque quelqu'un tente de l'acquérir dans les cas suivant :
- Il a plus de 10min
- Il a été mis par un autre processus du même serveur et ce processus n'existe plus (il a du planter, parce que sinon, il aurait bien libéré son lock)
To be continued