Import initial !

darcs-hash:20040831131446-d1718-0734aa73d3b8481b3b4b861e447e85128e488e8a.gz
This commit is contained in:
bernat 2004-08-31 15:14:46 +02:00
parent c9083dfd86
commit 6626a44f15
20 changed files with 6494 additions and 0 deletions

140
gestion/gen_confs/__init__.py Executable file
View file

@ -0,0 +1,140 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Package pour la génération des fichiers de conf
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
import sys, os, signal
sys.path.append('/usr/scripts/gestion')
import time, commands
from affich_tools import *
from lock import *
import config
from tempfile import NamedTemporaryFile
# Notes snmp
oid = '.1.3.6.1.4.1.2021.255'
try :
if sys.argv[1] == '-s' and sys.argv[2] == oid :
service = sys.argv[4].strip().strip('"')
except :
None
# Fin notes snmp
class gen_config :
""" Base pour toutes les classes de génération de fichiers de conf """
base = None
ann_scol = config.ann_scol
debug = 0
_locked = 0
__restore={} # pour restorer la config d'origine en cas d'erreur de génération
def lock(self) :
""" Lock le service courant """
if not self._locked :
make_lock(str(self.__class__),'')
self._locked = 1
def unlock(self) :
""" Supression du lock """
if self._locked : remove_lock(str(self.__class__))
def __del__(self) :
# Au cas où...
self.unlock()
def _restore(self) :
""" Affichage d'une erreur et du traceback si debug
Puis restauration des fichers """
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
# Restauration
for nom, f in self.__restore.items() :
os.system('cp -f %s %s' % ( f.name, nom ) )
def _open_conf(self,nom,comment=None) :
""" Créé un fichier
si comment est fourni, insère une entète qui utilisera le caractère
de commentaire fourni
copie l'ancien fichier dans un fichier temporaire pour permettre
la restauration en cas d'échec de la configuration
Retourne le descripteur du fichier """
f = NamedTemporaryFile()
os.system('cp %s %s 2> /dev/null' % ( nom, f.name ) )
self.__restore[nom] = f
fd = open(nom, 'w')
if comment :
e = """***********************************************************
Ce fichier est généré par les scripts de %s
Les données proviennent de la base LDAP et de la conf
présente au début du script.
Génération : %s
Fichier : %s
NE PAS EDITER
***********************************************************""" % \
(__name__, nom, time.strftime('%A %d %B %Y %H:%M') )
e = comment + e.replace('\n', '\n%s' % comment) + '\n'
fd.write(e)
return fd
def gen_conf(self) :
""" Génération des fichiers de conf, retourne 1 si erreur """
self.lock()
self.anim = anim('\tgénération fichiers')
try :
warn = self._gen()
if warn :
self.anim.reinit()
print WARNING
if self.debug : sys.stderr.write(warn.encode("ISO-8859-15"))
else :
self.anim.reinit()
print OK
self.unlock()
except :
self.anim.reinit()
self._restore()
self.unlock()
return 1
def restart(self) :
""" Redémarrage du service concerné """
self.lock()
self.anim = anim('\trestart')
status, output = commands.getstatusoutput(self.restart_cmd)
if status :
self.anim.reinit()
print ERREUR
if self.debug :
sys.stderr.write(output+'\n')
self.unlock()
return 1
else :
print OK
self.unlock()
def reconfigure(self) :
""" Génère les fichiers puis redémarre le service
si la génération c'est bien passée """
cprint('Reconfiguration %s :' % self.__str__() , 'gras')
if not self.gen_conf() :
return self.restart()
else : return 1

186
gestion/gen_confs/bind.py Executable file
View file

