scripts/surveillance/statsVlans.py
2015-03-01 18:49:49 +01:00

276 lines
10 KiB
Python
Executable file

#!/usr/bin/env python
# -*- 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
Réparé en 2015, le script remarche excepté la recherche par mac, remplacée par défaut par
la recherche du propriétaire de la chambre (création de l'option -m)
"""
import sys, getopt
from sys import path
path.append('/usr/scripts/gestion')
from annuaires_pg import chbre_prises, bat_switchs
from affich_tools import *
from ldap_crans import crans_ldap
from ldap_crans import MachineCrans, MachineWifi, BorneWifi
from hptools import hpswitch, ConversationError
# Accès à la base ldap
db = crans_ldap()
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.vlans(prise[1:])
if verbose:
print prise[1:]
for vlan in vlans:
print vlan
except ConversationError:
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] == u"adherent":
vlans_stats[vlans[0]] = vlans_stats[vlans[0]] + 1
else:
# Sinon, on récupère tous les VLANs
for vlan in vlans:
if not (vlan in vlans_stats):
vlans_stats[vlan] = 0
vlans_stats[vlan] = vlans_stats[vlan] + 1
# On récupère les données pour les afficher plus tard
try:
if macres:
macs = switch.show_prise_mac(int(prise[1:]))
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:
fm = db.search("mac=%s" % mac)
if len(fm["machine"]) != 0:
m = fm["machine"][0]
if isinstance(m, MachineWifi): t = u"Wifi"
elif isinstance(m, BorneWifi): t = u"Born"
else : t = u"Fixe"
adh = m.proprietaire()
nom = adh.Nom()
data.append([bat.upper() + prise,
adh.chbre(),
adh.Nom(),
m.nom().split('.')[0],
t,
', '.join(sorted(vlans))])
# 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]
fm = db.search("chbre=%s" % chbre)
if len(fm['adherent']) != 0:
nom = fm['adherent'][0].Nom()
elif len(fm['club']) != 0:
nom = fm['club'][0].Nom()
data.append([bat.upper() + prise,
chbre,
nom,
'-',
'-',
', '.join(sorted(vlans))])
# 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 = False
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"])