whos_lc.py 8.77 KB
Newer Older
1
#!/bin/bash /usr/scripts/python.sh
2 3 4 5 6 7
# -*- coding: utf-8 -*-
#
# Auteur : Pierre-Elliott Bécue <becue@crans.org>
# Licence : GPLv3
# Date : 01/09/2014

8
import sys
9
import argparse
10 11
import re
import time
12 13
from ldap import SIZELIMIT_EXCEEDED

14
from gestion.config import encoding
15 16
from gestion import affichage
from gestion import annuaires_pg
17
import lc_ldap.shortcuts
18 19 20 21
import lc_ldap.objets
import lc_ldap.filter2 as lfilter
import lc_ldap.crans_utils

22
ENCODING = encoding.in_encoding
23

24 25 26 27
MACRO_FILTRE_PRISE = re.compile(r'\(prise=(?P<prise>[a-zA-Z][0-9]{3})\)')
MACRO_FILTRE_ADHESION = re.compile(r'\(adhesion=ok\)')
MACRO_FILTRE_CONNEXION = re.compile(r'\(connexion=ok\)')

28
def explore_db(args):
29
    """Utilise le contenu de args pour décider comment explorer la base de données."""
30
    data = search_ldap(args)
31
    data = macro_expand(data, args)
32 33 34
    data = limits(data, args)
    dataLen = sum([len(elem) for elem in data.itervalues()])
    if dataLen:
35 36 37
        for (key, elem) in data.iteritems():
            _header = affichage.style(u"Résultats de type %s trouvés dans la base." % (key,), ['cyan'])
            print _header.encode(ENCODING)
38
            if len(elem) == 1:
39 40 41 42 43 44 45 46
                elem[0].display(
                    historique=args.historique,
                    blacklist=args.blacklist,
                    disp_adresse=args.adresse,
                    disp_telephone=args.telephone,
                    sshfp=args.sshfp,
                    ipsec=args.ipsec,
                    )
47
            else:
48
                print lc_ldap.printing.sprint_list(elem).encode(ENCODING)
49 50 51
                print "%s résultats" % len(elem)

def search_ldap(args):
52
    """Cherche et trie"""
53 54
    data = {}
    if args.ldap:
55
        search_filter = args.filtre.decode(ENCODING)
56
    else:
57 58
        search_filter = lfilter.human_to_ldap(args.filtre.decode(ENCODING))

59 60 61
    if args.macro_filtre:
        search_filter = filter_macro(search_filter)

62
    try:
63
        resultats = LDAP.search(search_filter, sizelimit=args.limite)
64
    except SIZELIMIT_EXCEEDED:
65
        raise EnvironmentError("La limite de résultats LDAP (%s) a été dépassée. Vous pouvez l'augmenter avec l'option -l" % (args.limite,))
66 67

    for elem in resultats:
68 69
        if elem not in data.get(elem.__class__.__name__, []):
            data.setdefault(elem.__class__.__name__, []).append(elem)
70

71 72
    return data

73 74 75 76 77
def macro_expand(data, args):
    """Gère les macros spécifiques à whos_lc.
    Permet de récupérer les propriétaires d'objets cherchés,
    ou les factures ou les machines. De chercher par prise,
    etc etc"""
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120

    new_data = dict(data)

    if args.proprietaire:
        for elem_list in data.itervalues():
            for elem in elem_list:
                if hasattr(elem, 'proprio'):
                    _proprio = elem.proprio()

                    # On a pas besoin du Crans dans le dico
                    if isinstance(_proprio, lc_ldap.objets.AssociationCrans):
                        continue

                    if _proprio not in data.get(_proprio.__class__.__name__, []):
                        new_data.setdefault(_proprio.__class__.__name__, []).append(_proprio)
        args.adherent = True

    return new_data

def filter_macro(filtre):
    """Étend les macros du filtre passé en argument"""

    thetime = lc_ldap.crans_utils.to_generalized_time_format(time.time())

    prise_match = MACRO_FILTRE_PRISE.match(filtre)
    adhesion_match = MACRO_FILTRE_ADHESION.match(filtre)
    connexion_match = MACRO_FILTRE_CONNEXION.match(filtre)

    if prise_match:
        prise = prise_match.groupdict()['prise']
        bat = prise[0]
        chbre = bat + annuaires_pg.reverse(bat, prise[1:])[0]
        filtre = filtre.replace(u"(prise=%s)" % (prise,), u"(chbre=%s)" % (chbre,))

    if adhesion_match:
        args.limite = 0
        filtre = filtre.replace(u"(adhesion=ok)", u"(&(finAdhesion>=%s)(|(aid=*)(cid=*)))" % (thetime,))

    if connexion_match:
        args.limite = 0
        filtre = filtre.replace(u"(connexion=ok)", u"(&(finConnexion>=%s)(|(aid=*)(cid=*)))" % (thetime,))

    return filtre