@ -0,0 +1,186 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Génération de la configuration pour bind9
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
# TODO :
# verif si SOA zamok.crans.org bon partout
# verif si liste NS identiques partout ok
# traitement warnings
import time, sre
from gen_confs import gen_config
class dns(gen_config) :
"""
Génération des fichiers de configuration de bind9 :
* fichier DNS_CONF qui contient les définitions de zone conformément
à zone_template. Ce fichier doit être inclus à partir de la config statique
de bind
* les fichiers de zones, ce sont eux qui contiennent les données du
dns, ils ont appellés par le fichier DNS_CONF et sont générés dans DNS_DIR
Leur entète est générée à partir de zone_entete.
Les fichiers générés placent bind comme autoritaire sur les noms de
zones_direct et les adresses de zones_reverse. Les données proviennent de
la base LDAP
"""
######################################PARTIE DE CONFIGURATION
### Fichiers à écrire
# Répertoire d'écriture des fichiers de zone
DNS_DIR='/etc/bind/generated/' # Avec un / à la fin
# Fichier de définition des zones
DNS_CONF=DNS_DIR + 'zones_crans'
### Sur quelles zones on a autorité ?
# Résolution directe
zones_direct = [ 'crans.org' , 'crans.ens-cachan.fr', 'wifi.crans.org' ]
# Résolution inverse (regexp pour définir les débuts des IP correspondantes)
zones_reverse = sre.compile('^138\.231\.1(3[6-9]|4[0-9]|5[01])') # 138.231.136.0 à 138.231.151.255
### Liste DNS
# Le premier est doit être le maitre
DNSs = [ 'zamok.crans.org' , 'sila.crans.org' , 'freebox.crans.org' ]
### Serveurs de mail
# format : [ priorité serveur , .... ]
MXs = ['10 zamok.crans.org', '20 freebox.crans.org' ]
### Entète des fichiers de zone
zone_entete="""
$ORIGIN %(zone)s.
$TTL 86400
@\tIN\tSOA zamok.crans.org. root.crans.org. (
%(serial)i ; numero de serie
21600 ; refresh (s)
3600 ; retry (s)
1209600 ; expire (s)
86400 ; TTL (s)
)
"""
# Syntaxe utilisée dans le fichier DNS_CONF pour définir une zone
zone_template="""
zone "%(NOM_zone)s" {
type master;
file "%(FICHIER_zone)s";
};
"""
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement contre les machines ne pouvant être classées
verbose = 1
restart_cmd = '/etc/init.d/bind9 reload'
######################################FIN PARTIE DE CONFIGURATION
def __str__(self) :
return "DNS"
def _gen(self) :
### Génération du numéro de série
# Le + 1000.... s'explique pas l'idée précédente et peu pratique d'avoir
# le numéro de série du type AAAAMMJJNN (année, mois, jour, incrément par jour)
serial = time.time() + 1000000000
### DNS
DNS='; DNS de la zone par ordre de priorité\n'
for d in self.DNSs :
DNS += '@\tIN\tNS %s.\n' % d
DNS += '\n'
### Serveurs de mail
MX='; Serveurs de mails\n'
for m in self.MXs :
MX += '%(zone)s.\t' # Sera remplacé par le nom de zone plus tard
MX += 'IN\tMX\t%s.\n' % m
MX += '\n'
### Tri des machines
direct = {} # format : { zone : [ lignes correspondantes] }
reverse = {}
warnings = ''
self.anim.iter=len(self.machines)
for machine in self.machines :
self.anim.cycle()
# Calculs préliminaires
try :
nom , zone = machine.nom().split('.',1)
zone = zone.encode('iso-8859-1')
except :
warnings += u'Machine ignorée (mid=%s) : format nom incorrect (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.nom().encode('iso-8859-1') )
continue
# Le direct
if zone in self.zones_direct :
ligne = "%s\tIN\tA\t%s\n" % ( nom, machine.ip() )
try : direct[zone] += ligne
except : direct[zone] = ligne
elif self.verbose :
warnings += u'Résolution directe ignorée (mid=%s) : zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), zone.encode('iso-8859-1') )
# Le direct avec alias
for alias in machine.alias() :
# Bon format ?
alias_l = alias.split('.')
ok = 0
for i in range(len(alias_l)) :
zone_essai = '.'.join(alias_l[i:])
if zone_essai in self.zones_direct :
# On est autoritaire sur cette zone
# On place donc l'alias dans le fichier de cette zone
zone = zone_essai
nom = '.'.join(alias_l[:i])
ok = 1
break
if not ok :
warnings += u'Alias ignoré (mid=%s) : %s\n' % ( machine.id().encode('iso-8859-1'), alias.encode('iso-8859-1') )
continue
zone = zone.encode('iso-8859-1')
ligne = "%s\tIN\tCNAME\t%s.\n" % ( nom, machine.nom() )
try : direct[zone] += ligne
except : direct[zone] = ligne
# Le reverse
if self.zones_reverse.match(machine.ip()) :
base_ip = machine.ip().split('.')
base_ip.reverse()
zone = "%s.%s.%s.in-addr.arpa" % tuple(base_ip[1:])
zone = zone.encode('iso-8859-1')
ligne = '%s\tIN\tPTR\t%s.\n' % (base_ip[0],machine.nom())
try : reverse[zone] += ligne
except : reverse[zone] = ligne
elif self.verbose :
warnings += u'Résolution inverse ignorée (mid=%s) : ip sur zone non autoritaire (%s)\n' % ( machine.id().encode('iso-8859-1'), machine.ip().encode('iso-8859-1') )
### Ajouts pour les fichiers de résolution directs
for zone in direct.keys() :
# MXs
direct[zone] = MX % { 'zone' : zone } + direct[zone]
### Ecriture des fichiers de zone et préparation du fichier de définition
f = ''
for zone, lignes in direct.items() + reverse.items() :
file = self.DNS_DIR + 'db.' + zone
fd = self._open_conf(file,';')
fd.write(self.zone_entete % \
{ 'zone' : zone, 'serveur_autoritaire' : self.DNSs[0] , 'serial' : serial } )
fd.write('\n')
fd.write(DNS)
fd.write(lignes)
fd.close()
f += self.zone_template % { 'NOM_zone' : zone, 'FICHIER_zone' : file }
### Ecriture fichier de définition
fd = self._open_conf(self.DNS_CONF,'//')
fd.write(f)
fd.close()
return warnings

