scripts/gestion/whos.py
bernat e771a7cebb Affichage des adresses MAC prsentes sur les prises
darcs-hash:20041002084849-d1718-3ed894da0f7d005541d9109e2052d5f20cc14d14.gz
2004-10-02 10:48:49 +02:00

823 lines
22 KiB
Python
Executable file

#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# Copyright (C) Frédéric Pauget
# Licence : GPLv2
"""Ce script permet de recherche et d'afficher le détail d'une machine ou
d'un adhérent.
Usage: %(prog)s [options] <chaine de recherche>
La chaine de recherche peut être :
* soit un terme unique, dans ce cas la recherche sera effectuée sur les
champs en bleu ci-dessous.
* soit du type "champ1=valeur1&champ2!=valeur2 ...", les résultats seront
alors limités aux entrées correspondantes à tous les critères.
Les champs de recherche possibles sont :
%(champs_rech)s
Les options de recherches sont :
* limitations sur l'affichage :
-a ou --adherent : limitation de l'affichage aux adhérents
-m ou --machine : limitation de l'affichage aux machines
-c ou --club : limitation de l'affichage aux clubs
-b ou --bornes : limitation de l'affichage aux bornes wifi
--crans : recherche uniquement les machines du crans
* options d'affichage :
-t ou --tech : affichages des infos techniques des machines
à la place des infos administratives dans les résumés.
-i ou --ipsec : montre la clef ipsec des machines wifi
-l <num> ou --limit=<num> : limite du nombre de résultats pour utiliser
le mode d'affichage condensé au lieu du mode détaillé (défaut %(limit_aff_details)i)
-L <num> ou --limit-historique=<num> : limitation du nombre de lignes
d'historique affichées (défaut %(limit_aff_historique)i)
"""
try:
import sys,locale
loc = locale.getdefaultlocale()
if loc[1]:
sys.reallysetdefaultencoding(loc[1])
except:
pass
from ldap_crans import is_actif , crans_ldap, ann_scol, crans
from affich_tools import *
from hptools import sw_chbre
limit_aff_details = 1
limit_aff_historique = 4
aff_ipsec = 0
def aff(qqch,mtech=0) :
""" Affichage de qqch.
qqch peut être une liste d'instances des classes adhérent ou machine
(un seul type dans la liste) dans ce cas :
* si la longueur de la liste est inférieure à limit_aff_details
affiche les propriétés détaillées de chaque élément.
* sinon résume dans un tabeau des principales propriétés
si qqch est une instance seul la traité comme une liste à une élément
Si mtech = 1 affiches les infomations techniques des machines plutot
qu'administratives dans le tableau des propriétés
"""
if type(qqch) != list :
qqch = [ qqch ]
if len(qqch) > limit_aff_details :
t = qqch[0].idn
if t == 'aid' :
print adhers_brief(qqch)
elif t == 'mid' :
if mtech : print list_machines(qqch)
else : print machines_brief(qqch)
elif t == 'cid' :
print clubs_brief(qqch)
else :
i = 0
for c in qqch :
t = c.idn
if i : print coul(u'='*80,'cyan')
i = 1
if t == 'aid' : print adher_details(c)
elif t == 'mid' :
print machine_details(c)
elif t == 'cid' : print club_details(c)
if len(qqch) > 1:
print "Total: %d" % len(qqch)
def adhers_brief(adhers) :
"""
Formatage sous forme de tableau des infos sur la liste d'adhérent fournie :
* aid
* prénom nom
* chambre
* machines
"""
data = [ ( u'aid' , u'Prénom Nom' , u'Chbre', u'P', u'C', u'Machines' ) ]
for a in adhers :
## Etat administratif
ok = u'\x1b[1;32mo\x1b[1;0m'
nok = u'\x1b[1;31mn\x1b[1;0m'
# Paiement
if ann_scol in a.paiement() : paid = ok
else : paid = nok
# Précablage
if ann_scol+1 in a.paiement() : paid = coul(paid,'f_vert')
# Carte d'étudiant
if ann_scol in a.carteEtudiant() : carte = ok
else : carte = nok
machines = ''
# Récupération des machines
for machine in a.machines() :
nom = machine.nom().split('.')[0]
if machine.blacklist_actif() : k = 'rouge'
else : k= ''
if machines : machines += ', ' + coul(nom,k)
else : machines = coul(nom,k)
# Données
data.append((a.id() , a.Nom(), a.chbre(),paid,carte,machines ))
return u"Machines en rouge = machines avec limitation de services\n" + \
u"P : paiement année en cours, le fond vert indique le précâblage\n" + \
u"C : carte d'étudiant année en cours\n" + \
tableau([5, 30 , 5, 1, 1,30], data)
def machines_brief(machines) :
"""
Formatage sous forme d'un tableau des propriétés de la liste de machine :
* mid
* type (fixe ou wifi, born)
* nom
* adresse IP
* adresse MAC
* si blacklistée
"""
data = [ ( u'mid' , u'Type', u'Nom de machine', u'Propriétaire', u'Chbre', u'Limitation' ) ]
for m in machines :
t, bl = __bases_machines(m)
# Propriétaire
a = m.proprietaire()
p = a.Nom()
# A jour administrativement
if ann_scol not in a.paiement() or ann_scol not in a.carteEtudiant() :
p = coul(p,'rouge')
# Données
data.append((m.id() , t, m.nom().split('.')[0], p, a.chbre(), bl))
return u"Le propriétaire en rouge signale un problème administratif\n" + \
tableau([5, 4, 18, 30, 5, 10], data)
def clubs_brief(clubs) :
"""
Formatage sous forme de tableau des infos sur la liste de clubs fournie :
* cid
* nom
* local
* machines
"""
data = [ ( u'cid' , u'Nom ', u'Local',u'P', u'Responsable', u'Machines' ) ]
for c in clubs :
## Etat administratif
ok = u'\x1b[1;32m\xa4\x1b[1;0m'
nok = u'\x1b[1;31m\xa4\x1b[1;0m'
# Paiement
if ann_scol in c.paiement() : paid = ok
else : paid = nok
# Précablage
if ann_scol+1 in c.paiement() : paid = coul(paid,'f_vert')
machines = ''
# Récupération des machines
for machine in c.machines() :
nom = machine.nom().split('.')[0]
if machine.blacklist_actif() : k = 'rouge'
else : k= ''
if machines : machines += ', ' + coul(nom,k)
else : machines = coul(nom,k)
# Responsable
resp = c.responsable().Nom()
# Données
data.append((c.id() , c.Nom(), c.local(),paid, resp, machines ))
return u"Machines en rouge = machines avec limitation de services\n" + \
u"P : signature charte année en cours, le fond vert indique le précâblage\n" + \
tableau([5, 15 , 6, 1, 21, 24], data)
def list_machines(machines) :
"""
Formatage sous forme d'un tableau des propriétés de la liste de machine :
* mid
* type (fixe ou wifi)
* nom
* adresse IP
* adresse MAC
* si blacklistée
"""
data = [ ( u'mid' , u'Type', u'Nom de machine', u'Adresse IP', u'Adresse MAC', u'Limitation' ) ]
for m in machines :
t, bl = __bases_machines(m)
# Données
data.append((m.id() , t, m.nom().split('.')[0], m.ip(), m.mac(), bl))
return tableau([5, 4, 18, 17, 19, 10], data)
def list_bornes(bornes) :
"""
Formatage sous forme d'un tableau des propriétés de la liste de bornes wifi :
* mid
* nom
* adresse IP
* adresse MAC
* puissance
* canal
* lieu (la première remarque en fait)
"""
data = [ ( u'mid' , u'Nom', u'Adresse IP', u'Adresse MAC', u'C' , u'P', u'Lieu') ]
for b in bornes :
t, bl = __bases_machines(b)
if t != 'born' : continue
# Données
try :
l = b.info()[0]
except :
l = u'????'
data.append((b.id() , b.nom().split('.')[0], b.ip(), b.mac(), b.canal(), b.puissance(),l ))
return u"C=canal, P=puissance\n" + tableau([5, 14, 17, 19, 2, 2, 13], data)
def adher_details(adher) :
"""
Affichage du détail des propriétés d'un adhérent
"""
f=''
# Aid
f+= coul(u'aid=%s ' % adher.id() ,'bleu')
# Nom, prenom
f += coul(u'Nom : ','gras') + "%s\n" % adher.Nom()
# Mail
if adher.mail().find('@')!=-1 :
f += coul(u'Adresse mail : ','gras') + "%s" % adher.mail()
else :
f += coul(u'Login : ','gras') + "%s\t" % adher.mail()
alias = ', '.join([adher.cannonical_alias()] + adher.alias())
if alias :
if alias[0]==',' :
# Cannonical étéait vide
alias = alias[2:]
f += coul(u'Alias : ','gras') + alias
f+= u'\n'
# Etat administratif
f += coul(u'Etat administratif : ','gras')
jour=1
if ann_scol not in adher.carteEtudiant() :
f += coul(u"manque carte d'étudiant",'violet')
jour = 0
if ann_scol not in adher.paiement() :
if not jour : f += ' et '
f += coul(u"cotisation %s/%d non réglée"% (ann_scol, ann_scol+1 ),'violet')
jour = 0
if jour :
f += coul(u"à jour",'vert')
f += '\n'
# Telephone
tel = adher.tel()
if tel != 'inconnu' :
try :
tel = u'%s %s %s %s %s' % ( tel[:2], tel[2:4], tel[4:6], tel[6:8], tel[8:] )
except :
pass
f += coul(u'Numéro de téléphone : ','gras') + "%s\n" % tel.ljust(12)
# Adresse
chbre = adher.chbre()
if chbre == 'EXT' :
# Adhérent extérieur
addr = adher.adresse()
if addr[0] :
f += coul(u'Adresse : ','gras')
f += addr[0] + u'\n'
if addr[1] != ' ' : f += u' ' + addr[1] + u'\n'
f+= u' ' + addr[2] + u' ' + addr[3] + '\n'
else :
# Chambre + prise (d'après annuaire)
f += coul(u'Chambre : ','gras') + u"%s " % chbre
prise = adher.prise()
if prise :
f += u'(prise %s' % prise
f += prise_etat(chbre)
f += prise_macs(chbre)
f += ')'
f += '\n'
# Etudes
if adher.etudes(1).isdigit() :
f += coul(u'Etudes : ','gras')+ "%s %s%s\n" % \
( adher.etudes(0), adher.etudes(1), adher.etudes(2) )
elif adher.etudes(0) :
f += coul(u'Etudes : ','gras')+ "%s %s %s\n" % \
( adher.etudes(0), adher.etudes(1), adher.etudes(2) )
# Role dans l'assoce
d = adher.droits()
if d :
f += coul(u"Droits sur les serveurs : ",'gras') + ', '.join(d)
f += u'\n'
# Paiement
if adher.paiement() :
if len(adher.paiement()) == 1 :
f += coul(u'Cotisation payée pour l\'année scolaire :','gras')
else :
f += coul(u'Cotisation payée pour les années scolaires :','gras')
g = u''
for an in adher.paiement() : g += u" %i-%i" % ( an, an+1 )
if len(g) > 35 : f += '\n\t'
f += g
f += u'\n'
# Cartes d'étudiant fournie
if adher.carteEtudiant() :
if len(adher.carteEtudiant()) == 1 :
f += coul(u"Carte d'étudiant fournie pour l'année scolaire :",'gras')
else :
f += coul(u"Carte d'étudiant fournie pour les années scolaires :",'gras')
g = u''
for an in adher.carteEtudiant() : g += u" %i-%i" % ( an, an+1 )
if len(g) > 25 : f += '\n\t'
f += g
f += u'\n'
f += _blacklist(adher)
f += _info(adher)
f += _hist(adher)
# Formatage des machines aussi
f += coul(u'Machine(s) : ','gras')
m = adher.machines()
if m :
f += u'\n' + list_machines(m)
else :
f += u'aucune'
return f
def machine_details(machine) :
"""
Formatage du détail des propriétés d'une machine
"""
f = ''
f+= coul(u'mid=%s ' % machine.id(),'bleu')
# Type de machine
if machine.ipsec() : a='Machine wifi'
elif machine.canal() : a='Borne wifi'
else : a='Machine fixe'
f+= coul(a+' : ' ,'gras')
f+= "%s\n" % machine.nom()
# Alias ?
alias = machine.alias()
if machine.alias() :
f += coul(u'Alias : ' ,'gras') + ', '.join(alias)
f+= '\n'
f+= coul(u'IP : ','gras') + "%s\t\t" %machine.ip()
f+= coul(u'MAC : ','gras') + "%s\n" %machine.mac()
# Propriétaire
f+= coul(u'Propriétaire : ','gras')
try :
f += machine.proprio + coul(' (adhérent détruit)', 'jaune')
a = crans()
except :
a = machine.proprietaire()
f += "%s" % a.Nom()
if a.chbre() : f += " (%s)" % a.chbre()
f+= '\n'
# Adhérent blacklisté ?
bl = a.blacklist_actif()
if bl :
f += coul(u'Restrictions sur adhérent : ','gras')
f += coul(u', '.join(bl),'rouge')
f += '\n'
# Borne wifi
if machine.puissance() :
f += coul(u'Puissance : ','gras') + machine.puissance()
f += coul(u'\tCanal : ', 'gras') + machine.canal()
f += '\n'
if aff_ipsec and machine.ipsec() :
f += coul(u'Clef IPsec : ','gras') + machine.ipsec()
f += '\n'
# Ports spéciaux
if machine.portTCPin() :
f += coul(u'Ports TCP ouvert ext->machine : ','gras') + machine.portTCPin() + '\n'
if machine.portTCPout() :
f += coul(u'Ports TCP ouvert machine->ext : ','gras') + machine.portTCPout() + '\n'
if machine.portTCPin() :
f += coul(u'Ports UDP ouvert ext->machine : ','gras') + machine.portUDPin() + '\n'
if machine.portUDPout() :
f += coul(u'Ports UDP ouvert machine->ext : ','gras') + machine.portUDPout() + '\n'
f += _blacklist(machine)
f += _info(machine)
f += _hist(machine)
return f
def club_details(club) :
"""
Affichage du détail des propriétés d'un adhérent
"""
f=''
# Cid
f+= coul(u'cid=%s ' % club.id() ,'bleu')
# Nom
f += coul(u'Nom : ','gras') + "%s\n" % club.Nom()
# Etat administratif
f += coul(u'Etat administratif : ','gras')
jour=1
if ann_scol not in club.paiement() :
if not jour : f += ' et '
f += coul(u"charte %s/%d non signée"% (ann_scol, ann_scol+1 ),'violet')
jour = 0
if jour :
f += coul(u"à jour",'vert')
f += '\n'
# Chambre + prise
f += coul(u'Local : ','gras') + "%s " % club.local()
prise = club.prise()
if prise :
f += '(prise %s' % prise
f += prise_etat(club.chbre())
f += ')'
f += '\n'
# Paiement
if club.paiement() :
f += coul(u'Charte signée pour les années scolaires :','gras')
g = ''
for an in club.paiement() : g += " %i-%i" % ( an, an+1 )
if len(g) > 35 : f += '\n\t'
f += g
f += '\n'
f += _blacklist(club)
f += _info(club)
f += _hist(club)
# Formatage des machines aussi
f += coul(u'Machine(s) : ','gras')
m = club.machines()
if m :
f += '\n' + list_machines(m)
else :
f += 'aucune'
return f
###########################################
# Fonctions annexes de formatage de données
def _blacklist(clas) :
""" Formatage blackliste de la classe fournie """
f = u''
for event in clas.blacklist() :
if is_actif(event) :
# Colorisation si sanction en cours
c = 'rouge'
else :
c = 'blanc'
f += u"%s\n\t " % coul(u'du %s au %s : %s, %s' % tuple(event.split(',')) ,c)
f = f[:-6] # supression des espaces superflus
if f :
return coul(u'Blackliste : ', 'gras') + f
else :
return ''
def _info(clas) :
""" Formatage des remarques de la classe fournie """
f= u''
c = clas.info()
if c :
f += coul(u'Remarque :\n ' ,'gras')
f += u'\n '.join(c)
f += u'\n'
return f
def _hist(clas) :
""" Formatage de l'historique de la classe fournie """
if limit_aff_historique==0 : return ''
f=''
h = clas.historique()
h.reverse()
if h :
f += coul(u'Historique : ','gras')
for i in range(0,limit_aff_historique) :
try :
a = h[i] # Produit une erreur si i trop grand
if i !=0 : f += ' '
f += '%s\n' % a
except :
break
try :
if h[i+1] : f += ' [...]\n'
except :
None
return f
def __bases_machines(m) :
""" Retourne [ type de la machines, blacklist ] """
#Type
if m.ipsec() : t='wifi'
elif m.canal() : t='born'
else : t='fixe'
# Déconnectée ?
b = m.blacklist_actif()
if not b :
bl = '-'
elif len(b) == 1 :
bl = coul(b[0],'rouge')
else :
bl = coul(u'cf détails','rouge')
return t , bl
def prise_macs(chbre) :
f = ''
try :
# On ajoute une partie des adresses MAC qui sont sur la prise
conn = sw_chbre(chbre)
result = conn.show_prise_mac()
f += ',\n\t\t'
if len(result) == 0:
f += coul('aucune MAC détectée', 'rouge')
else:
f += 'MACs: %s' % ", ".join(result[0:2])
if len(result) > 3:
f += ' [...]'
except:
# Switch non manageable
pass
return f
def prise_etat(chbre) :
f = ''
try :
# On met aussi l'état
conn = sw_chbre(chbre)
result = conn.status()
if result['etat']=='up' :
f += ', ' + coul('machine branchée','vert')
if result['vitesse_max'] == '10Mbps' :
f+= ', ' + coul('prise en 10Mbps','jaune')
elif result['activée'] == 'down' :
f+= ', ' + coul('prise désactivée','rouge')
else :
f+= ', activée, lien non détecté'
except :
# Switch non manageable
pass
return f
##############################################################################
## Partie dévolue au système de recherche
def __usage_brief(err='') :
""" Message d'erreur """
if err : cprint(err,'gras')
print "Pour obtenir de l'aide sur l'utilisation de ce programme utilisez l'option -h"
sys.exit(2)
def __usage() :
""" Comment ca marche ? """
list = ['']
for c in base.auto_search_champs.values() :
for champ in c :
coul_champ = coul(champ,'bleu')
if list[-1] == '' :
list[-1] = coul_champ
l = len(champ)
else :
l += len(champ) + 2
if l < 80 :
list[-1] += ', ' + coul_champ
else :
list.append(coul_champ)
l = len(champ)
for c in base.non_auto_search_champs.values() :
for champ in c :
l += len(champ) + 2
if l < 80 :
list[-1] += ', ' + champ
else :
list.append(champ)
l = len(champ)
print __doc__ % { 'prog' : sys.argv[0].split('/')[-1] ,
'champs_rech' : '\n'.join(list) ,
'limit_aff_details' : limit_aff_details ,
'limit_aff_historique' : limit_aff_historique }
sys.exit(0)
def __recherche() :
"""
Recherche et affichage des résultats à partir des options founies (sys.argv)
"""
global aff_ipsec, limit_aff_details, limit_aff_historique, debug
# Récupération des options
if len(sys.argv) == 1 :
# Pas d'option fournie
__usage_brief()
try :
options, arg = getopt.getopt(sys.argv[1:], 'hamctbil:L:', [ 'debug', 'help', 'adherent', 'machine', 'club' , 'tech', 'bornes', 'limit=', 'limit-historique=', 'ipsec', 'crans' ])
except getopt.error, msg :
__usage_brief(msg)
# Traitement des options
only_adh=0
only_mac=0
only_club=0
only_bornes=0
only_crans=0
mtech = 0
for opt, val in options :
if opt == '-h' or opt=='--help' :
__usage()
elif opt =='--debug' :
# Mode debug
debug = 1
elif opt == '-l' or opt =='--limit':
# Passage mode condensé, mode détaillé
try : limit_aff_details = int(val)
except :
__usage_brief('Valeur du paramètre %s incorecte (doit être un entier positif)' % opt)
elif opt == '-L' or opt =='--limit-historique':
# Limitation du nombre de lignes d'historique
try : limit_aff_historique = int(val)
except :
__usage_brief('Valeur du paramètre %s incorecte (doit être un entier positif)' % opt)
elif opt in [ '-a', '--adherent' ] :
only_adh = 1
print "Affichage limité aux adhérents."
elif opt in [ '-m', '--machine' ] :
only_mac = 1
print "Affichage limité aux machines."
elif opt in [ '-c', '--club' ] :
only_club = 1
print "Affichage limité aux clubs."
elif opt == '--crans' :
only_crans = 1
mtech = 1
print "Affichage limité aux machines du crans."
elif opt in [ '-b', '--bornes' ] :
only_bornes = 1
print "Affichage limité aux bornes wifi."
# On va tenter de limiter un peu la recherche
if not arg :
# Recherche initiale sans critère
arg = [ 'canal=*&host=*.crans.org']
elif arg[0].find('=')!=-1 :
# Recherche avec critères
arg += [ '&canal=*' ]
elif opt in [ '-t', '--tech' ] :
# Format affichage des machines
mtech = 1
elif opt in [ '-i', '--ipsec' ] :
# Affichage des clefs ipsec
aff_ipsec = 1
if only_adh + only_mac + only_club + only_bornes > 1 :
__usage_brief('Options utilisées incompatibles')
try :
if only_crans :
res = { 'machine' : crans().machines() , 'adherent' : [] , 'club' : [] }
else :
if not arg :
# Pas de chaine de recherche fournie
__usage_brief('Chaine de recherche incorrecte.')
res = base.search(' '.join(arg))
except ValueError, c :
__usage_brief(c.args[0])
# Traitement du résultat
if not res['adherent'] and not res['machine'] and not res['club']:
print "Aucun résultat trouvé."
sys.exit(3)
# L'affichage souhaité a été précisé ?
elif only_bornes :
if not res['machine'] :
print 'Aucun résultat à afficher'
sys.exit(4)
else :
if len(res['machine']) > limit_aff_details :
print list_bornes(res['machine'])
else :
aff(res['machine'])
elif only_adh :
if res['adherent'] : aff(res['adherent'])
elif res['machine'] :
to_aff=[]
traite =[]
for m in res['machine'] :
a = m.proprietaire()
if a.idn != 'aid' or a.id() in traite : continue
traite.append(a.id())
to_aff.append(m.proprietaire())
if not(to_aff) :
print 'Aucun résultat à afficher'
sys.exit(4)
aff(to_aff)
elif res['club'] :
print 'Aucun résultat à afficher'
sys.exit(4)
elif only_mac :
if res['machine'] : aff(res['machine'],mtech)
else :
to_aff = []
for a in res['adherent'] + res['club'] :
to_aff += a.machines()
aff(to_aff)
elif only_club :
if res['club'] : aff(res['club'])
elif res['machine'] :
to_aff=[]
traite =[]
for m in res['machine'] :
a = m.proprietaire()
if a.idn != 'cid' or a.id() in traite : continue
if a.id() in traite : continue
traite.append(a.id())
to_aff.append(m.proprietaire())
if not(to_aff) :
print 'Aucun résultat à afficher'
sys.exit(4)
aff(to_aff)
elif res['adherent'] :
print 'Aucun résultat à afficher'
sys.exit(4)
# Non : on affiche tout.
else :
if res['adherent'] :
cprint("Résultats trouvés parmi les adhérents :",'cyan')
aff(res['adherent'])
if res['machine'] :
cprint("Résultats trouvés parmi les machines :",'cyan')
aff(res['machine'],mtech)
if res['club']:
cprint("Résultats trouvés parmi les clubs :",'cyan')
aff(res['club'])
if __name__ == '__main__' :
global debug
debug = 0
import sys, getopt
base = crans_ldap()
try :
__recherche()
except KeyboardInterrupt :
print "Recherche interrompue par l'utilisateur."
sys.exit(255)
except SystemExit, c :
# Fin
sys.exit(c)
except :
print """Une erreur fatale c'est produite durant l'exécution.
Pour l'amélioration de ce programme merci de prévenir nounou en spécifiant la
marche à suivre pour reproduire cette erreur."""
if debug :
print '-'*40
print 'Détails techniques :'
import traceback
traceback.print_exc()
sys.exit(1)