121

122
def limits(data, args):
123
    """Applique les limitations dans la recherche.
124
    Les cas sont a priori conflictuels.
125

126 127 128 129
    """
    data_restricted = {}
    data_restricted.update(data)
    contentFilter = []
130

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    if args.adherent:
        contentFilter = ["adherent"]
    elif args.club:
        contentFilter = ["club"]
    elif args.machine:
        contentFilter = ["machineFixe", "machineWifi", "machineCrans", "switchCrans", "borneWifi"]
    elif args.crans:
        contentFilter = ["machineCrans", "switchCrans", "borneWifi"]
    elif args.switch:
        contentFilter = ["switchCrans"]
    elif args.borne:
        contentFilter = ["borneWifi"]
    # Special cases.
    elif args.adm:
        contentFilter = []
        out = []
        for machine in data.get('machineCrans', []):
            if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('adm'):
                out.append(machine)
        data_restricted = {'machineCrans' : out,}
    elif args.special:
        contentFilter = []
        out = []
        for machine in data.get('machineCrans', []):
            if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('special'):
                out.append(machine)
        data_restricted = {'machineCrans' : out,}
    elif args.serveur:
        contentFilter = []
        out = []
        for machine in data.get('machineCrans', []):
            if lc_ldap.crans_utils.find_rid_plage(machine['rid'][0].value)[0].startswith('serveur'):
                out.append(machine)
        data_restricted = {'machineCrans' : out,}
165

166 167
    if contentFilter:
        data_restricted = {a: data.get(a, []) for a in contentFilter}
168

169 170 171 172 173
    return data_restricted

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Recherche dans la base des adhérents", add_help=False)
    parser.add_argument('-A', '--adresse', help="Affiche l'adresse de l'adhérent.", action="store_true")
174
    parser.add_argument('-d', '--blacklist', type=int, help="Choix du nombre d'entrées blacklist à afficher pour les entrées détaillées.", action="store", default=10)
175
    parser.add_argument('-f', '--macro_filtre', help="Flag activant la gestion des macros pour le filtre LDAP.", action="store_true")
176 177
    parser.add_argument('-h', '--help', help="Affiche ce message et quitte.", action="store_true")
    parser.add_argument('-i', '--ipsec', help="Affichage de la clef wifi de la machine.", action="store_true")
178
    parser.add_argument('-l', '--limite', type=int, help="Modifier la taille limite de recherche dans la base LDAP", action="store", default=1000)
179
    parser.add_argument('-L', '--historique', type=int, help="Choix du nombre d'entrées d'historique à afficher pour les entrées détaillées.", action="store", default=10)
180 181
    parser.add_argument('-s', '--sshfp', help="Affiche les fingerprint SSH si elles existent.", action="store_true")
    parser.add_argument('-t', '--ldap', help="Utiliser les filtres tels que définis dans ldap", action="store_true")
182
    parser.add_argument('-T', '--telephone', help="Afficher le numéro de téléphone de l'adhérent.", action="store_true")
183
    parser.add_argument('--test', help="Se connecter à la base de test", action="store_true")
184 185
    parser.add_argument('-v', '--verbose', help="Rend le script (très) verbeux.", action="store_true")
    parser.add_argument('filtre', type=str, nargs="?", help="Le filtre whos à utiliser")
186 187 188 189 190 191 192 193

    type_group = parser.add_mutually_exclusive_group(required=False)
    type_group.add_argument('-a', '--adherent', help="Limite l'affichage aux adhérents.", action="store_true")
    type_group.add_argument('--adm', help="Limite l'affichage aux machines adm.", action="store_true")
    type_group.add_argument('-b', '--borne', help="Limite l'affichage aux bornes.", action="store_true")
    type_group.add_argument('-c', '--club', help="Limite l'affichage aux clubs.", action="store_true")
    type_group.add_argument('--crans', help="Limite l'affichage aux machines crans.", action="store_true")
    type_group.add_argument('-m', '--machine', help="Limite l'affichage aux machines.", action="store_true")
194
    type_group.add_argument('-P', '--proprietaire', help="Récupère le propriétaire de l'objet cherché.", action="store_true")
195 196 197 198
    type_group.add_argument('--serveur', help="Limite l'affichage aux serveurs.", action="store_true")
    type_group.add_argument('--special', help="Limite l'affichage aux machines spéciales.", action="store_true")
    type_group.add_argument('--switch', help="Limite l'affichage aux switches (pas encore implémenté).", action="store_true")

199 200 201 202 203
    args = parser.parse_args()

    if args.help:
        parser.print_help()
        sys.exit(0)
204 205
    if args.test:
        LDAP = lc_ldap.shortcuts.lc_ldap_test()
206
    else:
207 208 209
        LDAP = lc_ldap.shortcuts.lc_ldap_readonly()

    explore_db(args)