[trigger] Going back to simplified version
This commit is contained in:
parent
8068f057e0
commit
091a2d161e
6 changed files with 287 additions and 292 deletions
|
@ -7,6 +7,7 @@
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
debug = True
|
debug = True
|
||||||
|
log_level = "info"
|
||||||
|
|
||||||
# Serveur maître
|
# Serveur maître
|
||||||
master = "rabbitmq.adm.crans.org"
|
master = "rabbitmq.adm.crans.org"
|
||||||
|
|
|
@ -10,27 +10,50 @@
|
||||||
# License : GPLv3
|
# License : GPLv3
|
||||||
# Date : 28/04/2014
|
# Date : 28/04/2014
|
||||||
|
|
||||||
|
import collections
|
||||||
|
|
||||||
class TriggerFactory(object):
|
class TriggerFactory(object):
|
||||||
"""Factory containing which function is part of the trigger set
|
"""Factory containing which function is part of the trigger set
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_meths = {}
|
_services = {}
|
||||||
|
_parsers = collections.defaultdict(list)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register(cls, key, value):
|
def register_service(cls, key, value):
|
||||||
cls._meths[key] = value
|
cls._services[key] = value
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, key):
|
def get_service(cls, key):
|
||||||
return cls._meths.get(key, None)
|
return cls._services.get(key, None)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_services(cls):
|
def get_services(cls):
|
||||||
return cls._meths.values()
|
return cls._services.values()
|
||||||
|
|
||||||
def record(cls):
|
@classmethod
|
||||||
TriggerFactory.register(cls.__name__.lower(), cls)
|
def register_parser(cls, keys, parser):
|
||||||
|
for key in keys:
|
||||||
|
cls._parsers[key].append(parser)
|
||||||
|
|
||||||
def trigger(what):
|
@classmethod
|
||||||
return TriggerFactory.get(what)
|
def get_parser(cls, keyword):
|
||||||
|
return cls._parsers[keyword]
|
||||||
|
|
||||||
|
def record_service(func):
|
||||||
|
"""Records in the triggerfactory the function
|
||||||
|
|
||||||
|
The function provided are services to regen
|
||||||
|
|
||||||
|
"""
|
||||||
|
TriggerFactory.register_service(func.func_name, func)
|
||||||
|
|
||||||
|
def trigger_service(what):
|
||||||
|
return TriggerFactory.get_service(what)
|
||||||
|
|
||||||
|
def record_parser(*args):
|
||||||
|
def find_parser(func):
|
||||||
|
TriggerFactory.register_parser(args, func)
|
||||||
|
return func
|
||||||
|
return find_parser
|
||||||
|
|
|
@ -18,212 +18,186 @@ import struct
|
||||||
|
|
||||||
import gestion.config.trigger as trigger_config
|
import gestion.config.trigger as trigger_config
|
||||||
import cranslib.clogger as clogger
|
import cranslib.clogger as clogger
|
||||||
logger = clogger.CLogger("trigger", "dhcp", "debug", trigger_config.debug)
|
logger = clogger.CLogger("trigger", "dhcp", trigger_config.log_level, trigger_config.debug)
|
||||||
|
|
||||||
hostname = socket.gethostname().split(".")[0] + ".adm.crans.org"
|
hostname = socket.gethostname().split(".")[0]
|
||||||
|
hostname_adm = hostname + ".adm.crans.org"
|
||||||
|
|
||||||
import lc_ldap.shortcuts
|
import lc_ldap.shortcuts
|
||||||
from gestion.trigger.services.service import BasicService
|
|
||||||
from cranslib.conffile import ConfFile
|
from cranslib.conffile import ConfFile
|
||||||
import gestion.config.dhcp as dhcp_config
|
import gestion.config.dhcp as dhcp_config
|
||||||
import gestion.secrets_new as secrets_new
|
import gestion.secrets_new as secrets_new
|
||||||
import gestion.affichage as affichage
|
import gestion.affichage as affichage
|
||||||
import gestion.iptools as iptools
|
import gestion.iptools as iptools
|
||||||
from gestion.trigger.pypureomapi import pack_ip, pack_mac, OMAPI_OP_UPDATE
|
from gestion.trigger.pypureomapi import pack_ip, pack_mac, OMAPI_OP_UPDATE, Omapi, OmapiMessage
|
||||||
from gestion.trigger.pypureomapi import Omapi, OmapiMessage
|
from gestion.trigger.host import record_service, record_parser, TriggerFactory
|
||||||
|
|
||||||
|
|
||||||
class Dhcp(BasicService):
|
|
||||||
"""Class responsible of dhcp service.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Class lookup table to define which changes call which function.
|
|
||||||
changes_trigger = {
|
|
||||||
lc_ldap.attributs.macAddress.ldap_name: ('send_mac_ip',),
|
|
||||||
lc_ldap.attributs.ipHostNumber.ldap_name: ('send_mac_ip',),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if "dhcp" in trigger_config.services[hostname]:
|
||||||
|
dhcp_omapi_keyname = secrets_new.get("dhcp_omapi_keyname")
|
||||||
|
dhcp_omapi_key = secrets_new.get("dhcp_omapi_keys")[hostname_adm]
|
||||||
|
ldap_conn = lc_ldap.shortcuts.lc_ldap_readonly()
|
||||||
|
else:
|
||||||
dhcp_omapi_keyname = None
|
dhcp_omapi_keyname = None
|
||||||
dhcp_omapi_key = None
|
dhcp_omapi_key = None
|
||||||
ldap_conn = None
|
ldap_conn = None
|
||||||
|
|
||||||
@classmethod
|
@record_parser(lc_ldap.attributs.macAddress.ldap_name, lc_ldap.attributs.ipHostNumber.ldap_name)
|
||||||
def send_mac_ip(cls, body, diff):
|
def send_mac_ip(body, diff):
|
||||||
"""Computes mac_ip data to send from body and diff
|
"""Computes mac_ip data to send from body and diff
|
||||||
|
|
||||||
"""
|
"""
|
||||||
macs = tuple([body[i].get(lc_ldap.attributs.macAddress.ldap_name, [''])[0] for i in xrange(1, 3)])
|
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)])
|
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)])
|
hostnames = tuple([body[i].get(lc_ldap.attributs.host.ldap_name, [''])[0] for i in xrange(1, 3)])
|
||||||
|
|
||||||
# Régénération du DHCP :
|
# Régénération du DHCP :
|
||||||
if not macs[0]:
|
if not macs[0]:
|
||||||
# Création d'une nouvelle machine.
|
# Création d'une nouvelle machine.
|
||||||
dhcp_dict = {'add': [(macs[1], ips[1], hostnames[1])]}
|
dhcp_dict = {'add': [(macs[1], ips[1], hostnames[1])]}
|
||||||
elif not macs[1]:
|
elif not macs[1]:
|
||||||
# Destruction d'une machine.
|
# Destruction d'une machine.
|
||||||
dhcp_dict = {'delete': [(macs[0], ips[0])]}
|
dhcp_dict = {'delete': [(macs[0], ips[0])]}
|
||||||
else:
|
else:
|
||||||
# Mise à jour.
|
# Mise à jour.
|
||||||
dhcp_dict = {'update': [(macs[0], ips[0], macs[1], ips[1], hostnames[1])]}
|
dhcp_dict = {'update': [(macs[0], ips[0], macs[1], ips[1], hostnames[1])]}
|
||||||
return ("dhcp", dhcp_dict)
|
return ("dhcp", dhcp_dict)
|
||||||
|
|
||||||
@classmethod
|
@record_service
|
||||||
def regen(cls, body=None):
|
def dhcp(body=None):
|
||||||
"""Regenerates dhcp service taking body into account.
|
"""Regenerates dhcp service taking body into account.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
cls.check_params()
|
|
||||||
|
|
||||||
# http://satyajit.ranjeev.in/2012/01/12/python--dangerous-default-value-as-argument.html
|
# http://satyajit.ranjeev.in/2012/01/12/python--dangerous-default-value-as-argument.html
|
||||||
# dict are referenced.
|
# dict are referenced.
|
||||||
if body is None:
|
if body is None:
|
||||||
body = {}
|
body = {}
|
||||||
|
|
||||||
if body and isinstance(body, dict):
|
if body and isinstance(body, dict):
|
||||||
for (mac, ip, name) in body.get("add", []):
|
for (mac, ip, name) in body.get("add", []):
|
||||||
logger.info("Updating DHCP db by adding %s, %s, %s", mac, ip, name)
|
logger.info("Updating DHCP db by adding %s, %s, %s", mac, ip, name)
|
||||||
# XXX - Uncommend this when we need to start prod
|
# XXX - Uncommend this when we need to start prod
|
||||||
# cls.add_dhcp_host(mac, ip, name)
|
# add_dhcp_host(mac, ip, name)
|
||||||
for (mac, ip) in body.get("delete", []):
|
for (mac, ip) in body.get("delete", []):
|
||||||
logger.info("Updating DHCP db by deleting %s, %s", mac, ip)
|
logger.info("Updating DHCP db by deleting %s, %s", mac, ip)
|
||||||
# XXX - Uncommend this when we need to start prod
|
# XXX - Uncommend this when we need to start prod
|
||||||
# cls.delete_dhcp_host(mac, ip)
|
# delete_dhcp_host(mac, ip)
|
||||||
for (rmac, rip, mac, ip, name) in body.get("update", []):
|
for (rmac, rip, mac, ip, name) in body.get("update", []):
|
||||||
logger.info("Updating DHCP db by modifying %s, %s to %s, %s, %s", rmac, rip, mac, ip, name)
|
logger.info("Updating DHCP db by modifying %s, %s to %s, %s, %s", rmac, rip, mac, ip, name)
|
||||||
# XXX - Uncommend this when we need to start prod
|
# XXX - Uncommend this when we need to start prod
|
||||||
# cls.delete_dhcp_host(rmac, rip)
|
# delete_dhcp_host(rmac, rip)
|
||||||
# cls.add_dhcp_host(mac, ip, name)
|
# add_dhcp_host(mac, ip, name)
|
||||||
elif body == True:
|
elif body == True:
|
||||||
hosts = {}
|
hosts = {}
|
||||||
host_template = """
|
host_template = """
|
||||||
host %(nom)s {
|
host %(nom)s {
|
||||||
hardware ethernet %(mac)s;
|
hardware ethernet %(mac)s;
|
||||||
fixed-address %(ip)s;
|
fixed-address %(ip)s;
|
||||||
option host-name "%(host)s";
|
option host-name "%(host)s";
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
affichage.prettyDoin("Chargement des machines", "...")
|
affichage.prettyDoin("Chargement des machines", "...")
|
||||||
machines = cls.ldap_conn.allMachines()
|
machines = ldap_conn.allMachines()
|
||||||
affichage.prettyDoin("Chargement des machines", "Ok")
|
affichage.prettyDoin("Chargement des machines", "Ok")
|
||||||
animation = affichage.Animation(texte="Génération de la configuration",
|
animation = affichage.Animation(texte="Génération de la configuration",
|
||||||
nb_cycles=len(machines),
|
nb_cycles=len(machines),
|
||||||
couleur=True,
|
couleur=True,
|
||||||
kikoo=True)
|
kikoo=True)
|
||||||
|
|
||||||
for machine in machines:
|
for machine in machines:
|
||||||
for net in dhcp_config.reseaux.keys():
|
for net in dhcp_config.reseaux.keys():
|
||||||
ip = str(machine['ipHostNumber'][0])
|
ip = str(machine['ipHostNumber'][0])
|
||||||
mac = str(machine['macAddress'][0])
|
mac = str(machine['macAddress'][0])
|
||||||
nom = str(machine['host'][0])
|
nom = str(machine['host'][0])
|
||||||
if '<automatique>' not in [ip, mac] and iptools.AddrInNet(ip, net):
|
if '<automatique>' not in [ip, mac] and iptools.AddrInNet(ip, net):
|
||||||
d = {'nom' : nom,
|
d = {'nom' : nom,
|
||||||
'host' : nom.split(".", 1)[0],
|
'host' : nom.split(".", 1)[0],
|
||||||
'mac' : mac,
|
'mac' : mac,
|
||||||
'ip' : ip,
|
'ip' : ip,
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
hosts[net] += host_template % d
|
hosts[net] += host_template % d
|
||||||
except:
|
except:
|
||||||
hosts[net] = host_template % d
|
hosts[net] = host_template % d
|
||||||
animation.new_step()
|
animation.new_step()
|
||||||
# Put a \n after the last iteration.
|
# Put a \n after the last iteration.
|
||||||
animation.end()
|
animation.end()
|
||||||
|
|
||||||
step = "Enregistrement de la configuration dans les fichiers"
|
step = "Enregistrement de la configuration dans les fichiers"
|
||||||
affichage.prettyDoin(step, "...")
|
affichage.prettyDoin(step, "...")
|
||||||
for (net, fichier) in dhcp_config.reseaux.items():
|
for (net, fichier) in dhcp_config.reseaux.items():
|
||||||
with ConfFile(fichier) as configFile:
|
with ConfFile(fichier) as configFile:
|
||||||
configFile.header("#")
|
configFile.header("#")
|
||||||
if hosts.has_key(net):
|
if hosts.has_key(net):
|
||||||
configFile.write(hosts[net])
|
configFile.write(hosts[net])
|
||||||
|
affichage.prettyDoin(step, "Ok")
|
||||||
|
|
||||||
|
step = "Nettoyage des fichiers de leases"
|
||||||
|
affichage.prettyDoin(step, "...")
|
||||||
|
try:
|
||||||
|
lease_clean()
|
||||||
affichage.prettyDoin(step, "Ok")
|
affichage.prettyDoin(step, "Ok")
|
||||||
|
except:
|
||||||
|
affichage.prettyDoin(step, "Erreur")
|
||||||
|
print "During lease clean, an error occured."
|
||||||
|
raise
|
||||||
|
|
||||||
step = "Nettoyage des fichiers de leases"
|
|
||||||
affichage.prettyDoin(step, "...")
|
|
||||||
try:
|
|
||||||
cls.lease_clean()
|
|
||||||
affichage.prettyDoin(step, "Ok")
|
|
||||||
except:
|
|
||||||
affichage.prettyDoin(step, "Erreur")
|
|
||||||
print "During lease clean, an error occured."
|
|
||||||
raise
|
|
||||||
|
|
||||||
@classmethod
|
def add_dhcp_host(mac, ip, name=None):
|
||||||
def check_params(cls):
|
"""Adds a dhcp host using omapi
|
||||||
"""This method allows lazy evaluation for dhcp_omapi_keyname
|
|
||||||
and dhcp_omapi_key, since event imports all services. This is actually
|
|
||||||
the best lazy eval we can hope, since property won't work on
|
|
||||||
classmethods.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if cls.dhcp_omapi_keyname is None:
|
|
||||||
cls.dhcp_omapi_keyname = secrets_new.get("dhcp_omapi_keyname")
|
|
||||||
if cls.dhcp_omapi_key is None:
|
|
||||||
cls.dhcp_omapi_key = secrets_new.get("dhcp_omapi_keys")[hostname]
|
|
||||||
if cls.ldap_conn is None:
|
|
||||||
cls.ldap_conn = lc_ldap.shortcuts.lc_ldap_readonly()
|
|
||||||
|
|
||||||
@classmethod
|
if '<automatique>' in [ip, mac]:
|
||||||
def add_dhcp_host(cls, mac, ip, name=None):
|
return
|
||||||
"""Adds a dhcp host using omapi
|
msg = OmapiMessage.open(b"host")
|
||||||
|
msg.message.append((b"create", struct.pack("!I", 1)))
|
||||||
|
msg.message.append((b"exclusive", struct.pack("!I", 1)))
|
||||||
|
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
||||||
|
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
||||||
|
msg.obj.append((b"ip-address", pack_ip(ip)))
|
||||||
|
if name:
|
||||||
|
msg.obj.append((b"name", bytes(name)))
|
||||||
|
conn = Omapi(hostname_adm, 9991, dhcp_omapi_keyname, dhcp_omapi_key)
|
||||||
|
_ = conn.query_server(msg)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
"""
|
|
||||||
cls.check_params()
|
|
||||||
|
|
||||||
if '<automatique>' in [ip, mac]:
|
def delete_dhcp_host(mac, ip):
|
||||||
return
|
"""Deletes dhcp host using omapi
|
||||||
msg = OmapiMessage.open(b"host")
|
|
||||||
msg.message.append((b"create", struct.pack("!I", 1)))
|
|
||||||
msg.message.append((b"exclusive", struct.pack("!I", 1)))
|
|
||||||
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
|
||||||
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
|
||||||
msg.obj.append((b"ip-address", pack_ip(ip)))
|
|
||||||
if name:
|
|
||||||
msg.obj.append((b"name", bytes(name)))
|
|
||||||
conn = Omapi(hostname, 9991, cls.dhcp_omapi_keyname, cls.dhcp_omapi_key)
|
|
||||||
_ = conn.query_server(msg)
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
@classmethod
|
"""
|
||||||
def delete_dhcp_host(cls, mac, ip):
|
|
||||||
"""Deletes dhcp host using omapi
|
|
||||||
|
|
||||||
"""
|
if '<automatique>' in [ip, mac]:
|
||||||
cls.check_params()
|
return
|
||||||
|
msg = OmapiMessage.open(b"host")
|
||||||
|
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
||||||
|
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
||||||
|
msg.obj.append((b"ip-address", pack_ip(ip)))
|
||||||
|
conn = Omapi(hostname_adm, 9991, dhcp_omapi_keyname, dhcp_omapi_key)
|
||||||
|
response = conn.query_server(msg)
|
||||||
|
if response.opcode == OMAPI_OP_UPDATE:
|
||||||
|
_ = conn.query_server(OmapiMessage.delete(response.handle))
|
||||||
|
conn.close()
|
||||||
|
|
||||||
if '<automatique>' in [ip, mac]:
|
|
||||||
return
|
|
||||||
msg = OmapiMessage.open(b"host")
|
|
||||||
msg.obj.append((b"hardware-address", pack_mac(mac)))
|
|
||||||
msg.obj.append((b"hardware-type", struct.pack("!I", 1)))
|
|
||||||
msg.obj.append((b"ip-address", pack_ip(ip)))
|
|
||||||
conn = Omapi(hostname, 9991, cls.dhcp_omapi_keyname, cls.dhcp_omapi_key)
|
|
||||||
response = conn.query_server(msg)
|
|
||||||
if response.opcode == OMAPI_OP_UPDATE:
|
|
||||||
_ = conn.query_server(OmapiMessage.delete(response.handle))
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
@staticmethod
|
def lease_clean():
|
||||||
def lease_clean():
|
"""Clean the lease file
|
||||||
"""Clean the lease file
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO : use ConfigFile structure
|
# TODO : use ConfigFile structure
|
||||||
leasefile = open(dhcp_config.dhcplease)
|
leasefile = open(dhcp_config.dhcplease)
|
||||||
newleasefile = open(dhcp_config.dhcplease + '.new', 'w')
|
newleasefile = open(dhcp_config.dhcplease + '.new', 'w')
|
||||||
|
line = leasefile.readline()
|
||||||
|
write = True
|
||||||
|
while line:
|
||||||
|
if line.strip().startswith('host'):
|
||||||
|
write = False
|
||||||
|
if write:
|
||||||
|
newleasefile.write(line)
|
||||||
|
if not write and line.strip().endswith('}'):
|
||||||
|
write = True
|
||||||
line = leasefile.readline()
|
line = leasefile.readline()
|
||||||
write = True
|
leasefile.close()
|
||||||
while line:
|
newleasefile.close()
|
||||||
if line.strip().startswith('host'):
|
os.rename(dhcp_config.dhcplease+'.new', dhcp_config.dhcplease)
|
||||||
write = False
|
|
||||||
if write:
|
|
||||||
newleasefile.write(line)
|
|
||||||
if not write and line.strip().endswith('}'):
|
|
||||||
write = True
|
|
||||||
line = leasefile.readline()
|
|
||||||
leasefile.close()
|
|
||||||
newleasefile.close()
|
|
||||||
os.rename(dhcp_config.dhcplease+'.new', dhcp_config.dhcplease)
|
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,10 @@ import itertools
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import gestion.secrets_new as secrets
|
import gestion.secrets_new as secrets
|
||||||
|
|
||||||
# Trigger features
|
# Trigger features
|
||||||
import gestion.config.trigger as trigger_config
|
import gestion.config.trigger as trigger_config
|
||||||
from gestion.trigger.host import TriggerFactory
|
from gestion.trigger.host import TriggerFactory, record_service, record_parser
|
||||||
from gestion.trigger.services.service import BasicService
|
|
||||||
|
|
||||||
# Clogger
|
# Clogger
|
||||||
import cranslib.clogger as clogger
|
import cranslib.clogger as clogger
|
||||||
|
@ -32,7 +32,7 @@ import cranslib.clogger as clogger
|
||||||
# lc_ldap
|
# lc_ldap
|
||||||
import lc_ldap.attributs
|
import lc_ldap.attributs
|
||||||
|
|
||||||
logger = clogger.CLogger("trigger", "event", "debug", trigger_config.debug)
|
logger = clogger.CLogger("trigger", "event", trigger_config.log_level, trigger_config.debug)
|
||||||
|
|
||||||
services = []
|
services = []
|
||||||
for config_service in trigger_config.all_services:
|
for config_service in trigger_config.all_services:
|
||||||
|
@ -136,63 +136,52 @@ def compare_lists(list1, list2):
|
||||||
|
|
||||||
return moins, plus
|
return moins, plus
|
||||||
|
|
||||||
class Event(BasicService):
|
|
||||||
"""Event service class. It extends BasicService, but should not implement
|
@record_service
|
||||||
any change trigger, since it's this service which is designed to call
|
def event(body=()):
|
||||||
change triggers of other services.
|
"""When any event arrives on trigger-civet-event, this method is called
|
||||||
|
and designed to transcript the body (ldap data) in something usable for
|
||||||
|
the services. Afterwards, it sends these transcripts on the good way
|
||||||
|
using routing_key.
|
||||||
|
|
||||||
|
body is a 3-tuple, containing LDAP dn, the former state of the object
|
||||||
|
(a simple dict), and the later state. The data are non-binding-dependant.
|
||||||
|
|
||||||
|
A new object has body[1] to None, a deleted one has body[2] to None.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
logger.info("Received message %r…", body)
|
||||||
def get_changes(cls, body, diff):
|
|
||||||
"""Compute changes from diff"""
|
|
||||||
|
|
||||||
return [None]
|
diff = diff_o_matic(body)
|
||||||
|
|
||||||
@classmethod
|
# Now, diff is a dict containing attributes which has been modified.
|
||||||
def regen(cls, body=()):
|
# diff['macAddress'] could look like (['aa:bb:cc:dd:ee:fg'], ['aa:bb:cc:dd:ee:ff']),
|
||||||
"""When any event arrives on trigger-civet-event, this method is called
|
# where the list on the left is the former value of attributes, and the list on the
|
||||||
and designed to transcript the body (ldap data) in something usable for
|
# right the latter values.
|
||||||
the services. Afterwards, it sends these transcripts on the good way
|
|
||||||
using routing_key.
|
|
||||||
|
|
||||||
body is a 3-tuple, containing LDAP dn, the former state of the object
|
# -*- Explain -*-
|
||||||
(a simple dict), and the later state. The data are non-binding-dependant.
|
#In [11]: import itertools
|
||||||
|
#
|
||||||
|
#In [12]: a = [[(3, 'lol'), ('7', 3)], [(5, 6), None], [None], [('lol', 'lal')]]
|
||||||
|
#
|
||||||
|
#In [13]: a
|
||||||
|
#Out[13]: [[(3, 'lol'), ('7', 3)], [(5, 6), None], [None], [('lol', 'lal')]]
|
||||||
|
#
|
||||||
|
#In [14]: list(set([message for message in itertools.chain(*a)]))
|
||||||
|
#Out[14]: [('7', 3), (5, 6), None, ('lol', 'lal'), (3, 'lol')] # Only one None from a, since [None, x, y, None] is equivalent for itertools to [x, y]
|
||||||
|
#
|
||||||
|
#In [15]: b = list(set([message for message in itertools.chain(*a) if message is not None]))
|
||||||
|
#
|
||||||
|
#In [16]: b
|
||||||
|
#Out[16]: [('7', 3), (5, 6), ('lol', 'lal'), (3, 'lol')]
|
||||||
|
functions = list(set([function for function in itertools.chain(*[TriggerFactory.get_parser(key) for key in diff])]))
|
||||||
|
msg_to_send = [function(body, diff) for function in functions]
|
||||||
|
|
||||||
A new object has body[1] to None, a deleted one has body[2] to None.
|
for msg in msg_to_send:
|
||||||
|
logger.info("Sending %r on the road \\o/", msg)
|
||||||
"""
|
# XXX - uncomment this when in production
|
||||||
|
trigger_send(*msg)
|
||||||
logger.info("Received message %r…", body)
|
|
||||||
|
|
||||||
diff = diff_o_matic(body)
|
|
||||||
|
|
||||||
# Now, diff is a dict containing attributes which has been modified.
|
|
||||||
# diff['macAddress'] could look like (['aa:bb:cc:dd:ee:fg'], ['aa:bb:cc:dd:ee:ff']),
|
|
||||||
# where the list on the left is the former value of attributes, and the list on the
|
|
||||||
# right the latter values.
|
|
||||||
|
|
||||||
# -*- Explain -*-
|
|
||||||
#In [11]: import itertools
|
|
||||||
#
|
|
||||||
#In [12]: a = [[(3, 'lol'), ('7', 3)], [(5, 6), None], [None], [('lol', 'lal')]]
|
|
||||||
#
|
|
||||||
#In [13]: a
|
|
||||||
#Out[13]: [[(3, 'lol'), ('7', 3)], [(5, 6), None], [None], [('lol', 'lal')]]
|
|
||||||
#
|
|
||||||
#In [14]: list(set([message for message in itertools.chain(*a)]))
|
|
||||||
#Out[14]: [('7', 3), (5, 6), None, ('lol', 'lal'), (3, 'lol')] # Only one None from a, since [None, x, y, None] is equivalent for itertools to [x, y]
|
|
||||||
#
|
|
||||||
#In [15]: b = list(set([message for message in itertools.chain(*a) if message is not None]))
|
|
||||||
#
|
|
||||||
#In [16]: b
|
|
||||||
#Out[16]: [('7', 3), (5, 6), ('lol', 'lal'), (3, 'lol')]
|
|
||||||
msg_to_send = [message for message in itertools.chain(*[service.get_changes(body, diff) for service in TriggerFactory.get_services()]) if message is not None]
|
|
||||||
|
|
||||||
for msg in msg_to_send:
|
|
||||||
logger.info("Sending %r on the road \\o/", msg)
|
|
||||||
# XXX - uncomment this when in production
|
|
||||||
# trigger_send(*msg)
|
|
||||||
|
|
||||||
def trigger_send(routing_key, body):
|
def trigger_send(routing_key, body):
|
||||||
sender = EventProducer("civet")
|
sender = EventProducer("civet")
|
||||||
|
|
|
@ -16,67 +16,75 @@ it to regenerate what needs to.
|
||||||
|
|
||||||
import cranslib.clogger as clogger
|
import cranslib.clogger as clogger
|
||||||
import gestion.config.trigger as trigger_config
|
import gestion.config.trigger as trigger_config
|
||||||
logger = clogger.CLogger("trigger", "firewall", "debug", trigger_config.debug)
|
logger = clogger.CLogger("trigger", "firewall", trigger_config.log_level, trigger_config.debug)
|
||||||
|
|
||||||
import lc_ldap.shortcuts
|
import lc_ldap.shortcuts
|
||||||
|
|
||||||
from gestion.trigger.services.service import BasicService
|
from gestion.trigger.host import record_service, record_parser
|
||||||
import gestion.trigger.firewall4.firewall4 as firewall4
|
import gestion.trigger.firewall4.firewall4 as firewall4
|
||||||
|
|
||||||
class Firewall(BasicService):
|
class FwFactory(object):
|
||||||
"""Firewall service that handles any modification in the firewall.
|
"""Records firewall functions, and provide them.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Class lookup table to define which changes call which function.
|
_fwfuns = {}
|
||||||
changes_trigger = {
|
|
||||||
lc_ldap.attributs.macAddress.ldap_name: ('send_mac_ip',),
|
|
||||||
lc_ldap.attributs.ipHostNumber.ldap_name: ('send_mac_ip',),
|
|
||||||
}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def send_mac_ip(cls, body, diff):
|
def register(cls, key, value):
|
||||||
"""Computes mac_ip data to send from body and diff
|
cls._fwfuns[key] = value
|
||||||
|
|
||||||
"""
|
|
||||||
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)])
|
|
||||||
|
|
||||||
# Mise à jour du parefeu mac_ip
|
|
||||||
if not macs[0]:
|
|
||||||
# Création d'une nouvelle machine.
|
|
||||||
fw = {'add': [(macs[1], ips[1])]}
|
|
||||||
elif not macs[1]:
|
|
||||||
# Destruction d'une machine.
|
|
||||||
fw = {'delete': [(macs[0], ips[0])]}
|
|
||||||
else:
|
|
||||||
# Mise à jour.
|
|
||||||
fw = {'update': [(macs[0], ips[0], macs[1], ips[1])]}
|
|
||||||
return ("firewall", ("mac_ip", fw))
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def regen(cls, body=()):
|
def get(cls, key):
|
||||||
"""Regens the specific service
|
return cls._fwfuns.get(key, None)
|
||||||
|
|
||||||
"""
|
def fwrecord(fun):
|
||||||
if len(body) != 2:
|
FwFactory.register(fun.func_name, fun)
|
||||||
logger.warning("Received body %r, this format is incorrect, discarding.", body)
|
|
||||||
return
|
|
||||||
(service, data) = body
|
|
||||||
logger.info("Calling service %s for data %r", service, data)
|
|
||||||
getattr(cls, service)(data)
|
|
||||||
|
|
||||||
@classmethod
|
@record_parser(lc_ldap.attributs.macAddress.ldap_name, lc_ldap.attributs.ipHostNumber.ldap_name)
|
||||||
def mac_ip(cls, body):
|
def send_mac_ip(body, diff):
|
||||||
host_fw = firewall4.firewall()
|
"""Computes mac_ip data to send from body and diff
|
||||||
if body and isinstance(body, dict):
|
|
||||||
for (mac, ip) in body.get("add", []):
|
"""
|
||||||
logger.info("Adding mac_ip %s,%s", mac, ip)
|
macs = tuple([body[i].get(lc_ldap.attributs.macAddress.ldap_name, [''])[0] for i in xrange(1, 3)])
|
||||||
host_fw.mac_ip_append(mac, ip)
|
ips = tuple([body[i].get(lc_ldap.attributs.ipHostNumber.ldap_name, [''])[0] for i in xrange(1, 3)])
|
||||||
for (mac, ip) in body.get("delete", []):
|
|
||||||
logger.info("Removing mac_ip %s,%s", mac, ip)
|
# Mise à jour du parefeu mac_ip
|
||||||
host_fw.mac_ip_remove(mac, ip)
|
if not macs[0]:
|
||||||
for (rmac, rip, mac, ip) in body.get("update", []):
|
# Création d'une nouvelle machine.
|
||||||
logger.info("Updating mac_ip %s,%s with %s,%s", rmac, rip, mac, ip)
|
fw = {'add': [(macs[1], ips[1])]}
|
||||||
host_fw.mac_ip_remove(rmac, rip)
|
elif not macs[1]:
|
||||||
host_fw.mac_ip_append(mac, ip)
|
# Destruction d'une machine.
|
||||||
|
fw = {'delete': [(macs[0], ips[0])]}
|
||||||
|
else:
|
||||||
|
# Mise à jour.
|
||||||
|
fw = {'update': [(macs[0], ips[0], macs[1], ips[1])]}
|
||||||
|
return ("firewall", ("mac_ip", fw))
|
||||||
|
|
||||||
|
@record_service
|
||||||
|
def firewall(body=()):
|
||||||
|
"""Regens the specific service
|
||||||
|
|
||||||
|
"""
|
||||||
|
if len(body) != 2:
|
||||||
|
logger.warning("Received body %r, this format is incorrect, discarding.", body)
|
||||||
|
return
|
||||||
|
(service, data) = body
|
||||||
|
logger.info("Calling service %s for data %r", service, data)
|
||||||
|
# XXX - Uncomment when in prod
|
||||||
|
#FwFactory.get(service)(data)
|
||||||
|
|
||||||
|
@fwrecord
|
||||||
|
def mac_ip(body):
|
||||||
|
host_fw = firewall4.firewall()
|
||||||
|
if body and isinstance(body, dict):
|
||||||
|
for (mac, ip) in body.get("add", []):
|
||||||
|
logger.info("Adding mac_ip %s,%s", mac, ip)
|
||||||
|
host_fw.mac_ip_append(mac, ip)
|
||||||
|
for (mac, ip) in body.get("delete", []):
|
||||||
|
logger.info("Removing mac_ip %s,%s", mac, ip)
|
||||||
|
host_fw.mac_ip_remove(mac, ip)
|
||||||
|
for (rmac, rip, mac, ip) in body.get("update", []):
|
||||||
|
logger.info("Updating mac_ip %s,%s with %s,%s", rmac, rip, mac, ip)
|
||||||
|
host_fw.mac_ip_remove(rmac, rip)
|
||||||
|
host_fw.mac_ip_append(mac, ip)
|
||||||
|
|
|
@ -20,12 +20,12 @@ import pika
|
||||||
import gestion.secrets_new as secrets
|
import gestion.secrets_new as secrets
|
||||||
import gestion.config.trigger as trigger_config
|
import gestion.config.trigger as trigger_config
|
||||||
import gestion.affichage as affichage
|
import gestion.affichage as affichage
|
||||||
from gestion.trigger.host import trigger
|
from gestion.trigger.host import trigger_service
|
||||||
import cranslib.clogger as clogger
|
import cranslib.clogger as clogger
|
||||||
import cmb
|
import cmb
|
||||||
|
|
||||||
hostname = socket.gethostname().split(".")[0]
|
hostname = socket.gethostname().split(".")[0]
|
||||||
logger = clogger.CLogger("trigger", "trigger", "info", trigger_config.debug)
|
logger = clogger.CLogger("trigger", "trigger", trigger_config.log_level, trigger_config.debug)
|
||||||
|
|
||||||
# Ce bloc contient le peu de "magie" de la librairie, on utilise les services listés dans config/trigger.py
|
# Ce bloc contient le peu de "magie" de la librairie, on utilise les services listés dans config/trigger.py
|
||||||
# comme référence. Pour éviter toute redondance, la commande importe donc les services utiles suivant cette
|
# comme référence. Pour éviter toute redondance, la commande importe donc les services utiles suivant cette
|
||||||
|
@ -70,7 +70,7 @@ class EvenementListener(cmb.AsynchronousConsumer):
|
||||||
# about contient le nom de la fonction à appeler, body lui est filé en argument.
|
# about contient le nom de la fonction à appeler, body lui est filé en argument.
|
||||||
try:
|
try:
|
||||||
if about in trigger_config.services[hostname]:
|
if about in trigger_config.services[hostname]:
|
||||||
trigger(about).regen(body)
|
trigger_service(about)(body)
|
||||||
else:
|
else:
|
||||||
raise AttributeError
|
raise AttributeError
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -122,7 +122,7 @@ if __name__ == '__main__':
|
||||||
for host_service in trigger_config.services[hostname]:
|
for host_service in trigger_config.services[hostname]:
|
||||||
try:
|
try:
|
||||||
print affichage.style(" (Ré)Génération du service %s" % (host_service,), "cyan")
|
print affichage.style(" (Ré)Génération du service %s" % (host_service,), "cyan")
|
||||||
trigger(host_service).regen(True)
|
trigger_service(host_service)(True)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
print "No suitable trigger handle found for service %s on host %s" % (host_service, hostname)
|
print "No suitable trigger handle found for service %s on host %s" % (host_service, hostname)
|
||||||
elif args.daemon:
|
elif args.daemon:
|
||||||
|
@ -133,4 +133,4 @@ if __name__ == '__main__':
|
||||||
for arg_service in trigger_config.services[hostname]:
|
for arg_service in trigger_config.services[hostname]:
|
||||||
if getattr(args, arg_service, False) == True:
|
if getattr(args, arg_service, False) == True:
|
||||||
print affichage.style(" (Ré)Génération du service %s" % (arg_service,), "cyan")
|
print affichage.style(" (Ré)Génération du service %s" % (arg_service,), "cyan")
|
||||||
trigger(arg_service).regen(True)
|
trigger_service(arg_service)(True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue