#!/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