View file

@ -0,0 +1,42 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
from firewall import bl_upload_fw
from squid import bl_upload_squid
class bl_upload :
""" Classe d'interface avec les classes spécifiques des
opération de configuration pour upload """
debug = 0
description = u'Bloquage de toute communiquation vers l\'extérieur.'
def __str__(self) :
return "blackliste upload"
def __init__(self) :
self.fw = bl_upload_fw()
self.squid = bl_upload_squid()
def __set(self) :
""" Attribution des proprietes des differentes classes """
self.fw.base = self.base
self.fw.debug = self.debug
self.squid.base = self.base
self.squid.debug = self.debug
def reconfigure(self) :
self.__set()
self.fw.reconfigure()
self.squid.reconfigure()
def restart(self) :
self.__set()
self.fw.restart()
self.squid.restart()
def gen_conf(self) :
self.__set()
self.fw.gen_conf()
self.squid.gen_conf()

115
gestion/gen_confs/dhcpd.py Executable file
View file

@ -0,0 +1,115 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Génération de la configuration pour le dhcp
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
from iptools import AddrInNet, param
from gen_confs import gen_config
class dhcp(gen_config) :
""" Génération du fichier de configuration pour dhcpd (DHCPD_CONF)
Le fichier comporte une partie par réseau servi, chaque réseau
servi doit être une clef du dictionnaire reseaux, la valeur correspondante
est une chaine décrivant les options spécifiques à ce réseau.
Les options communes sont celles de base_dhcp.
Chaque machines possède ensuite une entrée de la forme de host_template
"""
######################################PARTIE DE CONFIGURATION
# Fichier à écire
DHCPD_CONF='/etc/dhcpd.conf'
# Réseaux servis avec leurs options spécifiques
reseaux = { '138.231.136.0/21' :
"""option routers 138.231.136.4;
option domain-name-servers 138.231.136.6, 138.231.136.10, 138.231.136.9;
option domain-name "crans.org";
option option-119 "crans.org wifi.crans.org";""",
'138.231.148.0/22' :
"""option routers 138.231.148.1;
option domain-name-servers 138.231.148.1;
option domain-name "wifi.crans.org";
option option-119 "wifi.crans.org crans.org";"""
}
# Options communes à toutes les réseaux servis
base_dhcp="""
subnet %(network)s netmask %(netmask)s {
default-lease-time 86400;
option subnet-mask %(netmask)s;
option broadcast-address %(broadcast)s;
%(OPTIONS_RESEAU)s
option time-servers 138.231.136.6;
option ntp-servers 138.231.136.6;
option smtp-server 138.231.136.6;
option netbios-name-servers 138.231.136.6;
option netbios-dd-server 138.231.136.6;
option netbios-node-type 8;
option ip-forwarding off;
option option-252 "http://www.crans.org/proxy.pac" ;
deny unknown-clients;
not authoritative;
%(HOSTs)s
}
"""
host_template="""
host %(nom)s {
hardware ethernet %(mac)s;
fixed-address %(ip)s;
option host-name "%(nom)s";
}
"""
### Verbosité
# Si =1 ralera (chaine warnings) si machines hors zone trouvée
# Si =0 ralera seulement si réseau vide
verbose = 1
restart_cmd = '/etc/init.d/dhcp restart'
######################################FIN PARTIE DE CONFIGURATION
def __str__(self) :
return 'dhcp'
def _gen(self) :
warnings =''
### Construction de la partie du fichier contenant les machines
hosts={}
self.anim.iter=len(self.machines)
for machine in self.machines :
self.anim.cycle()
t = 0
for net in self.reseaux.keys() :
if AddrInNet(machine.ip(),net) :
d = { 'nom' : machine.nom().split('.')[0] , 'mac' : machine.mac() , 'ip' : machine.ip() }
try : hosts[net] += self.host_template % d
except : hosts[net] = self.host_template % d
t = 1
if not t and self.verbose :
warnings += u'Machine ignorée (mid=%s) : ip en dehors des réseaux servis (%s)\n' % ( machine.id(), machine.ip() )
### Ecriture du fichier
fd = self._open_conf(self.DHCPD_CONF,'#')
for net, options in self.reseaux.items() :
if not hosts.has_key(net) :
warnings += u'Réseau %s ignoré : aucune machine à servir\n' % net
continue
d = param(net)
d['OPTIONS_RESEAU'] = options
d['HOSTs'] = hosts[net]
fd.write(self.base_dhcp % d)
fd.close()
return warnings

80
gestion/gen_confs/droits.py Executable file
View file

@ -0,0 +1,80 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
import sys, signal
from gen_confs import gen_config, anim, cprint, OK, ERREUR
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, crans, ann_scol, preattr, ldap
class droits(crans_ldap,gen_config) :
####### Les groupes
base_group_dn = 'ou=Group,dc=crans,dc=org'
# Quels droits donnent l'appartenacne à quel groupe ?
groupes = { 'adm' : [ u'Nounou' ] ,
'respbats' : [ u'Câbleur' , u'Déconnecteur', u'Nounou' ] ,
'moderateurs' : [ u'Modérateur' ] ,
'disconnect' : [ u'Déconnecteur' ] ,
'webcvs' : [ u'CVSWeb'] }
####### Les ML
# Le + devant un nom de ML indique une synchronisqtion
# ML <-> fonction partielle : il n'y a pas d'effacement
# des abonnés si le droit est retiré
mailing_listes = { 'roots' : [ u'Nounou', u'Apprenti' ],
'+nounou' : [ u'Nounou', u'Apprenti' ],
'respbats' : [ u'Câbleur', u'Nounou' ],
'moderateurs' : [ u'Modérateur' ],
'disconnect' : [ u'Déconnecteur' ] }
def restart(s) :
# Rien à faire
pass
def __str__(self):
return "droits"
def build_group(self) :
""" Reconstruit les groupes dans la base LDAP """
self.anim.iter = len( self.groupes.keys() )
for group, fonctions in self.groupes.items() :
self.anim.cycle()
# Qui doit être dans ce groupe ?
res = []
for f in fonctions :
res += self.search('droits=%s' % f)['adherent']
# Récupération de la constitution du groupe actuel
dn = 'cn=%s,%s' % (group, self.base_group_dn)
data = self.conn.search_s(dn ,0,'objectClass=posixGroup')[0][1]
init_data = data.copy()
# Supression de tout les membres
data['memberUid'] = []
# Ajout des bonnes personnes
for adher in res :
uid = preattr(adher.compte())[1]
if uid and uid not in data['memberUid'] :
data['memberUid'].append(uid)
# Sauvegarde
modlist = ldap.modlist.modifyModlist(init_data,data)
self.conn.modify_s(dn,modlist)
def gen_conf(self) :
self.anim = anim('\tconfiguration groupes')
try :
self.build_group()
self.anim.reinit()
print OK
except :
self.anim.reinit()
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
self.anim = anim('\tconfiguration ML Crans')
print 'TODO'

60
gestion/gen_confs/firewall.py Executable file
View file

@ -0,0 +1,60 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Génération de la configuration pour le firewall
Copyright (C) Frédéric Pauget
Licence : GPLv2
"""
from gen_confs import gen_config
from time import localtime
class firewall(gen_config) :
""" Génère le fichier de paires MAC-IP """
# Fichier
MACIP = '/CRANS/generated/ether/pairesMAC-IP.txt'
restart_cmd = '/etc/init.d/firewall macip'
def __str__(self) :
return "firewall"
def _gen(self) :
macip= self._open_conf(self.MACIP)
self.anim.iter=len(self.machines)
for machine in self.machines :
self.anim.cycle()
macip.write( "%s %s\n" % ( machine.mac(), machine.ip() ) )
macip.close()
class bl_upload_fw(gen_config) :
""" Génère le fichier de blackliste d'upload pour le firewall"""
# Fichier
BL_UPLOAD = '/tmp/bl_upload_fw'
restart_cmd = '/etc/init.d/firewall blacklist'
def __str__(self) :
return "blackliste upload firewall"
def _gen(self) :
upload = self._open_conf( self.BL_UPLOAD, '#' )
if localtime()[1] == 9:
# On est en septembre, on autorise ceux qui ont payé l'an dernier et cette année
base = self.base.search('(paiement=%d|paiement=%d)' % (int(self.ann_scol),
int(self.ann_scol) - 1))
else:
base = self.base.search('paiement=%s' % self.ann_scol)
for adh in ( [ self.crans ] + base['adherent'] + base['club'] ):
for machine in adh.machines() :
self.anim.cycle()
bl = machine.blacklist_actif()
if 'bl_upload' in bl and not 'bloq' in bl :
upload.write( '%s:smtp,smtps,pop3,pop3s,imap,imaps,http\n' % machine.nom() )
upload.close()

161
gestion/gen_confs/generate.py Executable file
View file

@ -0,0 +1,161 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
import sys, signal, os, commands, getopt
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, crans, ann_scol
from lock import *
from affich_tools import anim, cprint, OK, ERREUR, WARNING
from time import localtime
import config
signal.signal(signal.SIGINT,signal.SIG_IGN) # Pas de Ctrl-C
db = crans_ldap()
make_lock('auto_generate')
##### Options fournies ?
try :
if len(sys.argv) > 1 :
options, arg = getopt.getopt(sys.argv[1:], '', ['quiet', 'home=', 'ML-ENS=', 'droits', 'switch=' , 'dhcp', 'dns', 'firewall' ])
else :
options, arg = ( [],'')
except getopt.error, msg :
sys.stderr.write('%s\n' % msg)
sys.exit(255)
debug = 1 # défaut
to_do = {}
for opt, val in options :
if opt == '--quiet' :
debug = 0
elif len(opt)>2 and opt[:2]=='--' :
to_do[opt[2:]] = [ val ]
##### Lecture de la base LDAP si besion ce qu'il y a a faire et préparation
if not to_do :
if debug : print 'Lecture services à redémarrer dans la base LDAP'
to_do = db.services_to_restart()
auto = 1
else :
auto = 0
if debug : print 'Services à redémarrer imposés (non lecture de la base LDAP)'
inst = []
if 'home' in to_do.keys() :
if auto : db.services_to_restart('-home')
cprint('Création home','gras')
for args in to_do['home'] :
anim('\t' + args)
try :
home, uid, login = args.split(',')
os.mkdir(home, 0755)
os.chown(home, int(uid) ,config.gid)
os.mkdir(home + '/Mail', 0700)
os.chown(home + '/Mail', int(uid) ,config.gid)
status, output = commands.getstatusoutput('/usr/sbin/edquota -p pauget %s' % login )
if status :
print WARNING
if debug :
sys.stderr.write(output+'\n')
else :
print OK
except :
print ERREUR
if debug :
import traceback
traceback.print_exc()
if 'ML-ENS' in to_do.keys() :
db.services_to_restart('-ML-ENS')
cprint('Inscription ML-ENS','gras')
for mail in to_do['ML-ENS'] :
anim('\t'+mail)
status, output = commands.getstatusoutput("echo '%s' | /usr/sbin/add_members -r - com-ens >/dev/null 2>&1" % mail)
if status :
# Il y a eu une erreur
print ERREUR
if debug :
sys.stderr.write(output+'\n')
else :
print OK
if 'droits' in to_do.keys() :
db.services_to_restart('-droits')
from gen_confs.droits import droits
a = droits()
a.debug = debug
a.reconfigure()
if 'switch' in to_do.keys() :
if auto : db.services_to_restart('-switch')
from gen_confs.switchs import switch
a = switch(to_do['switch'])
a.debug = debug
a.reconfigure()
# Les services suivants ont besoin de la liste des machines
# On va donc la lire une seule fois pour leur passer ensuite
if 'firewall' in to_do.keys() :
# Quand sila et komaz liront la base LDAP
# db.services_to_restart('firewall-komaz')
# db.services_to_restart('firewall-sila')
db.services_to_restart('-firewall')
from gen_confs.firewall import firewall
inst.append(firewall())
if 'dns' in to_do.keys() :
db.services_to_restart('-dns')
from gen_confs.bind import dns
inst.append(dns())
if 'dhcp' in to_do.keys() :
from gen_confs.dhcpd import dhcp
db.services_to_restart('-dhcp')
inst.append(dhcp())
##### On fait ce qu'il reste à faire
if inst :
##### Récolte des données
cprint('Lecture base LDAP','gras')
# Machines de l'assoce
machines = crans().machines()
# Machines des adhérents et clubs de l'année en cours
if localtime()[1] == 9:
# On est en septembre, on autorise ceux qui ont payé l'an dernier et cette année
base = db.search('(paiement=%d|paiement=%d)' % (int(ann_scol),
int(ann_scol) - 1))
else:
base = db.search('paiement=%s' % ann_scol)
base = base['adherent'] + base['club']
a = anim('\ttri machines',len(base))
for adh in base :
a.cycle()
# Adhérent ayant payé l'année en cours
if 'bloq' in adh.blacklist_actif() :
# Adhérent ignoré
continue
machines += adh.machines()
a.reinit()
print OK
#### Reconfiguration des services
for i in inst :
i.debug = debug
i.machines = machines
try :
i.reconfigure()
except :
sys.stderr.write('Erreur dans le service %s\n' % i)
if debug :
print 'Non traité ici mais signalé dans la base LDAP : \n\t', db.services_to_restart()
signal.signal(signal.SIGINT,signal.SIG_DFL) # Comportement normal de Ctrl-C
remove_lock('auto_generate')

14
gestion/gen_confs/home.py Normal file
View file

@ -0,0 +1,14 @@
home
home = args[0]
os.mkdir(home, 0755)
os.mkdir(home + '/Mail', 0700)
os.lchown(home, int(args[1]) ,config.gid)
os.system('/usr/sbin/edquota -p pauget %s' % arg[3] )
ML-ENS
if os.system("echo '%s' | /usr/sbin/add_members -r - com-ens" % mail) :
# Il y a eu une erreur
arg = u'--title "Inscription Mailing liste de communiquation ENS" '
arg+= u'--msgbox "Une erreur s\'est produite lors de l\'ajout à la mailing liste.\n\n\n" 0 0'
dialog(arg)

