From 711f723af7b32ac37002ecbdf3a03bf0d4732780 Mon Sep 17 00:00:00 2001 From: pauget Date: Sun, 12 Sep 2004 22:22:09 +0200 Subject: [PATCH] Gnration fichier de conf switchs darcs-hash:20040912202209-41617-78c98e9bee1b4ff36b33330890962a67e78ebe9d.gz --- gestion/gen_confs/switchs.py | 508 ++++++++++++++++------------------- 1 file changed, 232 insertions(+), 276 deletions(-) diff --git a/gestion/gen_confs/switchs.py b/gestion/gen_confs/switchs.py index fe75d27a..523d1378 100755 --- a/gestion/gen_confs/switchs.py +++ b/gestion/gen_confs/switchs.py @@ -17,89 +17,22 @@ import string, sys, os, commands, smtplib -sys.path.append('/CRANS/code') -#sys.path.append('/home/fred/Crans/zamok/CRANS/code') -from hptools import hp +import snmp 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 annuaires import chbre_prises, uplink_prises, reverse +from gen_confs import * 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 : - if chbre == '????' : - continue - 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])) - if prise[-1]=='-' : - prise=prise[:-1] - sw.set_prise(int(prise[1:4]),'speed-duplex auto-10') - r = sw.set_prise(int(prise[1:4]),action) - 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: (CRANS) Changement d'état d'une chambre !\n\n" - if action == 'disable': - txt_mail+= "Chambre %s à débrancher." % chbre - else: - txt_mail+= "Chambre %s à 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() +sys.path.append('/CRANS/code') +from hptools import hp -### BROUILLON POUR PLUS TARD - -class switch2(gen_config) : +class switch(gen_config) : # Répertoire ou écire les fichiers de conf - CONF_REP='/tmp/' # avec un / derrière + CONF_REP='/var/tftp_switchs/' # avec un / derrière config = """; J4899A Configuration Editor; Created on release #H.07.32 @@ -135,6 +68,7 @@ vlan 1 ip igmp no ip igmp querier exit +%(MAC_FILTER)s ;-------------------------------------------------------- Accès d'adminsitration no web-management aaa authentication ssh login public-key @@ -156,223 +90,245 @@ no cdp run password manager """ - interface_template = """interface %(prise)i\n%(etat)s - name %(nom)s + interface_template = """interface %(prise)i%(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' + filtre_mac_template = "port-security %i learn-mode static address-limit 3 mac-address%s\n" + def __init__(self,truc): + """ truc est soit : + * une liste de chambres => reconfig de ces chambres + * un nom de switch => reconfig de ce swith""" + self.db = crans_ldap() # connexion LDAP + if type(truc) == list : + # On enlève la chambre "CRA" et "????" + self.chbres = [ch for ch in truc if (ch != "CRA" and ch!= "????") ] + self.switch = None + else : + self.chbres = None + self.switch = truc + def __str__(self) : - return self.nom + return 'switchs' - def __init__(self,qqch='') : - """ - Si qqch='' : reconfigure tous les switchs - Si qqch= (batX-N) : reconfigure que ce switch - Si qqch= (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() + # Rien à faire ici + pass - 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.') + def gen_conf(self) : + if self.chbres : + self.chbres.sort() + for chbre in self.chbres : + self.configure_chbre(chbre) + elif self.switch : + self.configure_switch(self.switch) - fd = self._open_conf(self.CONF_REP + 'switch' + '.conf') - fd.write(self.config % params) - fd.close() + def configure_chbre(self,chbre) : + """ Recontigure la chambre fournie chambre """ + 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' - aff.reinit() + try : + if bat in bat_switchs : + # Action sur le switch + prise = chbre_prises[bat][chbre[1:].lower()] + sw=hp(bat,int(prise[0])) + if prise[-1]=='-' : + prise=prise[:-1] + sw.set_prise(int(prise[1:4]),'speed-duplex auto-10') + r = sw.set_prise(int(prise[1:4]),action) + 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: (CRANS) Changement d'état d'une chambre !\n\n" + if action == 'disable': + txt_mail+= "Chambre %s à débrancher." % chbre + else: + txt_mail+= "Chambre %s à brancher." % chbre + conn.sendmail(From, To , txt_mail % { 'From' : From, 'To' : To }) + conn.quit() 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 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é """ + warn = '' + conn = snmp.hptools(switch) + def add_prise(dict, key, prise) : + """ ajoute la prise à la liste de prise du dictionnaire dict + dict[key] est ensuite de la forme 1,3-7,9-12 (ajout des prises + 1, 3, 4, 5, 6, 7, 9, 10, 11, 12 dans l'ordre) + """ + if dict.has_key(key) : + l1 = dict[key].split(',')[-1] + l2 = dict[key].split('-')[-1] + if len(l1)>len(l2) : + # de la forme xxx-l2 + if int(l2)+1 == prise : + dict[key] = '-'.join(dict[key].split('-')[:-1]) + '-%i'% prise + else : + dict[key] += ',%i' % prise + else : + # de la forme xxx,l1 + if int(l1)+1 == prise : + dict[key] += '-%i' % prise + else : + dict[key] += ',%i' % prise + else : + dict[key] = str(prise) + + return dict + + ### Récupération données du switch + # Bat + bat = switch[3].lower() + params = { 'switch' : switch, 'bat' : bat.upper() } + + # Numéro du switch + try : + sw_num = int(switch[5]) + except : + sw_num = 0 + + # Nombre de prises + nb_prises = conn.nb_prises() + if not nb_prises : + raise RuntimeError("Erreur : impossible de déterminer le nombre de ports") + params['nb_prises'] = nb_prises + + # IP + params['ip'] = commands.getoutput("host %s" % switch).split()[-1] + + ### Configuration prises + params['INTERFACES_CONF'] = '' + params['MAC_FILTER'] = '' + + # Dictionnaire prise -> chambre + prise_chbres = reverse(bat) + + mac_filter=[] + self.aff.iter = nb_prises+1 + + for prise in range(1,nb_prises+1): + self.aff.cycle() + + 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 = add_prise(params,'uplinks',prise) + else : + ### Prise adhérent + params = add_prise(params,'non_uplinks',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']='\n disable' + chbres = [] + + ## Configuration de la prise adhérent + if chbres : + prise_params['nom'] = 'Chambre' + if len(chbres) > 1 : prise_params['nom'] += 's' + + macs = '' + for chbre in chbres : + prise_params['nom'] += '_' + chbre + + # Macs sur la prise + nb = 0 + adh = self.db.search('chbre=%s%s' % (bat.upper(), chbre) )['adherent'] + if nb>=3 : + warn += 'Trop de macs sur la prise %i\n' % prise + continue + if not adh : + continue + elif len(adh) == 1 : + adh = adh[0] + if 'bloq' in adh.blacklist_actif() : continue + for m in adh.machines() : + macs += ' ' + m.mac().encode('iso-8859-15').replace(':','') + nb += 1 + else : + warn += 'Plusieurs adherents dans la chambre %s%s\n' % (bat.upper(), chbre) + + if not macs : + prise_params['etat']='\n disable' + else : + params['MAC_FILTER'] += self.filtre_mac_template % ( prise, macs ) + + 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() + + return warn + +if __name__ == '__main__' : + if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) != 2 : + print "%s " % sys.argv[0].split('/')[-1].split('.')[0] + print "Génération du fichier de configuration de switch donnée." + sys.exit(255) + + sw = switch(sys.argv[1]) + sw.debug = 1 + sw.reconfigure()