scripts/gestion/hptools2/tools.py
2015-08-22 05:18:22 +02:00

144 lines
4.9 KiB
Python

#!/bin/bash /usr/scripts/python.sh
# -*- coding: utf-8 -*-
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
"""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(switches=None):
"""Remplit l'ensemble des switches avec les MACS qui sont
présentes sur leurs ports.
Peut également ne remplir qu'une liste spécifique si fournie
en argument."""
if switches == None:
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