scripts/gestion/trigger/services/dhcp.py
2015-03-10 16:41:49 +01:00

182 lines
6.2 KiB
Python

#!/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 <becue@crans.org>
# 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 '<automatique>' 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 '<automatique>' 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 '<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_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)