#!/bin/bash /usr/scripts/python.sh # -*- coding: utf-8 -*- # # DHCP common stuff # Based on work from Frédéric Pauget and Valentin Samir # # Author : Pierre-Elliott Bécue # Licence : GPLv3 # Date : 14/07/2014 # # TODO : Take care of each XXX or TODO and think about updating # gestion/config/dhcp when submitting for production, because # of .test files. import socket import os import struct import gestion.config.trigger as trigger_config import cranslib.clogger as clogger logger = clogger.CLogger("trigger", "dhcp", trigger_config.log_level, trigger_config.debug) hostname = socket.gethostname().split(".")[0] hostname_adm = hostname + ".adm.crans.org" import lc_ldap.shortcuts from cranslib.conffile import ConfFile import gestion.config.dhcp as dhcp_config import gestion.secrets_new as secrets_new import gestion.affichage as affichage import gestion.iptools as iptools from gestion.trigger.pypureomapi import pack_ip, pack_mac, OMAPI_OP_UPDATE, Omapi, OmapiMessage from gestion.trigger.host import record_service 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_key = None ldap_conn = None @record_service def dhcp(ob_id, body=None): """Regenerates dhcp service taking body into account. """ # http://satyajit.ranjeev.in/2012/01/12/python--dangerous-default-value-as-argument.html # dict are referenced. if body is None: body = {} if body and isinstance(body, dict): for (mac, ip, name) in body.get("add", []): logger.info("Updating DHCP db by adding %s, %s, %s", mac, ip, name) # XXX - Uncommend this when we need to start prod # add_dhcp_host(mac, ip, name) for (mac, ip) in body.get("delete", []): logger.info("Updating DHCP db by deleting %s, %s", mac, ip) # XXX - Uncommend this when we need to start prod # delete_dhcp_host(mac, ip) 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) # XXX - Uncommend this when we need to start prod # delete_dhcp_host(rmac, rip) # add_dhcp_host(mac, ip, name) elif body == True: hosts = {} host_template = """ host %(nom)s { hardware ethernet %(mac)s; fixed-address %(ip)s; option host-name "%(host)s"; } """ affichage.prettyDoin("Chargement des machines", "...") machines = ldap_conn.allMachines() affichage.prettyDoin("Chargement des machines", "Ok") animation = affichage.Animation(texte="Génération de la configuration", nb_cycles=len(machines), couleur=True, kikoo=True) for machine in machines: for net in dhcp_config.reseaux.keys(): ip = str(machine['ipHostNumber'][0]) mac = str(machine['macAddress'][0]) nom = str(machine['host'][0]) if '' not in [ip, mac] and iptools.AddrInNet(ip, net): d = {'nom' : nom, 'host' : nom.split(".", 1)[0], 'mac' : mac, 'ip' : ip, } try: hosts[net] += host_template % d except: hosts[net] = host_template % d animation.new_step() # Put a \n after the last iteration. animation.end() step = "Enregistrement de la configuration dans les fichiers" affichage.prettyDoin(step, "...") for (net, fichier) in dhcp_config.reseaux.items(): with ConfFile(fichier) as configFile: configFile.header("#") if hosts.has_key(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") except: affichage.prettyDoin(step, "Erreur") print "During lease clean, an error occured." raise def add_dhcp_host(mac, ip, name=None): """Adds a dhcp host using omapi """ if '' in [ip, mac]: return 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() def delete_dhcp_host(mac, ip): """Deletes dhcp host using omapi """ if '' 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_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() def lease_clean(): """Clean the lease file """ # TODO : use ConfigFile structure leasefile = open(dhcp_config.dhcplease) 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() leasefile.close() newleasefile.close() os.rename(dhcp_config.dhcplease+'.new', dhcp_config.dhcplease)