
La fonction walk de hptools fait appel au binaire snmpwalk. Celui-ci renvoi (dans le cas d'une demande des hpSwitchPortFdbAddress) des lignes de la forme: STATISTICS-MIB::hpSwitchPortFdbAddress.$(numerodeport).'$(mac en binaire)' "$(mac en hexa) " Par $(mac en binaire), je désigne une représentation où chaque octet de l'adresse mac est représenté par le caractère ascii correspondant. Cependant, il existe plus d'un caractère ascii non-représentable, et ces caractères sont tous remplacés par des ".". Cela donne des résultats avec plusieurs fois le même oid (quand présents sur la même prise): STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "D4 BE D9 80 CD F8 " STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 D9 12 " STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 DA A8 " STATISTICS-MIB::hpSwitchPortFdbAddress.25.'......' "DC 9F DB 07 DB 1B " (^^^^ ex ici avec des bornes wifi sur le port 25) Cela pose un problème certain car la fonction walk renvoie un dictionnaire indexé par les oid, ce qui écrase donc les données précédentes. On patche en utilisant une lib snmp sachant traiter des oid binaires arbitraires. Comme cela change un peu la sortie de la fonction walk, j'ai préféré garder l'ancienne version, tout en permettant l'utilisation de la nouvelle via un argument optionnel de compatibilité.
567 lines
20 KiB
Python
Executable file
567 lines
20 KiB
Python
Executable file
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Fichier de base d'interface avec les switchs manageables.
|
|
|
|
Donne la classe switch qui permet d'effectuer les opérations
|
|
élémentaires sur les switchs manageable HP 26xx.
|
|
|
|
Frédéric PAUGET
|
|
TODO réécrire ce script (la moitié des fonctions ne marchent plus,
|
|
l'autre ferait bien d'utiliser netsnmp ou équivalent)
|
|
"""
|
|
from time import sleep
|
|
from sys import stderr, path
|
|
from commands import getstatusoutput
|
|
from annuaires_pg import chbre_prises, all_switchs
|
|
from os.path import exists
|
|
from os import system
|
|
import os
|
|
import sys
|
|
from re import findall
|
|
import re
|
|
from config import vlans
|
|
import netsnmp
|
|
|
|
path.append('/usr/scripts/gestion')
|
|
from ldap_crans import crans_ldap
|
|
cl = crans_ldap()
|
|
|
|
try:
|
|
path.append('/usr/scripts/gestion/secrets')
|
|
from secrets import config_snmp_secrete, reconf_snmp
|
|
except:
|
|
# Si a pas le droit de lire config_snmp_secrete
|
|
# on va tenter de tout faire en snmpv1 et communauté public
|
|
def config_snmp_secrete(snmp,switch) :
|
|
snmp = snmp(switch,version='1',community='public')
|
|
return snmp.get, snmp.set, snmp.walk
|
|
|
|
#############################################################################################
|
|
### Définitions de classes utiles
|
|
|
|
# Quelques exceptions
|
|
class ConnectionTimout(Exception) :
|
|
pass
|
|
|
|
class ConnectionClosed(Exception) :
|
|
pass
|
|
|
|
class ConversationError(Exception) :
|
|
pass
|
|
|
|
# Classes de base pour comminiquer (ssh et snmp)
|
|
|
|
import pexpect
|
|
class ssh :
|
|
""" Ouverture d'une connexion ssh, envoi de commandes et récupération du résultat """
|
|
|
|
|
|
def __init__(self,host) :
|
|
""" Ouverture d'une connexion ssh vers le switch choisi """
|
|
self.switch = host.split('.')[0] # On garde pas le fqdn
|
|
self.__sshout = ''
|
|
self.ssh = pexpect.spawn("ssh %s" % host)
|
|
self.ssh.sendline("")
|
|
self.ssh.sendline("configure")
|
|
try:
|
|
self.ssh.expect("%s\(config\)# " % self.switch, timeout=20)
|
|
except pexpect.TIMEOUT:
|
|
print "Timeout !"
|
|
import traceback
|
|
traceback.print_exc()
|
|
print "Contenu du buffer :"
|
|
print self.ssh.before
|
|
|
|
def __del__(self) :
|
|
"""Ferme la connexion : envoi logout et attend """
|
|
self.ssh.sendline("logout")
|
|
self.ssh.send("y")
|
|
self.ssh.send("y")
|
|
self.ssh.close()
|
|
|
|
def send_cmd(self,cmd,timeout=15):
|
|
""" Envoi une commande, attend le prompt et retourne la réponse """
|
|
# Envoi de la commande
|
|
self.ssh.sendline(cmd)
|
|
self.__sshout = ''
|
|
|
|
try:
|
|
# Attente de la réponse
|
|
while 1:
|
|
index = self.ssh.expect([' \[y/n\]\? ',
|
|
'%s\(config\)# ' % self.switch,
|
|
'quit: Control-C'],
|
|
timeout=timeout)
|
|
|
|
self.__sshout = self.__sshout + self.ssh.before
|
|
if index == 0:
|
|
# On répond oui
|
|
self.ssh.send("y")
|
|
elif index == 1:
|
|
# On est revenu au prompt
|
|
break
|
|
elif index == 2:
|
|
# On doit continuer, on envoie espace
|
|
self.ssh.send(" ")
|
|
|
|
return self.__sshout
|
|
except pexpect.TIMEOUT:
|
|
print "Timeout !"
|
|
import traceback
|
|
traceback.print_exc()
|
|
print "Contenu du buffer :"
|
|
print self.ssh.before
|
|
|
|
class snmp :
|
|
""" Classe de communication SNMP """
|
|
def __init__(self,host,version=None,community=None,authentication_protocol=None, authentication_pass=None, username=None, privacy_pass=None) :
|
|
""" host doit être la machine sur laquelle se connecter
|
|
version est la verion du protocole snmp à utiliser : 1, 2c ou 3
|
|
le reste des données doit être ou non fourni suivant la version
|
|
|
|
pour v1 et v2c seule la communauté est prise en compte
|
|
pour v3 authentication_protocol, authentication_pass et username sont requis si accès en authNoPriv
|
|
si privacy_pass est fourni accès en authPriv
|
|
"""
|
|
self.host = host
|
|
self.version = version
|
|
self.community = community
|
|
|
|
if version == '1' or version == '2c' :
|
|
self.options = "-v %s -c '%s' %s " % ( version, community, host )
|
|
elif version =='3' :
|
|
self.fetch_engineid()
|
|
self.options = "-v 3 -e %s -u %s -a %s -A '%s' -l authNoPriv" % ( self._engineid, username, authentication_protocol, authentication_pass )
|
|
if privacy_pass :
|
|
self.options += " -x DES -X '%s' -l authPriv" % privacy_pass
|
|
self.options += " %s " % host
|
|
else :
|
|
raise ValueError('Version incorrecte')
|
|
|
|
def getBaseMac(self):
|
|
''' retourne la Base Mac du switch concerné. C'est elle qui est
|
|
utilisée pour l'engineid.'''
|
|
switch = cl.search("host=%s" % self.host)["machineCrans"][0]
|
|
baseMac = switch.mac().replace(':', '')[0:11] + '0'
|
|
return baseMac
|
|
|
|
def fetch_engineid(self):
|
|
self._engineid = '0000000b0000%s' % self.getBaseMac()
|
|
|
|
def __exec(self,cmd) :
|
|
status, response = getstatusoutput(cmd)
|
|
if status:
|
|
response = response.replace('snmpget: ','')
|
|
print 'Erreur : '+response+' : '+cmd
|
|
return response
|
|
|
|
def get(self,oid) :
|
|
""" Retourne le résultat correspondant à l'oid demandé """
|
|
return self.__exec('snmpget -O vq %s %s ' % ( self.options, oid ) )
|
|
|
|
def get_string(self,oid) :
|
|
""" Retourne le resultat convertit en String correspondant à l'oid demandé. Fonctionne avec les types de depart String, Integer, Hex-String. Raise ValueError sinon. """
|
|
s= self.__exec('snmpget -O v %s %s ' % ( self.options, oid ) )
|
|
if s=="\"\"":
|
|
return ""
|
|
type=s[0:s.find(":")]
|
|
var=s[s.find(":")+2:]
|
|
if type=="STRING":
|
|
return var[1:-1]
|
|
elif type=="Hex-STRING":
|
|
return var.replace(" ","").replace("\n", "").decode("hex")
|
|
elif type=="INTEGER":
|
|
return unicode(var)
|
|
else:
|
|
raise ValueError('Type inconnu')
|
|
|
|
def set(self,oid,typ,val) :
|
|
""" Change la valeur le l'oid donné.
|
|
type est le type de la valeur
|
|
val est la valeur à écrire
|
|
"""
|
|
return self.__exec('snmpset -O vq %s %s %s %s' % (self.options, oid, typ, val ) )
|
|
|
|
def walk(self,base_oid, bin_comp=False) :
|
|
""" Retourne le résultat de snmpwalk
|
|
le retour est un dictionnaire { oid : valeur }
|
|
"""
|
|
if bin_comp:
|
|
return snmp.bin_walk(self, base_oid)
|
|
lignes = self.__exec('snmpwalk -Ox %s %s' % (self.options, base_oid ) ).split('\n')
|
|
result = {}
|
|
for ligne in lignes:
|
|
try:
|
|
oid, valeur = ligne.split('Hex-STRING: ')
|
|
result[oid] = valeur
|
|
except:
|
|
pass
|
|
return result
|
|
|
|
def bin_walk(self, base_oid):
|
|
""" Retourne le résultat de snmpwalk
|
|
le retour est un dictionnaire { oid : valeur }
|
|
TODO: prendre en compte l'auth et le snmp vn, n>1
|
|
TODO: malheureusement, la plupart des fonctions faisant appel
|
|
à walk ne marchent pas out-of-the-box, il faut donc
|
|
d'abord les convertir avant de leur faire utiliser cette nouvelle
|
|
fonction
|
|
"""
|
|
try:
|
|
prefix, b_oid = base_oid.split('::', 1)
|
|
except ValueError:
|
|
raise NotImplementedError('Merci de préciser un MIB')
|
|
|
|
os.environ['MIBS'] = prefix
|
|
# ^^^ Je suis triste de faire ça
|
|
|
|
oid_obj = netsnmp.VarList(netsnmp.Varbind(b_oid))
|
|
# oid_obj est remple des réponses du snmpwalk
|
|
netsnmp.snmpwalk(oid_obj,
|
|
Version = int(self.version),
|
|
DestHost=self.host,
|
|
Community=self.community,
|
|
)
|
|
#UseLongNames=1, #ceci devrait marcher selon la doc
|
|
#en pratique, non (cf /usr/lib/python2.7/dist-packages/netsnmp/client.py)
|
|
|
|
# On renvoie un résultat ressemblant à ce que fait le snmpwalk shell
|
|
return { '%s::%s.%s' % (prefix, res.tag, res.iid): res.val
|
|
for res in oid_obj }
|
|
|
|
#############################################################################################
|
|
### Gestion des switchs proprement dite
|
|
|
|
class hpswitch :
|
|
""" Classe pour l'administration des switchs HP. """
|
|
|
|
# Variables internes
|
|
__debug=0
|
|
__logDest=stderr
|
|
|
|
# Variables internes
|
|
switch = None # nom du switch
|
|
prise = ''
|
|
__conn_ssh = None
|
|
|
|
def __init__(self,switch) :
|
|
""" Switch doit être le nom du switch """
|
|
if self.__debug : self.__logDest.write("HP DEBUG : __init__(switch=%s)\n" % switch )
|
|
self.switch = switch.lower()
|
|
|
|
# Config snmp
|
|
self.get, self.set, self.walk = config_snmp_secrete(snmp,switch)
|
|
|
|
def send_cmd(self,cmd,timout=15) :
|
|
""" Envoi une commande par ssh au switch """
|
|
if not self.__conn_ssh :
|
|
self.__conn_ssh = ssh(self.switch)
|
|
|
|
return self.__conn_ssh.send_cmd(cmd,timout)
|
|
|
|
def show_prise_mac(self,prise='') :
|
|
""" Retourne le(s) adresse(s) MAC présentes sur la prise."""
|
|
if not prise : prise = self.prise
|
|
if self.__debug : self.__logDest.write("HP DEBUG : show_prise_mac(prise=%s)\n" % prise)
|
|
try:
|
|
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress.%d' % int(prise),
|
|
bin_comp=True)
|
|
macs = []
|
|
for value in data.itervalues():
|
|
if len(value) != 6:
|
|
continue # Should not happen
|
|
mac = ':'.join('%02x' % ord(c) for c in value)
|
|
macs.append(mac)
|
|
return macs
|
|
except ValueError:
|
|
# Pas de MAC trouvée
|
|
return []
|
|
|
|
def where_is_mac(self, mac) :
|
|
"""Retrouve la prise correspondant à une adresse MAC donnée"""
|
|
if self.__debug : self.__logDest.write("HP DEBUG : where_is_mac(mac=%s)\n" % mac)
|
|
mac = mac.lower()
|
|
# On interroge le switch
|
|
try:
|
|
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress',
|
|
bin_comp=True)
|
|
except ValueError:
|
|
print >> sys.stderr, "Le switch %s fait du caca..." % self.switch
|
|
return None
|
|
|
|
# On cherche dans data la bonne adresse MAC
|
|
for (onesnmp, onemac) in data.iteritems():
|
|
try:
|
|
onemac = onemac.replace(' ', '').lower().replace('"', '')
|
|
if not re.match('([0-9a-f]{2}){6}', onemac):
|
|
onemac = onemac.encode('hex').lower()
|
|
onemac = "%s:%s:%s:%s:%s:%s" % (onemac[0:2], onemac[2:4], onemac[4:6], onemac[6:8], onemac[8:10], onemac[10:12])
|
|
if onemac.startswith(mac):
|
|
return int(onesnmp.split(".")[1])
|
|
except:
|
|
pass
|
|
onemac = ""
|
|
|
|
# On a rien trouvé
|
|
return None
|
|
|
|
def __scp(self,destination,fichier) :
|
|
if self.__debug :
|
|
self.__logDest.write("HP DEBUG : scp(%s,%s,%s)\n" % (fichier, self.switch, destination))
|
|
if exists(fichier):
|
|
system('scp %s %s:%s' % (fichier, self.switch, destination))
|
|
|
|
def update(self,file=None) :
|
|
""" Upload le fichier de config fourni
|
|
Fait rebooter le switch """
|
|
self.__scp('cfg/startup-config',file)
|
|
|
|
def upgrade(self,file=None) :
|
|
""" Changement de firmware,
|
|
le firmware est dans le fichier fourni en argument
|
|
Ne reboote pas le switch """
|
|
self.__scp('os/primary',file)
|
|
|
|
def add_key(self,file=None) :
|
|
""" Ajoute la clef publique ssh aux clefs autorises
|
|
par le switch """
|
|
self.scp('ssh/mgr_keys',file)
|
|
|
|
def multicast(self,ip='') :
|
|
""" Donne la liste des ports du swich inscrits au flux multicast donné
|
|
Si aucun flux donné teste tous les flux multicast possibles.
|
|
|
|
Retourne un dictionnaire : { adresse du flux : [ ports inscrits ] }
|
|
"""
|
|
if self.__debug : self.__logDest.write("HP DEBUG : multicast(ip=%s)\n" % ip)
|
|
if ip :
|
|
data = self.walk('STATISTICS-MIB::hpIgmpStatsPortIndex2.%s' % ip)
|
|
return { ip : data.values() }
|
|
|
|
else :
|
|
data = self.walk('STATISTICS-MIB::hpIgmpStatsPortIndex2')
|
|
result = {}
|
|
# On veut tout
|
|
for oid, port in data.items() :
|
|
try : ip = '.'.join(oid.split('.')[2:6])
|
|
except : continue
|
|
result.setdefault(ip,[])
|
|
result[ip].append(port)
|
|
|
|
return result
|
|
|
|
def nb_prises(self) :
|
|
""" Retourne le nombre de prises du switch """
|
|
if self.__debug : self.__logDest.write("HP DEBUG : nb_prises()\n")
|
|
return int(self.get('SNMPv2-SMI::mib-2.17.1.2.0'))
|
|
|
|
def version(self) :
|
|
""" Retourne la version du firmware du switch """
|
|
if self.__debug : self.__logDest.write("HP DEBUG : version()\n")
|
|
return self.get('SNMPv2-MIB::sysDescr.0')
|
|
|
|
def enable(self,prise=0) :
|
|
""" Active une prise """
|
|
if not prise : prise = self.prise
|
|
if self.__debug : self.__logDest.write("HP DEBUG : enable(prise=%s)\n" % prise)
|
|
return self.set('IF-MIB::ifAdminStatus.%d' % int(prise), 'i', 1)
|
|
|
|
def disable(self,prise=0) :
|
|
""" Désactive une prise """
|
|
if not prise : prise = self.prise
|
|
if self.__debug : self.__logDest.write("HP DEBUG : disable(prise=%s)\n" % prise)
|
|
return self.set('IF-MIB::ifAdminStatus.%d' % int(prise), 'i', 2)
|
|
|
|
def __is(self,oid,prise) :
|
|
if not prise : prise = self.prise
|
|
prise = str(prise)
|
|
if prise=='all' :
|
|
nb = 0
|
|
for oid,etat in self.walk(oid).items() :
|
|
if etat == 'up' and int(oid.split('.')[1])<51 :
|
|
# Le <51 est ici pour éviter de compter les ports fictifs
|
|
nb += 1
|
|
return nb
|
|
prise = prise.replace('-','')
|
|
return self.get(oid + '.' + prise) == 'up'
|
|
|
|
def is_enable(self,prise=0) :
|
|
""" Retoune True ou False suivant si la prise est activée ou non
|
|
Si prise=all retourne le nombre de prises activées sur le switch """
|
|
if prise != 'all': prise = int(prise)
|
|
return self.__is('IF-MIB::ifAdminStatus',prise)
|
|
|
|
def is_up(self,prise=0) :
|
|
""" Retoune True ou False suivant si la prise est up
|
|
Si prise=all retourne le nombre de prises up sur le switch """
|
|
if prise != 'all': prise = int(prise)
|
|
return self.__is('IF-MIB::ifOperStatus',prise)
|
|
|
|
def nom(self,nom=None,prise=0) :
|
|
""" Retourne ou attribue le nom à la prise fournie """
|
|
if not prise : prise = self.prise
|
|
oid = 'IF-MIB::ifAlias.%d' % int(prise)
|
|
if nom==None :
|
|
return self.get(oid)
|
|
else :
|
|
self.set(oid, 's' , nom)
|
|
|
|
def eth_mode(self,mode=None,prise=0) :
|
|
""" Fixe ou retourne le mode d'une prise
|
|
mode est un tuple : (vitesse, duplex) ou simplement "auto"
|
|
vitesse est : 10 100 ou 1000
|
|
duplex est FD, HD ou auto
|
|
"""
|
|
if not prise : prise = self.prise
|
|
oid = 'CONFIG-MIB::hpSwitchPortFastEtherMode.%d' % int(prise)
|
|
|
|
if mode == None :
|
|
return self.get(oid)
|
|
|
|
# Conversion du mode
|
|
if mode == 'auto' :
|
|
code = 5
|
|
else :
|
|
code = { 'HD' : 2 , 'FD' : 4 , 'AUTO' : 8 }[mode[1].upper()]
|
|
if mode[0] == 10 :
|
|
code -= 1
|
|
elif mode[0] == 1000 :
|
|
if code == 8 : code += 1
|
|
elif code == 2 : raise ValueError('Mode invelide %s' % mode)
|
|
else: code += 1
|
|
|
|
self.set(oid,'i',code)
|
|
|
|
def vlans(self, prise = None):
|
|
"""Récupère les vlans activés sur la prise 'prise'"""
|
|
if not prise:
|
|
prise = self.prise
|
|
prise = int(prise)
|
|
oid_base = 'SNMPv2-SMI::enterprises.11.2.14.11.5.1.7.1.15.3.1.1'
|
|
oid_format = oid_base + '.%(vlan)d.%(prise)d'
|
|
oids = self.walk(oid_base)
|
|
result = []
|
|
for vlan_name, vlan in vlans.iteritems():
|
|
if oid_format % {'vlan': vlan, 'prise': prise} in oids:
|
|
result.append(vlan_name)
|
|
|
|
return result
|
|
|
|
|
|
class sw_chbre(hpswitch) :
|
|
def __init__(self,chbre) :
|
|
# On retrouve la chbre dans l'annuaire
|
|
self.chbre = chbre
|
|
try :
|
|
bat = chbre[0].lower()
|
|
prise = chbre_prises(bat, chbre[1:])
|
|
self.prise_brute = prise
|
|
self.switch = 'bat%s-%i.adm.crans.org' % (bat , int(prise[0]) )
|
|
if prise[-1] == '-' :
|
|
#Prise en 10
|
|
self.prise = int(prise[1:-1])
|
|
self.prise10Mb = True
|
|
else :
|
|
self.prise = int(prise[1:])
|
|
self.prise10Mb = False
|
|
except :
|
|
raise ValueError('Chambre %s inconnue' % chbre)
|
|
|
|
# Config snmp
|
|
self.get, self.set, self.walk = config_snmp_secrete(snmp,self.switch)
|
|
|
|
|
|
def reconfigure(self) :
|
|
""" Reconfigure la prise (nom et vitesse) """
|
|
in10 = self.eth_mode().find('10Mbits') != 1
|
|
|
|
if self.prise10Mb and not in10 :
|
|
self.eth_mode(('10','auto'))
|
|
elif not self.prise10Mb and in10 :
|
|
self.eth_mode('auto')
|
|
|
|
nom = 'Chambre_%s' % self.chbre.capitalize()
|
|
if nom != self.nom() :
|
|
self.nom(nom)
|
|
|
|
class sw_prise(sw_chbre):
|
|
def __init__(self, prise):
|
|
bat = prise[0].lower()
|
|
prise = prise[1:]
|
|
self.prise_brute = prise
|
|
self.switch = 'bat%s-%i.adm.crans.org' % (bat , int(prise[0]))
|
|
if prise[-1] == '-' :
|
|
#Prise en 10
|
|
self.prise = int(prise[1:-1])
|
|
self.prise10Mb = True
|
|
else :
|
|
self.prise = int(prise[1:])
|
|
self.prise10Mb = False
|
|
|
|
# Config snmp
|
|
self.get, self.set, self.walk = config_snmp_secrete(snmp,self.switch)
|
|
|
|
|
|
if __name__ == '__main__' :
|
|
import sys, getopt, re
|
|
|
|
try :
|
|
options, arg = getopt.getopt(sys.argv[1:], 'U:hc:', [ 'help', 'snmp' ])
|
|
except getopt.error, msg :
|
|
print msg
|
|
sys.exit(1)
|
|
|
|
cmds = []
|
|
firmware=''
|
|
wait=True
|
|
for opt, val in options :
|
|
if opt == '-h' or opt=='--help' :
|
|
print "Usage : %s [[-c commande1] -c commande2...] [-U firmware] [--snmp] regex "
|
|
print "Envoi les commandes données au switchs matchant la regex"
|
|
print "si aucune commande est founie lit l'entree standart"
|
|
print "L'envoi de firmware ne fait pas rebooter le switch"
|
|
print "L'option --snmp ajoute les commandes de reconfiguration snmp"
|
|
sys.exit(0)
|
|
|
|
elif opt=='-c' :
|
|
cmds.append(val)
|
|
|
|
elif opt=='-U' :
|
|
firmware=val
|
|
|
|
elif opt=='--snmp' :
|
|
cmds.append(reconf_snmp)
|
|
cmds.append("write memory")
|
|
|
|
# Quels switchs ?
|
|
switchs=[]
|
|
if arg :
|
|
rexp=re.compile(arg[0])
|
|
for sw in all_switchs() :
|
|
if rexp.match(sw) :
|
|
switchs.append(sw)
|
|
|
|
if not switchs :
|
|
print "Aucun switch trouvé"
|
|
print "Note : il faut une _regex_ (!= wilcards au sens du shell)"
|
|
sys.exit(3)
|
|
|
|
if not cmds and not firmware :
|
|
cmds=map(str.strip,sys.stdin.readlines())
|
|
|
|
# Ce que l'on va faire
|
|
print "Commandes :\n\t", '\n\t'.join(cmds)
|
|
print "\nSwitchs : ", ' '.join(switchs)
|
|
print
|
|
|
|
for sw in switchs :
|
|
print sw
|
|
# Au cas ou le switch ne répondrai pas
|
|
s = hpswitch(sw)
|
|
if firmware :
|
|
s.upgrade(firmware)
|
|
for cmd in cmds :
|
|
print s.send_cmd(cmd)
|
|
|