From d45f55dae6fd1a48f70ba7014dc4d12004a5ebfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Elliott=20B=C3=A9cue?= Date: Sat, 14 Jun 2014 16:44:44 +0200 Subject: [PATCH] [trigger] Event probablement fonctionnel, need further tests. --- gestion/config/trigger.py | 2 +- gestion/trigger/services/event.py | 111 +++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 3 deletions(-) diff --git a/gestion/config/trigger.py b/gestion/config/trigger.py index 1763135a..564ebe30 100644 --- a/gestion/config/trigger.py +++ b/gestion/config/trigger.py @@ -15,7 +15,7 @@ services = { 'dhcp' : ["dhcp"], 'dyson' : ["autostatus"], 'isc' : ["dhcp"], - 'komaz' : ["firewall", "secours"], + 'komaz' : ["mac_ip", "secours"], 'owl' : ["userdel"], 'redisdead' : ["mailman", "modif_ldap", "solde", "userdel", "secours"], 'sable' : ["dns"], diff --git a/gestion/trigger/services/event.py b/gestion/trigger/services/event.py index 6c7f400e..eda18ea3 100644 --- a/gestion/trigger/services/event.py +++ b/gestion/trigger/services/event.py @@ -13,6 +13,7 @@ import gestion.config.trigger as trigger_config from gestion.trigger.host import record import cranslib.clogger as clogger import pika +import lc_ldap.attributs logger = clogger.CLogger("trigger", "info") @@ -50,10 +51,116 @@ class Event(cmb.BasicProducer): def announce(self, body): self.send_message("trigger.announce", body) +def diff_o_matic(body=()): + """Fait un diff exhaustif des deux dicos""" + + if not body: + raise("diff_o_matic received %r as an argument, which is unusable." % (body,)) + + before = body[1] or {} + after = body[2] or {} + + # set(dico) retourne un set de dico.keys() + keys_pool = set(before).union(set(after)) + diff = {} + + for key in key_pool: + if before.has_key(key): + if not isinstance(before[key], list): + blist = [before[key]] + else: + blist = before[key] + else: + blist = [] + if after.has_key(key): + if not isinstance(after[key], list): + alist = [after[key]] + else: + alist = after[key] + else: + alist = [] + moins, plus = compare_lists(blist, alist) + if moins != [] or plus != []: + diff[key] = (moins, plus) + + return diff + +def compare_lists(list1, list2): + """Compare deux listes, retourne deux listes, une + avec les données perdues, et une avec les données + apparues + + Insensible à la casse. + + """ + moins, plus = [], [] + + llist2 = [a.lower() for a in list2] + for elem in [] + list1: + try: + ind = list2.index(elem.lower()) + except ValueError: + moins.append(elem) + continue + list1.remove(elem) + list2.pop(ind) + plus = plus + list2 + + return moins, plus + @record -def event(body={}): +def event(body=()): """Trigger event qui transcrit toute modif ldap en truc exploitable par trigger. Warning, bootstrap incoming. + body est exceptionnellement un tuple. Pour être précis, un 3-tuple. + Le premier élément est le dn de l'objet LDAP, il est pas indispensable. + Le deuxième est un dico qui recense l'état complet de l'objet modifié avant + validation des modifications. + Le troisième est un dico qui recense l'état complet de l'objet modifié après + modification. + + Si l'objet vient d'être créé, le deuxième élément est None. + Si l'objet vient d'être supprimé, le troisième élément vaut None. + + Il faut donc faire un diff, générer la liste des triggers à envoyer, puis + les envoyer. + """ - pass + + diff = diff_o_matic(body) + + # À cette étape, on a un dico des attrs ayant subi une modif + # a["macAddress"] par exemple, pourrait ressembler à + # (["aa:bb:cc:dd:ee:fg"], ["aa:bb:cc:dd:ee:ff"]), la liste de gauche + # étant les trucs perdus, celle de droite ceux gagnés. Suivant le type + # des attributs, ça peut être un remplacement (mac, ip...), ou juste + # des retraits/ajouts (mailAlias...) + # Avec ça on peut trigger tout ce qu'on veut. + + # Si la mac ou l'IP a changé… + if diff.has_key(lc_ldap.attributs.ipHostNumber.ldap_name) or diff.has_key(lc_ldap.attributs.macAddress.ldap_name): + trigger_mac_ip(body, diff) + +def trigger_mac_ip(body, diff): + macs = tuple([body[i].get(lc_ldap.attributs.macAddress.ldap_name, [''])[0] for i in xrange(1, 3)]) + ips = tuple([body[i].get(lc_ldap.attributs.ipHostNumber.ldap_name, [''])[0] for i in xrange(1, 3)]) + hostnames = tuple([body[i].get(lc_ldap.attributs.host.ldap_name, [''])[0] for i in xrange(1, 3)]) + + # Régénération du DHCP : + if not macs[0]: + # Création d'une nouvelle machine. + to_send = {'add': (macs[1], ips[1], hostnames[1])} + elif not macs[1]: + # Destruction d'une machine. + to_send = {'delete': (macs[0], ips[0])} + else: + # Mise à jour. + to_send = {'update': (macs[0], ips[0], macs[1], ips[1], hostnames[1])} + trigger_send('dhcp', to_send) + + # Régénération du parefeu. + trigger_send('mac_ip', to_send) + +def trigger_send(ttype, to_send): + print "Sending trigger %s with %s…" % (ttype, to_send)