scripts/gestion/gen_confs/switchs.py
bernat cfeec3070a A l'avenir, les prises wifi seront "tagged". Ce n'est pas encore le
cas actuellement.

darcs-hash:20051231194447-d1718-d93fb0c3ff05a7f522c14ef894b2e6da66756c28.gz
2005-12-31 20:44:47 +01:00

441 lines
16 KiB
Python
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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, smtplib
sys.path.append('/usr/scripts/gestion')
from hptools import hpswitch, sw_chbre
from ldap_crans import crans_ldap
from annuaires import chbre_prises, uplink_prises, reverse, bat_manuels, all_switchs
from random import shuffle
from gen_confs import *
from time import localtime
from annuaires import bat_switchs
class switch(gen_config) :
# Répertoire ou écire les fichiers de conf
CONF_REP='/tmp/' # avec un / derrière
config = """; %(modele)s Configuration Editor; Created on release #H.08.72
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
;-------------------------------------------------------- Heure/date
time timezone 60
time daylight-time-rule Western-Europe
sntp server 138.231.144.3
timesync sntp
sntp unicast
;-------------------------------------------------------- Misc
console inactivity-timer 30
;-------------------------------------------------------- Logs
logging 138.231.144.7
;-------------------------------------------------------- Logs
%(INTERFACES_CONF)s
;-------------------------------------------------------- IP du switch
ip default-gateway 138.231.144.4
vlan 1
name "DEFAULT_VLAN"
%(prises_default)s
no ip address
ip igmp
no ip igmp querier
exit
vlan 2
name "Adm"
%(prises_adm)s
ip address %(ip)s 255.255.255.0
exit
vlan 3
name "Wifi"
%(prises_wifi)s
no ip address
exit
vlan 4
name "Hotspot"
%(prises_hotspot)s
no ip address
exit
;------------------------------------------------------- Accès d'administration
no telnet-server
no web-management
aaa authentication ssh login public-key
aaa authentication ssh enable public-key
ip ssh
ip ssh version 2
ip authorized-managers 138.231.144.0 255.255.255.0
ip ssh filetransfer
;------------------------------------------------------- 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
;------------------------------------------------------- Serveurs radius
radius-server dead-time 2
radius-server key %(radius_key)s
%(radius-serveurs)s
;------------------------------------------------------- Filtrage mac
aaa port-access mac-based %(prises_filtrage_mac)s
aaa port-access mac-based %(prises_filtrage_mac)s addr-limit 3
aaa port-access mac-based %(prises_filtrage_mac)s logoff-period 3600
aaa port-access mac-based addr-format multi-colon
;------------------------------------------------------- Bricoles
no cdp run
no stack
"""
interface_template = """interface %(prise)i%(etat)s
name "%(nom)s"
flow-control%(speed)s
no lacp
exit
"""
# Serveurs radius
rad_servs = [ '138.231.144.10' , '138.231.144.18' ]
rad_template = "radius-server host %s\n"
def __init__(self,truc):
""" truc est soit :
* une _liste_ de chambres => reconfig de ces chambres
* un _tulpe_ de noms de switch => reconfig de ces swiths"""
self.db = crans_ldap() # connexion LDAP
if type(truc) == list :
# On enlève les chambres "CRA", "????" et EXT qui n'ont pas besion de config
self.chbres = [ch for ch in truc if (ch not in [ "CRA", "????", "EXT" ]) ]
self.switch = None
else :
self.chbres = None
self.switch = truc
def __str__(self) :
return 'switchs'
def restart(self) :
if self.chbre :
# Tout est déja fait
return
####### Vu qu'il n'y a pas de serveur tftp ici
# on excécute pas le truc en dessous
#for switch in self.switch :
# self.aff = anim('\treboot de %s' % switch)
# sw = hptools.switch(switch)
# sw.update()
def gen_conf(self) :
if self.chbres :
self.chbres.sort()
for chbre in self.chbres :
self.configure_chbre(chbre)
elif self.switch :
for switch in self.switch :
self.configure_switch(switch)
def configure_chbre(self,chbre) :
""" Recontigure la chambre fournie chambre """
try :
bat = chbre[0].lower()
if bat in bat_switchs :
prise = sw_chbre(chbre)
prise.reconfigure() # Vitesse et nom (juste au cas ou ca aurait changé)
elif bat in bat_manuels :
class prise_non_manageable :
def __init__(self,chbre) :
self.chbre = chbre
def __mail(self,sujet) :
To = "clef%s@crans.org" % self.chbre[0].lower()
From = To
conn=smtplib.SMTP('localhost')
txt_mail = "From: Crans scripts <%(From)s>\n"
txt_mail+= "To: %(To)s\n"
txt_mail+= "Subject: (CRANS) %s\n\nMerci." % sujet
conn.sendmail(From, To , txt_mail % { 'From' : From, 'To' : To })
conn.quit()
def disable(self) :
self.__mail("Chambre %s à débrancher." % self.chbre)
def enable(self) :
self.__mail("Chambre %s à brancher." % self.chbre)
prise=prise_non_manageable(chbre)
else :
# Rien a faire
print OK
return True
a = self.db.search('chbre=%s&paiement=ok' % chbre)
a = a['adherent'] + a['club']
if a and 'bloq' not in a[0].blacklist_actif() :
# Il faut activer la prise
anim('\tactivation chbre %s' % chbre)
prise.enable()
else :
# Il faut désactiver la prise
anim('\tdésactivation chbre %s' % chbre)
prise.disable()
print OK
except :
print ERREUR
if self.debug :
import traceback
traceback.print_exc()
return False
return True
def configure_switch(self,switch) :
self.aff = anim('\tconfiguration de %s' % switch)
try:
warn = self.__configure_switch(switch)
self.aff.reinit()
if warn :
print WARNING
if self.debug :
sys.stderr.write(warn)
else :
print OK
except :
self.aff.reinit()
print ERREUR
self._restore()
return 1
def __configure_switch(self,switch) :
""" Génère le fichier de conf du switch donné """
conn = hpswitch(switch)
### Récupération données du switch
# Batiment et numéro du switch
bat = switch[3].lower()
sw_num = int(switch[5])
# Conf radius
from secrets import radius_key
shuffle(self.rad_servs)
rad = self.rad_template * len(self.rad_servs)
params = { 'switch' : switch, 'bat' : bat.upper() ,
'radius_key' : radius_key ,
'radius-serveurs' : rad[:-1] % tuple(self.rad_servs)}
# Nombre de prises et modèle
nb_prises = conn.nb_prises()
modele = conn.version()
if not nb_prises or not modele :
raise RuntimeError("Erreur : impossible de déterminer les caractéristiques du switch.")
params['modele'] = modele.split()[1]
# IP
params['ip'] = commands.getoutput("host %s" % switch).split()[-1]
### Configuration prises
params['INTERFACES_CONF'] = ''
# Dictionnaire prise -> chambre
prise_chbres = reverse(bat)
# Prises occupées par des machines du Cr@ns
crans_prises={}
for m in self.db.search('prise=%s%i*' % (bat.upper(), sw_num))['machine'] :
try: crans_prises[m.prise()].append(m)
except: crans_prises[m.prise()] = [ m ]
self.aff.iter = nb_prises+1
# Param-Aètres à affecter-b
for key in ( 'uplinks', 'non_uplinks', 'prises_filtrage_mac' ) :
params[key] = []
vlans = { 'wifi_tagged' : [] , 'wifi_untagged' : [] ,
'hotspot_tagged' : [], 'hotspot_untagged' : [],
'adm_tagged' : [] , 'adm_untagged' : [] ,
'default_tagged' : [] , 'default_untagged' : [] }
# Génération de la conf de chaque prise
for prise in range(1,nb_prises+1):
self.aff.cycle()
# Conf par défaut : activée, autonégociation
prise_params = { 'prise' : prise , 'speed' : '', 'etat' : '' }
annu_prise = '%i%02i' % (sw_num, prise) # prise telle que notée dans l'annuaire
if uplink_prises[bat].has_key(int(annu_prise)) :
### Prise d'uplink
prise_params['nom'] = uplink_prises[bat][int(annu_prise)]
params['uplinks'].append(prise)
vlans['default_untagged'].append(prise)
vlans['adm_tagged'].append(prise)
vlans['wifi_tagged'].append(prise)
vlans['hotspot_tagged'].append(prise)
params['INTERFACES_CONF'] += self.interface_template % prise_params
continue
params['non_uplinks'].append(prise)
if crans_prises.has_key("%s%s" % (bat.upper(), annu_prise)) :
### Prise réservée à l'association
wifi=0
adm=0
autres=0
for m in crans_prises["%s%s" % (bat.upper(), annu_prise)] :
if m.canal() : wifi+=1
elif m.Nom().find('.adm.crans.org')!=-1 : adm+=1
else : autres+=1
if autres==0 and adm==0 :
# Vlan wifi uniquement
if wifi == 1 :
prise_params['nom'] = "Wifi_%s" % m.nom().split(".")[0]
else :
prise_params['nom'] = "Wifi"
vlans['hotspot_tagged'].append(prise)
vlans['wifi_tagged'].append(prise)
elif wifi==0 and autres==0 :
# Vlan adm uniquement
if amd == 1 :
prise_params['nom'] = m.nom().split(".")[0]
else :
prise_params['nom'] = "Uplink_adm"
vlans['adm_untagged'].append(prise)
else :
# Tous les vlans
prise_params['nom'] = "Prise_crans"
vlans['default_untagged'].append(prise)
vlans['adm_tagged'].append(prise)
vlans['wifi_tagged'].append(prise)
vlans['hotspot_tagged'].append(prise)
params['INTERFACES_CONF'] += self.interface_template % prise_params
continue
vlans['default_untagged'].append(prise)
# A quelle chambre correspond la 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'] = '\n speed-duplex auto-10'
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']='\n disable'
params['INTERFACES_CONF'] += self.interface_template % prise_params
continue
params['prises_filtrage_mac'].append(prise)
## Configuration de la prise adhérent
# Nom
prise_params['nom'] = 'Chambre'
if len(chbres) > 1 : prise_params['nom'] += 's'
for chbre in chbres :
prise_params['nom'] += '_%s%s' % (bat.upper(), chbre)
# Besoin d'activer la prise ?
prise_params['etat']='\n disable'
for chbre in chbres :
res = self.db.search('chbre=%s%s&paiement=ok' % (bat.upper(), chbre) )
for res in res['adherent'] + res['club'] :
if 'bloq' not in res.blacklist_actif() :
prise_params['etat']=''
break
params['INTERFACES_CONF'] += self.interface_template % prise_params
# Petite verif
if not params['uplinks'] or not params['non_uplinks'] :
raise RuntimeError('Switch sans uplink ou sans prise adhérent.')
def mk_list(liste_prise) :
"""
transforme une liste de prises en une chaine pour le switch
exemple : 1, 3, 4, 5, 6, 7, 9, 10, 11, 12 => 1,3-7,9-12
"""
if not liste_prise : return ''
liste_prise.sort()
# initialisation
i = liste_prise.pop(0)
groupe = [ i, i ]
result = []
liste_prise.append(9999) # apparaitra jamais dans la liste
while liste_prise :
nouveau = liste_prise.pop(0)
if nouveau == groupe[1] + 1 :
groupe[1] += 1
else :
# Ajout du groupe au résultat
if groupe[0] == groupe[1] :
result.append(str(groupe[0]))
else :
result.append('-'.join(map(str,groupe)))
# Réinit de groupe
groupe = [ nouveau, nouveau ]
return ','.join(result)
# Saut de ligne parasite
params['INTERFACES_CONF'] = params['INTERFACES_CONF'][:-1].encode('iso-8859-15')
# Conversion des listes
for key in [ 'prises_filtrage_mac', 'uplinks', 'non_uplinks' ] :
params[key] = mk_list(params[key])
for key, prises in vlans.items() :
vlans[key]=mk_list(prises)
# Config des vlan
for v in ('default', 'adm', 'wifi', 'hotspot') :
params['prises_%s' % v] = ''
for t in ('tagged' , 'untagged') :
if vlans['%s_%s' % (v,t)] :
params['prises_%s' % v] += '\n %s %s' % (t, vlans['%s_%s' % (v,t)])
# Saut de ligne parasite
params['prises_%s' % v] = params['prises_%s' % v][4:]
# Ecriture
fd = self._open_conf(self.CONF_REP + switch + '.conf')
fd.write(self.config % params)
fd.close()
if __name__ == '__main__' :
if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) == 1 :
print "%s <switch>" % sys.argv[0].split('/')[-1].split('.')[0]
print "Génération du fichier de configuration des switchs donnés."
sys.exit(255)
if sys.argv[1] == 'all' :
switchs = tuple(all_switchs())
else :
switchs = tuple(sys.argv[1:])
sw = switch(switchs)
sw.debug = 1
sw.reconfigure()