90
gestion/gen_confs/squid.py Executable file
View file

@ -0,0 +1,90 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" Génération de la configuration pour squid """
from gen_confs import gen_config
from time import localtime
class bl_carte_etudiant(gen_config) :
""" Génère le fichier de blackliste pour carte d'étudiant pour squid"""
BL_CARTE = '/tmp/bl_carte_et'
restart_cmd = '/etc/init.d/squid reload'
def __str__(self) :
return "blackliste cartes d'étudiant"
def _gen(self) :
fd=self._open_conf(self.BL_CARTE)
if localtime()[1] == 9:
# On est en septembre, on autorise ceux qui ont payé l'an dernier et cette année
base = self.base.search('carteEtudiant!=%s&(paiement=%d|paiement=%d)' % (self.ann_scol,
int(self.ann_scol),
int(self.ann_scol) - 1))
else:
base = self.base.search('paiement=%s' % self.ann_scol)
for adh in ( [ self.crans ] + base['adherent'] + base['club'] ):
for machine in adh.machines() :
self.anim.cycle()
if 'bloq' in machine.blacklist_actif() : continue
if machine.proprietaire().idn != 'aid' : continue
fd.write(machine.nom() + '\n')
fd.close()
class bl_upload_squid(gen_config) :
""" Génère le fichier de blackliste d'upload pour squid"""
# Fichier
BL_UPLOAD = '/tmp/bl_upload_squid'
restart_cmd = '/etc/init.d/squid reload'
def __str__(self) :
return "blackliste upload squid"
def _gen(self) :
upload = self._open_conf( self.BL_UPLOAD )
if localtime()[1] == 9:
# On est en septembre, on autorise ceux qui ont payé l'an dernier et cette année
base = self.base.search('(paiement=%d|paiement=%d)' % (int(self.ann_scol),
int(self.ann_scol) - 1))
else:
base = self.base.search('paiement=%s' % self.ann_scol)
for adh in ( [ self.crans ] + base['adherent'] + base['club'] ):
for machine in adh.machines() :
self.anim.cycle()
bl = machine.blacklist_actif()
if 'bl_upload' in bl and not 'bloq' in bl :
upload.write( machine.nom() + '\n' )
upload.close()
class bl_virus(gen_config) :
""" Génère le fichier de blackliste virus pour squid"""
# Fichiers
BL_VIRUS = '/tmp/bl_virus'
def __str__(self) :
return "blackliste virus"
restart_cmd = '/etc/init.d/squid reload'
description = u'Bloquage accès http vers l\'extérieur, page expliquative'
def _gen(self) :
virus = self._open_conf( self.BL_VIRUS )
if localtime()[1] == 9:
# On est en septembre, on autorise ceux qui ont payé l'an dernier et cette année
base = self.base.search('(paiement=%d|paiement=%d)' % (int(self.ann_scol),
int(self.ann_scol) - 1))
else:
base = self.base.search('paiement=%s' % self.ann_scol)
for machine in base['machine'] :
self.anim.cycle()
bl = machine.blacklist_actif()
if 'bl_virus' in bl and not 'bloq' in bl :
virus.write( machine.nom() + '\n')
virus.close()

372
gestion/gen_confs/switchs.py Executable file
View file

