[hptools] éviter les collisions de mac

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é.
This commit is contained in:
Daniel STAN 2013-07-26 02:07:01 +02:00
parent 6c54abcbf6
commit e05c4be14c

View file

@ -8,6 +8,8 @@ Donne la classe switch qui permet d'effectuer les opérations
élémentaires sur les switchs manageable HP 26xx. élémentaires sur les switchs manageable HP 26xx.
Frédéric PAUGET 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 time import sleep
from sys import stderr, path from sys import stderr, path
@ -15,10 +17,12 @@ from commands import getstatusoutput
from annuaires_pg import chbre_prises, all_switchs from annuaires_pg import chbre_prises, all_switchs
from os.path import exists from os.path import exists
from os import system from os import system
import os
import sys import sys
from re import findall from re import findall
import re import re
from config import vlans from config import vlans
import netsnmp
path.append('/usr/scripts/gestion') path.append('/usr/scripts/gestion')
from ldap_crans import crans_ldap from ldap_crans import crans_ldap
@ -123,6 +127,7 @@ class snmp :
""" """
self.host = host self.host = host
self.version = version self.version = version
self.community = community
if version == '1' or version == '2c' : if version == '1' or version == '2c' :
self.options = "-v %s -c '%s' %s " % ( version, community, host ) self.options = "-v %s -c '%s' %s " % ( version, community, host )
@ -179,10 +184,12 @@ class snmp :
""" """
return self.__exec('snmpset -O vq %s %s %s %s' % (self.options, oid, typ, val ) ) return self.__exec('snmpset -O vq %s %s %s %s' % (self.options, oid, typ, val ) )
def walk(self,base_oid) : def walk(self,base_oid, bin_comp=False) :
""" Retourne le résultat de snmpwalk """ Retourne le résultat de snmpwalk
le retour est un dictionnaire { oid : valeur } 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') lignes = self.__exec('snmpwalk -Ox %s %s' % (self.options, base_oid ) ).split('\n')
result = {} result = {}
for ligne in lignes: for ligne in lignes:
@ -193,6 +200,37 @@ class snmp :
pass pass
return result 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 ### Gestion des switchs proprement dite
@ -228,13 +266,13 @@ class hpswitch :
if not prise : prise = self.prise if not prise : prise = self.prise
if self.__debug : self.__logDest.write("HP DEBUG : show_prise_mac(prise=%s)\n" % prise) if self.__debug : self.__logDest.write("HP DEBUG : show_prise_mac(prise=%s)\n" % prise)
try: try:
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress.%d' % int(prise)) data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress.%d' % int(prise),
bin_comp=True)
macs = [] macs = []
for value in data.itervalues(): for value in data.itervalues():
mac = value.replace(' ', '').lower().replace('"', '') if len(value) != 6:
if not re.match('([0-9a-f]{2}){6}', mac): continue # Should not happen
mac = mac.encode('hex').lower() mac = ':'.join('%02x' % ord(c) for c in value)
mac = "%s:%s:%s:%s:%s:%s" % (mac[0:2], mac[2:4], mac[4:6], mac[6:8], mac[8:10], mac[10:12])
macs.append(mac) macs.append(mac)
return macs return macs
except ValueError: except ValueError:
@ -247,7 +285,8 @@ class hpswitch :
mac = mac.lower() mac = mac.lower()
# On interroge le switch # On interroge le switch
try: try:
data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress') data = self.walk('STATISTICS-MIB::hpSwitchPortFdbAddress',
bin_comp=True)
except ValueError: except ValueError:
print >> sys.stderr, "Le switch %s fait du caca..." % self.switch print >> sys.stderr, "Le switch %s fait du caca..." % self.switch
return None return None