Version plus pythonesque de HPTools. Pleinement fonctionnelle sous jessie.

* Les requêtes de type lecture seule marchent très bien tout court ;
 * Celles de type écriture sont sans effet sous wheezy. C'est a priori
 un bug dans python-netsnmp
This commit is contained in:
Pierre-Elliott Bécue 2015-04-24 01:55:52 +02:00
parent cd5ae8aaa5
commit a0f0c80ead
8 changed files with 932 additions and 0 deletions

124
gestion/hptools2/tools.py Normal file
View file

@ -0,0 +1,124 @@
#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
"""Fournit des outils et fonctions appelables au besoin"""
from gestion import annuaires_pg
from multiprocessing import Process, Manager
from .switch import HPSwitch
from .mac import MACFactory, format_mac
def filter_uplink(switch, stuff):
"""Filtre les prises uplink d'un retour.
stuff est une liste de la forme
[(port_id, mac), ...]"""
sortie = []
# Retourne "batg", "4.adm.crans.org", par exemple.
bat, num = switch.split('-', 1)
# On filtre ce qui n'est pas utile.
bat = bat[-1]
num = int(num[0])
# On récupère les infos utiles.
uplink = annuaires_pg.uplink_prises[bat]
gen_num_prise = 100 * num
for (port_id, mac) in stuff:
num_prise = gen_num_prise + port_id
if not num_prise in uplink:
sortie.append((port_id, mac))
return sortie
# +--------------------------------------------------------+
# | Mac Tracking Functions |
# +--------------------------------------------------------+
"""Ces fonctions servent à tracker une mac sur le réseau.
La fonction trace_mac s'occupe de ce travail. Elle utilise
la librairie multiprocessing pour spawner un process par
switch, et aller récupérer auprès de ceux-ci la liste des
MACs connectées, et les ports allant bien.
Multiprocessing ne mettant pas en place du partage de variable
par défaut, les objets retournés le sont via un Manager, dans
un dico, sans structure complexe.
Une solution dans laquelle les switches seraient renvoyés dans
leur structure python existe, mais elle est plus coûteuse,
et peu utile dans notre cas. (l'overhead engendré par la méthode
à base de dicos et régénération dans le processus parent est
epsilonesque)"""
def fetch_all_ports(switch, output):
"""Récupère l'ensemble des ports d'un switch, avec les MACS
dessus."""
sw = HPSwitch(switch)
# output est un Manager().dict()
__stuff = sw.fetch_all_ports()
__stuff = filter_uplink(switch, __stuff)
output[switch] = __stuff
def populate_all_switches():
"""Remplit l'ensemble des switches avec les MACS qui sont
présentes sur leurs ports"""
switches = annuaires_pg.all_switchs()
hp_switches = {
switch : HPSwitch(switch)
for switch in switches
}
processes = {}
# La sortie des appels de fetch_all_ports sera écrite dans ce dico.
# On évitera la concurrence en utilisant le nom du switch comme
# séparateur
output = Manager().dict()
# Dans une première boucle, on crée les switches. Et on met
# les processes en mode actif.
for switch in switches:
hp_switches[switch].flush_ports()
processes[switch] = Process(target=fetch_all_ports, args=(switch, output), name=switch)
processes[switch].start()
# On fait la jointure des processes dans une seconde
# boucle, pour s'assurer que les processes ont bien
# tous été lancés avant de commencer à les sonder.
for switch in switches:
processes[switch].join()
for switch in switches:
if output[switch] is not None:
for (iid, val) in output[switch]:
if hp_switches[switch].ports.get(iid, None) is not None:
hp_switches[switch].ports[iid].append_mac(val)
else:
print "Output for switch %s is None." % (switch,)
def trace_mac(mac, in_all_switches=False):
"""Cherche une MAC. Si in_all_switches est à True, commence
par instancier tous les switches, et à les peupler.
Cette méthode est assez agressive, il faut l'utiliser avec
précaution."""
if in_all_switches:
populate_all_switches()
mac = format_mac(mac)
# On boucle sur les macs dans la factory
__mac = MACFactory.get_mac(mac)
if __mac is not None:
# On boucle sur les parents (des ports) à la recherche
# de ceux qui appartiennent au switch courant.
__parents = []
for parent in __mac.parents.itervalues():
__parents.append(parent)
# Si on en a trouvé, on les retourne avec la mac.
if __parents:
return (__mac, __parents)
return None