@ -0,0 +1,372 @@
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
""" met à jour les propriétés des prises des switchs du bat :
mac autorisée(s), état (activé ou non) et nom de la prise
argument : nom du switch
procédure de configuration initiale :
* mot de passe admin (password manager user-name <username>)
* upgrade firmware (copy tftp flash 138.231.136.7 <file>)
* reboot (boot)
* génération clef ssh (crypto key generate ssh)
* copie fichier de conf (copy tftp startup-config 138.231.136.7 <file>)
* faire le stacking et le snmpv3 à la main
pour les reconfiguration juste copier le fichier de conf
"""
import string, sys, os, commands
sys.path.append('/CRANS/code')
#sys.path.append('/home/fred/Crans/zamok/CRANS/code')
from hptools import hp
sys.path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap, ann_scol
from annuaires import chbre_prises #, uplink_prises, reverse
from gen_confs import gen_config, OK, ERREUR, anim
from time import localtime
# from qqch import switchs # Liste des switchs
bat_switchs = [ 'b', 'c', 'h', 'i', 'g' ]
class switch(gen_config) :
def __init__(self,chbres):
""" Chbre doit être une liste de chambres """
self.db = crans_ldap()
# On enlève la chambre "CRA"
self.chbres = [ch for ch in chbres if ch != "CRA"]
def __str__(self) :
return 'switchs'
def restart(self) :
# Rien à faire ici
pass
def gen_conf(self) :
self.chbres.sort()
for chbre in self.chbres :
bat = chbre[0].lower()
a = self.db.search('chbre=%s' % chbre)['adherent']
action = ''
for adh in a :
if ((ann_scol in adh.paiement() or
((ann_scol-1) in adh.paiement and localtime()[1]==9)) and
'bloq' not in adh.blacklist_actif()) :
# Il faut activer la prise
anim('\tactivation chbre %s' % chbre)
action = 'enable'
break
if action == '' :
# Il faut désactiver la prise
anim('\tdésactivation chbre %s' % chbre)
action = 'disable'
try :
if bat in bat_switchs :
# Action sur le switch
prise = chbre_prises[bat][chbre[1:].lower()]
sw=hp(bat,int(prise[0]))
r = sw.set_prise(int(prise[1:4]),'disable')
sw.close()
if not r :
raise RuntimeError('Erreur de communiquation')
else :
# Mail au bat
To = "bat%s@crans.org" % bat
From = To
conn=smtplib.SMTP('localhost')
txt_mail = "From: Crans scripts <%(From)s>\n"
txt_mail+= "To: %(To)s\n"
txt_mail+= "Subject: Bienvenue au Cr@ns !\n\n"
txt_mail+= "Chambre %s à débrancher." % chbre
conn.sendmail(From, To , txt_mail % { 'From' : From, 'To' : To })
conn.quit()
print OK
except :
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
### BROUILLON POUR PLUS TARD
class switch2(gen_config) :
# Répertoire ou écire les fichiers de conf
CONF_REP='/tmp/' # avec un / derrière
config = """; J4899A Configuration Editor; Created on release #H.07.32
hostname "%(switch)s"
;-------------------------------------------------------- Snmp
snmp-server contact "root@crans.org"
snmp-server location "Batiment %(bat)s"
;A faire à la main
;snmpv3 enable
;snmpv3 restricted-access
;snmpv3 user "initial"
;snmpv3 user "crans"
;snmpv3 group ManagerPriv user "crans" sec-model ver3
;snmp-server community "public" Operator
;-------------------------------------------------------- Réglage heure/date
time timezone 60
time daylight-time-rule Western-Europe
sntp server 138.231.136.6
timesync sntp
sntp unicast
;-------------------------------------------------------- Misc
console inactivity-timer 30
;-------------------------------------------------------- Logs
logging 138.231.136.7
;-------------------------------------------------------- Logs
%(INTERFACES_CONF)s
;-------------------------------------------------------- IP du switch
ip default-gateway 138.231.136.4
vlan 1
name "DEFAULT_VLAN"
untagged 1-%(nb_prises)d
ip address %(ip)s 255.255.248.0
ip igmp
no ip igmp querier
exit
;-------------------------------------------------------- Accès d'adminsitration
no web-management
aaa authentication ssh login public-key
ip ssh
ip ssh version 2
ip authorized-managers 138.231.136.0 255.255.255.0
ip authorized-managers 138.231.137.216
ip authorized-managers 138.231.137.215
;STACKING_CONF
;-------------------------------------------------------- Spanning-tree
spanning-tree
; Config des uplinks
no spanning-tree %(uplinks)s edge-port
; Config des prises adhérent
spanning-tree %(non_uplinks)s point-to-point-mac auto
spanning-tree %(non_uplinks)s priority 15
no cdp run
;-------------------------------------------------------- Avec mot de passe ;)
password manager
"""
interface_template = """interface %(prise)i\n%(etat)s
name %(nom)s
flow-control%(speed)s
no lacp
exit
"""
filtre_mac_template = "port-security %(prise)i learn-mode static address-limit 3 mac-address%(macs)s\n"
nom = 'switchs'
def __str__(self) :
return self.nom
def __init__(self,qqch='') :
"""
Si qqch='' : reconfigure tous les switchs
Si qqch=<nom d'un switch> (batX-N) : reconfigure que ce switch
Si qqch=<chambre> (XNNN) : regénère le fichier de conf du switch correspondant
et reconfigure uniquement la prise """
# Traitement argument
if not qqch :
self.__params = {}
elif qqch in switchs :
self.__params = { 'bat' : qqch[3].lower() ,
'sw_num' : qqch[5] ,
'switch' : qqch.lower() }
self.nom = 'switch %(switch)s' % self.__params
else :
# Ca doit être une chambre
bat = qqch[0].lower()
if bat in mail_bats :
# Pas de switch à reconfigurer
self.__params = { 'chbre' : qqch.capitalize() ,
'bat' : bat }
else :
try :
prise = chbre_prises[bat][qqch[1:]]
self.__params = { 'nom_prise' : qqch.capitalize() ,
'sw_prise' : int(prise[1:]) ,
'bat' : bat ,
'sw_num': int(prise[0]),
'switch': 'bat%s-%s' % (bat, prise[0]) }
self.nom = 'prise %s%s (chbre %s)' % (bat.upper(), prise,qqch)
except :
# Prise inconnue
raise RuntimeError("Impossible d'associer une prise à la chambre.")
def gen_conf(self) :
""" Génération configuration :
* soit d'un switch si présent dans self.__params
* soit de tous les switchs si aucun présent dans self.__params
* soit d'aucun switch si chbre dans bat non manageable, dans ce cas
envoi un mail quand il faut aller débrancher et retourne 2
En cas d'erreur retourne 1
"""
if self.__params.has_key('chbre') :
# Pas de switch manageable, il suffit de mailer
anim('\tmail à bat%(bat)s' % self.__params)
print 'TODO'
return 2
self.lock()
if self.__params.has_key('switch') :
# Regénération de la conf d'un switch
self.__gen_switch(self.__params)
else :
# Regénération de la conf de tous les switchs
for switch in switchs :
params = { 'bat' : switch[3].lower() ,
'sw_num' : int(switch[5]) ,
'switch' : switch.lower() }
self.__gen_switch(params)
self.unlock()
def restart(self) :
"""
Si l'instance à été initialisée avec une chbre reconfigure cette chambre
Sinon reconfigure le switch founi, si aucun fourni, les reconfigure tous
"""
if self.__params.has_key('chbre') :
# Rien à faire, le mail doit être envoyé
return
self.lock()
if self.__params.has_key('sw_prise') :
# Utiliser la classe hptools et/ou faire du snmp
anim('\treconfiguration prise' )
elif self.__params.has_key('switch') :
# Restart d'un seul switch
self.__restart_switch(self.__params['switch'])
else :
# Restart tous les switchs
for switch in switchs :
self.__restart_switch(switch)
self.unlock()
def __gen_switch(self,params) :
""" params est un dictionnaire avec les keys bat, sw_num et switch """
aff = anim('\tgénération de %(switch)s.conf' % params)
try :
bat = params['bat']
# Nombre de prises
nb_prises = """
METTRE CA DANS LA CLASSE S'OCCUPANT DU SNMP
try :
nb = int(sys.argv[2])
except :
a=os.popen("snmpget -c public %s system.sysDescr.0 2>/dev/null" % switch)
try :
version = string.strip(string.split(string.split(a.readlines()[0],',')[0],'=')[1])
except :
version = ''
a.close()
if version == 'HP J4900A ProCurve Switch 2626' :
nb=26
elif version == 'HP J4899A ProCurve Switch 2650' :
nb=50
else :
print "Erreur : impossible de déterminer le nombre de ports"
sys.exit(1)
"""
nb_prises = 50
params['nb_prises'] = nb_prises
# Récupération IP
params['ip'] = commands.getoutput("host %s" % switch).split()[-1]
params['INTERFACES_CONF'] = ''
params['MAC_FILTER'] = ''
# Dictionnaire prise -> chambre
prise_chbres = reverse(bat)
# Configuration des prises
mac_filter=[]
aff.iter = nb_prises+1
for prise in range(1,nb_prises+1):
aff.cycle()
prise_params = { 'prise' : prise , 'speed' : '', 'etat' : '' }
annu_prise = '%i%02i' % (params['sw_num'], prise)
if uplink_prises[bat].has_key(int(annu_prise)) :
### Prise d'uplink
prise_params['nom'] = uplink_prises[bat][int(annu_prise)]
try : params['uplinks'] += ',%i' % prise
except : params['uplinks'] = str(prise)
else :
### Prise adhérent
try : params['non_uplinks'] += ',%i' % prise
except : params['non_uplinks'] = str(prise)
if prise_chbres.has_key(annu_prise) :
chbres = prise_chbres[annu_prise]
elif prise_chbres.has_key(annu_prise+'-') :
# Prise en 10
prise_params['speed'] = ' speed-duplex auto-10\n'
chbres = prise_chbres[annu_prise+'-']
else :
# Prise non référencée dans l'annuaire
prise_params['nom'] = "Pas_dans_l'annuaire"
prise_params['etat']=' disable\n'
chbres = []
if chbres :
prise_params['nom'] = 'Chambre'
if len(chbres) > 1 :
prise_params['nom'] += 's'
for chbre in chbres :
prise_params['nom'] += '_' + chbre
# Etat
macs = ''
machines = self.base.search('chbre=%s%s' % (bat.upper(), chbre) )['machine']
for m in machines :
if 'bloq' in m.blacklist_actif() : continue
macs += ' ' + m.mac()
if not macs :
prise_params['etat']=' disable\n'
else :
params['MAC_FILTER'] += self.filtre_mac_template % vars()
params['INTERFACES_CONF'] += self.interface_template % prise_params
# Petites verif
if not params.has_key('uplinks') or not params.has_key('non_uplinks') :
raise RuntimeError('Switch sans uplink ou sans prise adhérent.')
fd = self._open_conf(self.CONF_REP + 'switch' + '.conf')
fd.write(self.config % params)
fd.close()
aff.reinit()
print OK
except :
aff.reinit()
self._restore()
return 1
def __restart_switch(self,switch) :
anim('\trestart %s' % switch)
try :
print 'TODO'
except :
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
return 1