Implémentation d'un gestionnaire d'événements sommaire.

This commit is contained in:
Pierre-Elliott Bécue 2015-03-10 16:41:15 +01:00
parent 6c97d6998f
commit 201377528c
12 changed files with 411 additions and 239 deletions

View file

@ -1,11 +1,9 @@
Auteur : PEB <becue@crans.org>
Date : 14/07/2014
Date : 09/03/2015
Licence : GPLv3
Documentation succincte de trigger
==================================
Tous les fichiers sont renseignés depuis /usr/scripts.
What the fuck is happening?
===========================
Trigger est une sorte de librairie de remplacement de generate et des services
dans la base LDAP, qui fonctionnent avec bien trop de délai.
@ -13,6 +11,18 @@ dans la base LDAP, qui fonctionnent avec bien trop de délai.
Trigger est le fruit d'une longue et intelligente (quelle modestie) réflexion,
et donc nous allons ici décrire son fonctionnement.
Mise à jour LDAP : the fuck is happening?
=========================================
Le binding envoit un tuple contenant en première entrée un hash, en deuxième entrée
un dico contenant les attributs avant modif par le binding, en troisième entrée un
dico contenant les attributs après modif, en quatrième entrée des données additionnelles
(inchangées durant tout le processing).
Documentation succincte de trigger
==================================
Tous les fichiers sont renseignés depuis /usr/scripts.
* gestion/trigger/trigger.py est un fichier python qui importe un consumer de
la librairie cmb. Il marche de manière asynchrone, c'est-à-dire qu'il attend et
traîte les messages un par un. Dans gestion/config/trigger.py, il y a la liste
@ -21,10 +31,11 @@ et donc nous allons ici décrire son fonctionnement.
qu'il doit importer. Par exemple, sur l'hôte dhcp, le seul service présent est
dhcp, et donc trigger va aller chercher gestion/trigger/service/dhcp.py, et
travailler avec.
* gestion/trigger/trigger.py importe une méthode trigger depuis
gestion/trigger/host.py. Cette méthode permet d'aller puiser dans une factory
portant le nom TriggerFactory les références vers les services utiles. Cela
permet ensuite de les régénérer à la volée.
* gestion/trigger/trigger.py importe des services, qui sont dans le dossier
services, et eux importent une méthode depuis gestion/trigger/host.py, qui leur
permet d'enregistrer des triggers. Cette méthode permet d'aller puiser dans une
factory portant le nom TriggerFactory les références vers les services utiles.
Cela permet ensuite de les régénérer à la volée.
* Le dossier gestion/trigger/services contient la liste des services existants
pour trigger. Le fonctionnement des services sera détaillé ci-après.
@ -32,56 +43,56 @@ et donc nous allons ici décrire son fonctionnement.
Fonctionnement des services
===========================
"Un service est une classe qui ne sera jamais instanciée"
Un service est un fichier dans le dossier gestion/trigger/services. Il contient
une fonction décorée avec record_service. C'est une fonction qui sera appelée quand
trigger recevra une demande sur un serveur fournissant ledit service.
Un service est la donnée dans un fichier d'une classe portant le nom du fichier
(et donc du service). La casse dans le nom de la classe n'importe pas. Cette
classe hérite de BasicService, une classe définie dans
gestion/trigger/services/service.py. Cette classe s'appuie sur la métaclasse
MetaService pour se construire, ce qui permet d'établir un certain nombre de
liens entre les méthodes d'une classe représentant un service et des attributs
de lc_ldap que l'on souhaite monitorer. La métaclasse et l'ensemble des liens
susmentionnés n'ont d'intérêt que pour la partie "transcription des modifs de la
base LDAP dans un langage compréhensible par les services".
Enfin, tout service contient une méthode regen prévue pour régénérer ledit
service.
Les services peuvent ensuite contenir autant de méthodes que souhaitées, dans la
mesure où se sont des méthodes de classe ou statiques.
La variable faisant le lien entre les attributs ldap à monitorer et les
fonctions à appeler pour transcrire les changements s'appelle changes_trigger.
C'est un dictionnaire dont les clefs sont le nom des attributs ldap à
surveiller, et les valeurs des tuples contenant les noms des fonctions à
appeler en cas de changement.
Ces fonctions devront toujours avoir le prototype suivant :
@classmethod
def toto(cls, body, diff):
où body et diff sont gérés et fournis tels quels par le service event. body est
un 3-tuple contenant le dn de l'objet ldap modifié, la liste des clefs avant
modification, et celle après. diff est un dictionnaire de différences calculé
entre body[1] et body[2].
Pour que civet sache si un service doit être régénéré, et donc qu'il lui envoie
un message, il faut définir un parser. Ces parsers sont contenus dans
gestion/trigger/parsers/, et portent le nom du service associé. Ils contiennent
au moins une fonction décorée avec record_parser (dont les arguments sont des
attributs ldap à surveiller). Quand civet reçoit des modifs des bindings, il regarde
pour chaque attribut ayant changé s'ils sont surveillés par des parsers, et le cas
échéant demande la régénération des services associés.
Ajouter un nouveau service
==========================
Pour ajouter un service, il faut créer un fichier adapté dans trigger/services/,
puis, définir une classe héritant de BasicService, et respecter quelques règles
primordiales.
et un dans trigger/parsers/. Il faut écrire des fonctions adaptées (le nom est libre),
par exemple, pour un parser :
Premièrement, ce service sera importé sur chaque machine où il est configuré
pour fonctionner, et sur civet dans event.py. Pensez donc une fois le tout
configuré à relancer trigger sur civet, et à vérifier que ça marche. La variable
de configuration debug dans gestion/config/trigger.py est là pour aider. Parmi
les choses importantes, l'idéal est d'avoir des dépendances les plus paresseuses
possibles d'un point de vue évaluation. Ainsi, civet qui ne fait qu'importer le
fichier et utiliser les fonctions d'analyse listées dans changes_trigger peut
éviter de jouer avec ce qui ne le concerne pas.
{{{
@record_parser(lc_ldap.attributs.macAddress.ldap_name, lc_ldap.attributs.ipHostNumber.ldap_name)
def send_mac_ip(body, diff):
}}}
Ensuite, il faut absolument une méthode regen, et définir changes_trigger. (un
dict vide convient)
body est le message reçu par civet sans transformation. diff est le diff calculé
à la volée. Le nom de la fonction n'est pas important. Le décorateur prend les
noms d'attributs à surveiller en paramètre. La fonction doit retourner un tuple
dont le premier élément est le nom du service à régénérer (par exemple, "dhcp"),
et le second les choses que le service devra lire et gérer pour se régénérer.
Pour un service, voici un exemple :
{{{
@record_service
def dhcp(body=None):
}}}
body contient le "body" construit dans un parseur. La fonction est décorée, et
son nom est stocké dans la TriggerFactory. Comme souligné précédemment, le nom
de la fonction est important, au même titre que le nom des fichiers dans
trigger/parsers et triggers/services.
Il faut ensuite référencer le service dans config/trigger.py pour les serveurs
où il est important, et relancer trigger sur ces machines. Lors des tests, il ne
faut pas hésiter à passer trigger en debug dans le fichier config/trigger.py.
Parmi les choses importantes, l'idéal est d'avoir des dépendances les plus
paresseuses possibles d'un point de vue évaluation. Ainsi, civet qui ne fait
qu'importer le fichier et utiliser les fonctions d'analyse listées dans
changes_trigger peut éviter de jouer avec ce qui ne le concerne pas.
Enfin, si vous avez des questions, posez-les avant, pas après.
@ -94,11 +105,10 @@ trigger-*-nomduservice.
Un service spécial
==================
civet est un hôte spécial, qui gère un service spécial : le transcripteur. Le
transcripteur est le service event, dans gestion/trigger/services/event.py,
qui reçoit des messages sur la queue trigger-civet-event. C'est lui qui,
fonction des messages reçus, les répartis tous vers les autres queues avec
clef de routage idoine.
Le service event est celui qui utilise les parseurs pour savoir quels services
doivent être régénérés. Quand il reçoit le body, il fait un calcul des différences
entre body[1] et body[2] (les deux dicos), et fournit ces différences aux parseurs,
qui lui rendent des messages à envoyer.
L'intérêt est d'assurer une indépendance maximale entre binding ldap et la
librairie trigger : le binding doit juste envoyer avec clef de routage