From 08892ae5ef9269f37caed8a4ef9fa6d75e34f663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pierre-Elliott=20B=C3=A9cue?= Date: Wed, 30 Apr 2014 21:41:29 +0200 Subject: [PATCH] [trigger/dhcp] Gestion du dhcp, et mise en place des services pour isc et dhcp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Travail basé sur dhcpd_new --- gestion/config/dhcp.py | 20 +++++ gestion/trigger/dhcp.py | 152 +++++++++++++++++++++++++++++++++ gestion/trigger/hosts/dhcp.py | 5 ++ gestion/trigger/hosts/isc.py | 1 + gestion/trigger/pypureomapi.py | 1 + 5 files changed, 179 insertions(+) create mode 100644 gestion/config/dhcp.py create mode 100644 gestion/trigger/dhcp.py create mode 100644 gestion/trigger/hosts/dhcp.py create mode 120000 gestion/trigger/hosts/isc.py create mode 120000 gestion/trigger/pypureomapi.py diff --git a/gestion/config/dhcp.py b/gestion/config/dhcp.py new file mode 100644 index 00000000..64933892 --- /dev/null +++ b/gestion/config/dhcp.py @@ -0,0 +1,20 @@ +# Serveurs dhcp autoritaires +authoritative = ["dhcp", "isc"] + +# Fichier de leases +dhcplease = '/var/lib/dhcp/dhcpd.leases' + +# Zones (couple zone IP, fichier des correspondandes MAC/IP) +reseaux = { '138.231.136.0/21' : '/etc/dhcp3/generated/adherents.liste.test', + '10.42.0.0/16' : '/etc/dhcp3/generated/gratuit.liste.test', + '10.2.9.0/24' : '/etc/dhcp3/generated/appartements.liste.test', + '138.231.144.0/21' : '/etc/dhcp3/generated/wifi.liste.test' } + +# Commande de serveur +server_cmd = "service isc-dhcp-server" + +# Options pour la commande +start = "start" +stop = "stop" +restart = "restart" +reload = "reload" diff --git a/gestion/trigger/dhcp.py b/gestion/trigger/dhcp.py new file mode 100644 index 00000000..b469ab02 --- /dev/null +++ b/gestion/trigger/dhcp.py @@ -0,0 +1,152 @@ +#!/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 + +import lc_ldap.shortcuts +from gestion.trigger.host import TriggerFactory, record +from cranslib.conffile import ConfFile +import cranslib.clogger as clogger +import gestion.config.dhcp as dhcp_config +import gestion.secrets_new as secrets_new +import socket +import gestion.affichage as affichage +import os +import sys +import gestion.iptools as iptools + +from pypureomapi import pack_ip, pack_mac, OMAPI_OP_UPDATE +from pypureomapi import Omapi, OmapiMessage, OmapiError, OmapiErrorNotFound +import struct + +logger = clogger.CLogger("trigger.dhcp", "debug") +hostname = socket.gethostname().split(".")[0] + ".adm.crans.org" +dhcp_omapi_keyname = secrets_new.get("dhcp_omapi_keyname") +dhcp_omapi_key = secrets_new.get("dhcp_omapi_keys")[hostname] +ldap_conn = lc_ldap.shortcuts.lc_ldap_readonly() + +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, 9991, dhcp_omapi_keyname, dhcp_omapi_key) + response = conn.query_server(msg) + conn.close() + +def delete_dhcp_host(self, 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, 9991, dhcp_omapi_keyname, dhcp_omapi_key) + response = conn.query_server(msg) + if response.opcode == OMAPI_OP_UPDATE: + response = 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') + config = "" + 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) + +@record +def dhcp(body={}): + """Regenerates dhcp service taking body into account. + + """ + if body and isinstance(body, dict): + for (mac, ip, name) in body.get("add", []): + add_dhcp_host(mac, ip, name) + for (mac, ip) in body.get("delete", []): + delete_dhcp_host(mac, ip) + for (rmac, rip, mac, ip, name) in body.get("update", []): + 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 diff --git a/gestion/trigger/hosts/dhcp.py b/gestion/trigger/hosts/dhcp.py new file mode 100644 index 00000000..09ea1a11 --- /dev/null +++ b/gestion/trigger/hosts/dhcp.py @@ -0,0 +1,5 @@ +#!/bin/bash /usr/scripts/python.sh +# -*- coding: utf-8 -*- + +from gestion.trigger.dhcp import dhcp +from gestion.trigger.host import trigger diff --git a/gestion/trigger/hosts/isc.py b/gestion/trigger/hosts/isc.py new file mode 120000 index 00000000..c12c5757 --- /dev/null +++ b/gestion/trigger/hosts/isc.py @@ -0,0 +1 @@ +dhcp.py \ No newline at end of file diff --git a/gestion/trigger/pypureomapi.py b/gestion/trigger/pypureomapi.py new file mode 120000 index 00000000..8575f0fc --- /dev/null +++ b/gestion/trigger/pypureomapi.py @@ -0,0 +1 @@ +../gen_confs/pypureomapi.py \ No newline at end of file