#!/bin/bash /usr/scripts/python.sh # -*- coding: utf-8 -*- u""" Script permettant d'obtenir des statistiques sur les VLans actuellement distribués par les switchs. Le script va scanner toutes les prises présentes dans le fichier d'annuaire. S'il est impossbile de se connecter à un switch, on abandonne le batiment concerné À la fin sont affichées quelques statistiques, dont les prises sur lesquelles on a trouvé d'autre VLANs qu'"adherent", ainsi que les machines connectées sur ces prises. Xavier Lagorce - 2009 Gabriel Détraz - 2015 Réparé en 2015, utilise à présent lc_ldap et hptools2 """ import sys, getopt from gestion.annuaires_pg import chbre_prises, bat_switchs from gestion.affich_tools import * from gestion.hptools2 import HPSwitch from gestion.config import vlans from lc_ldap import shortcuts # Accès à la base ldap ldap = shortcuts.lc_ldap_readonly() # On mets les vlans dans l'ordre id/nom vlandict = dict((v,k) for k,v in vlans.items()) def scan_bats(bats, annuaire=chbre_prises, verbose=False): """Fonction permettant de scanner un certain nombre de switchs La fonction scanne les switchs enregistrés de annuaire.py se trouvant dans les bâtiments contenus dans la liste bats. La fonction utilise l'annuaire passé en argument au celui de annuaire.py par défaut. Si verbose est à 'True', la fonction affiche le détails de ses connexions aux switchs La fonction renvoie un triplet (vlans_stats,data,erreurs) : * vlans_stats est un dictionnaire contenant les statistiques des VLANs trouvés * data contient les informations sur les machines se trouvant sur des prises possédant d'autres VLANs que le VLAN 'adhérent' * erreurs contient la liste des noms des switchs sur lesquels il a été impossible de se connecter """ # Initialistation des données : # nombre de prises possédant chaque VLAN vlans_stats = {'adherent' : 0} # liste des résultats particuliers découverts pendant le scan data = [] # liste des noms de switch en erreur : erreurs = [] # On Commence par itérer sur chaque batiment : for bat in bats: prises = dict() for chbre, prise in annuaire(bat).iteritems(): prises[prise] = chbre current_switch = -1 switch_name = ' ' for prise in sorted(prises.keys()): # Si l'on est pas connecté au switch sur lequel se trouve la prise, on en change if current_switch != int(prise[0]) : switch_name = u"bat" + bat + u"-" + prise[0] + u".adm.crans.org" current_switch = int(prise[0]) if verbose: print u"Connexion à " + switch_name + u" ..." try: switch = HPSwitch(switch_name) except ValueError: if verbose: print u"\tImpossible de se connecter à ce switch, abandon du bâtiment..." erreurs.append(switch_name) break else: if verbose: print u"\tConnexion établie" # On récupère les VLANs présents sur la prise try: vlans = switch.get_vlans(int(prise[1:])) if verbose: print vlans print prise[1:] except: if verbose: print u"\tErreur de communication avec " + switch_name print u"\tAbandon du bâtiment..." erreurs.append(switch_name) break if vlans: # Si la prise ne possède que le VLAN adherent, on ne va pas plus loin if len(vlans) == 1 and vlans[0] == 1: vlans_stats[vlandict[vlans[0]]] = vlans_stats[vlandict[vlans[0]]] + 1 else: # Sinon, on récupère tous les VLANs for vlan in vlans: if not (vlan in vlans_stats): vlans_stats[vlandict[vlan]] = 0 vlans_stats[vlandict[vlan]] = vlans_stats[vlandict[vlan]] + 1 # On récupère les données pour les afficher plus tard try: if macres: macs = switch.show_port_macs(int(prise[1:]))[0] else: macs = [] except ConversationError: if verbose: print u"\tErreur de communication avec " + switch_name print u"\tAbandon du bâtiment..." erreurs.append(switch_name) break if macs: for mac in macs: machine = ldap.search(u"macAddress=%s" % mac) try: machine = machine[0] adh = machine.proprio() chbre = bat.upper() + prises[prise] data.append([bat.upper() + prise, chbre, unicode(adh['nom'][0]), unicode(machine['host'][0]), machine.ldap_name, ', '.join(sorted([vlandict[vlan] for vlan in vlans]))]) except IndexError: pass # Si aucune machine n'est connectée, on ajoute quand même une # entrée dans les résultats else: # On tente de trouver le nom de l'adherent : chbre = bat.upper() + prises[prise] adh = ldap.search(u"chbre=%s" % chbre) try: adh = adh[0] nom = unicode(adh['nom'][0]) data.append([bat.upper() + prise, chbre, nom, '-', '-', ', '.join(sorted([vlandict[vlan] for vlan in vlans]))]) except IndexError: pass # On renvoie les résultats return (vlans_stats,data,erreurs) def __usage_brief(err=''): """Affiche un message d'erreur court""" if err: err = u' : ' + err else: err = u'.' print u"Option(s) invalide(s)" + err print u"Pour obtenir de l'aide sur l'utilisation de ce programme utilisez l'option -h" sys.exit(2) def __usage(): """Affichage de l'aide sur l'utilisation du script""" print u""" statsVLans.py : Script permettant d'obtenir des statistiques sur les VLans présents sur le réseau Usage : statsVLans.py OPTIONS options disponibles : -a / --all : Scanne l'intégralité des bâtiments et des switchs présents dans l'annuaire. Incompatible avec l'option --bats. -b / --bats : Permet de spécifier les bâtiments à scanner. Incompatible avec l'option --all. ex : --bats=abh -h / --help : Affiche ce message d'aide. -v / --verbose : Affiche le détail des connexions aux switchs pendant le scan. -m / --macresearch Effectue un traitement des résultats par mac (et non par propriétaire de chambre) Une des options --all ou --bats doit être obligatoirement spécifiée. """ sys.exit(0) # Traitement par défaut si le fichier est directement appellé comme un script if __name__ == "__main__": # Récupération des options if len(sys.argv) == 1: # Pas d'option fournie __usage_brief() try: options, arg = getopt.gnu_getopt(sys.argv[1:],'ab:p:hvm', ['all','bats=','prises=','help','verbose','macresearch']) except getopt.error, msg : __usage_brief(unicode(msg)) # Traitement des options verb = False bats = '' all_prises = False macres = True for opt, val in options: if opt == '-a' or opt == '--all': if bats: __usage_brief(u"les options --all et --bats sont incompatibles !") bats = 'all' elif opt == '-b' or opt == '--bats': if bats == 'all': __usage_brief(u"les options --all et --bats sont incompatibles !") # On évite les doublons de batiments for c in val: if not (c in bats): bats += c elif opt == '-h' or opt == '--help' : __usage() elif opt == '-v' or opt == '--verbose': verb = True elif opt == '-m' or opt == '--macresearch': macres = True if not bats: __usage_brief(u"il faut spécifier des bâtiments à scanner") if bats == 'all': # On récupère tous les bâtiments contenus dans l'annuaire : lbats = bat_switchs else: # On génère une liste avec les bâtiments pour être propre lbats = [bat for bat in bats] # On récupère les statistiques sur les bâtiments demandés vlans_stats, data, erreurs = scan_bats(lbats,verbose=verb) # Fonction helper : def concat(s1,s2): return s1 + u' ' + s2 # Et on les affiche print u"Statistiques sur les batiments :" + reduce(concat,lbats,'') if erreurs: print u"Ces switchs n'ont pas pû être contactés :" for switch in erreurs: print u" * " + switch print u"Statistiques des VLANs : ", vlans_stats print u"" if data: print u"Prises possédant des VLANs différent d''adherent'" print tableau(data, titre = [u"Prise", u"Chambre", u"Adhérent", u"Machine", u"Type", u"VLANs"])