
Maintenant radius dit aux switchs quel vlan mettre en non taggé. Ça permet de switcher facilement sur le bon vlan suivant le type de compte et ça évite la désynchronisation de la configuration des switchs. darcs-hash:20080904041337-af139-665172ad09d19f439c6aa8ee6c529752c0e80d95.gz
459 lines
16 KiB
Python
Executable file
459 lines
16 KiB
Python
Executable file
#!/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>)
|
|
* activation du ssh (crypto key generate ssh)
|
|
* copie fichier de conf
|
|
pour les reconfiguration copier le fichier de conf
|
|
|
|
Dans tous les cas FAIRE LE SNMP A LA MAIN (script hpttols)
|
|
"""
|
|
|
|
import string, sys, os, commands, smtplib
|
|
|
|
sys.path.append('/usr/scripts/gestion')
|
|
from hptools import hpswitch, sw_chbre
|
|
from ldap_crans import crans_ldap, BorneWifi
|
|
from annuaires import chbre_prises, uplink_prises, reverse, bat_manuels, all_switchs
|
|
from random import shuffle
|
|
from gen_confs import *
|
|
from time import localtime
|
|
import config
|
|
|
|
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.86
|
|
|
|
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 10.231.136.3
|
|
timesync sntp
|
|
sntp unicast
|
|
;-------------------------------------------------------- Misc
|
|
console inactivity-timer 30
|
|
;-------------------------------------------------------- Logs
|
|
logging 10.231.136.7
|
|
;-------------------------------------------------------- Logs
|
|
%(INTERFACES_CONF)s
|
|
;-------------------------------------------------------- IP du switch
|
|
ip default-gateway 10.231.136.4
|
|
vlan %(vlan_adherent)s
|
|
name "DEFAULT_VLAN"
|
|
untagged %(prises_default)s
|
|
no ip address
|
|
ip igmp
|
|
no ip igmp querier
|
|
exit
|
|
vlan %(vlan_adm)s
|
|
name "Adm"
|
|
%(prises_adm)s
|
|
ip address %(ip)s 255.255.255.0
|
|
exit
|
|
vlan %(vlan_wifi)s
|
|
name "Wifi"
|
|
%(prises_wifi)s
|
|
no ip address
|
|
exit
|
|
vlan %(vlan_hotspot)s
|
|
name "Hotspot"
|
|
%(prises_hotspot)s
|
|
no ip address
|
|
exit
|
|
vlan %(vlan_radin)s
|
|
name "Radin"
|
|
tagged %(prises_default)s
|
|
no ip address
|
|
exit
|
|
vlan %(vlan_accueil)s
|
|
name "Accueil"
|
|
tagged %(prises_default)s
|
|
no ip address
|
|
exit
|
|
;------------------------------------------------------- Accès d'administration
|
|
no telnet-server
|
|
no web-management
|
|
aaa authentication ssh login public-key none
|
|
aaa authentication ssh enable public-key none
|
|
ip ssh
|
|
ip ssh version 2
|
|
ip authorized-managers 10.231.136.0 255.255.255.0
|
|
ip ssh filetransfer
|
|
;------------------------------------------------------- Spanning-tree
|
|
spanning-tree protocol-version rstp
|
|
; Config des uplinks
|
|
no spanning-tree %(uplinks)s edge-port
|
|
spanning-tree %(uplinks)s point-to-point-mac true
|
|
spanning-tree %(uplinks)s priority 6
|
|
; Config des prises adhérent
|
|
spanning-tree %(non_uplinks)s edge-port
|
|
spanning-tree %(non_uplinks)s point-to-point-mac auto
|
|
spanning-tree %(non_uplinks)s priority 8
|
|
; On active
|
|
spanning-tree
|
|
;------------------------------------------------------- Serveurs radius
|
|
radius-server dead-time 2
|
|
radius-server key %(radius_key)s
|
|
%(radius-serveurs)s
|
|
;------------------------------------------------------- Filtrage mac
|
|
aaa port-access mac-based addr-format multi-colon
|
|
;------------------------------------------------------- Bricoles
|
|
no cdp run
|
|
no stack
|
|
"""
|
|
|
|
interface_template = """interface %(prise)i enable
|
|
name "%(nom)s"
|
|
flow-control%(speed)s
|
|
no lacp
|
|
exit
|
|
"""
|
|
# Serveurs radius
|
|
rad_servs = [ '10.231.136.10' , '10.231.136.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
|
|
sys.path.append('/usr/scripts/gestion/secrets')
|
|
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'] = str(self.db.search(switch)['machine'][0].ip())
|
|
|
|
### 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ètres à affecter
|
|
for key in ( 'uplinks', 'non_uplinks' ) :
|
|
params[key] = []
|
|
|
|
vlans = { 'wifi_tagged' : [] , 'wifi_untagged' : [] ,
|
|
'hotspot_tagged' : [], 'hotspot_untagged' : [],
|
|
'adm_tagged' : [] , 'adm_untagged' : [] ,
|
|
|
|
# VLans pour le reste: le vlan des adhérents, des
|
|
# inconnus et de ceux qui ne paie pas
|
|
'default' : [] }
|
|
|
|
# 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'].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 isinstance(m, BorneWifi): 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]
|
|
# Certaines bornes sont dans des chambres, est-ce le cas ?
|
|
if prise_chbres.has_key(annu_prise):
|
|
chbres = prise_chbres[annu_prise]
|
|
prise_params['nom'] += '+Chambre'
|
|
if len(chbres) > 1 : prise_params['nom'] += 's'
|
|
for chbre in chbres :
|
|
prise_params['nom'] += '_%s%s' % (bat.upper(), chbre)
|
|
vlans['default'].append(prise)
|
|
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 adm == 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'].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
|
|
|
|
# Quelle(s) chambre(s) est/sont sur la prise. A cause du
|
|
# cas PDJ il peux y avoir des prises avec plusieurs
|
|
# chambres.
|
|
chbres = prise_chbres.get(annu_prise, [])
|
|
|
|
# "unauth-vid" est le vlan sur lequel sont envoyé les
|
|
# inconnus, qui est le vlan d'accueil
|
|
params['INTERFACES_CONF'] += """aaa port-access mac-based %(prise)s
|
|
aaa port-access mac-based %(prise)s addr-limit %(nbmac)s
|
|
aaa port-access mac-based %(prise)s logoff-period 3600
|
|
aaa port-access mac-based %(prise)s unauth-vid 7
|
|
""" % { 'nbmac': 1+2*len(chbres), 'prise': prise }
|
|
|
|
# On donne à la prise un nom qui dépend des chambres
|
|
# connectés dessus
|
|
if chbres :
|
|
prise_params['nom'] = 'Chambre'
|
|
if len(chbres) > 1 : prise_params['nom'] += 's'
|
|
for chbre in chbres :
|
|
prise_params['nom'] += '_%s%s' % (bat.upper(), chbre)
|
|
else :
|
|
prise_params['nom'] = 'Inconnu'
|
|
|
|
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 [ 'uplinks', 'non_uplinks' ] :
|
|
params[key] = mk_list(params[key])
|
|
for key, prises in vlans.items() :
|
|
vlans[key]=mk_list(prises)
|
|
|
|
# Config des vlans spéciaux (adm et wifi)
|
|
for v in ('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:]
|
|
|
|
for name, number in config.vlans:
|
|
params["vlan_%s" % name] = number
|
|
|
|
# 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()
|