#!/usr/bin/env python
# -*- coding: utf8 -*-
#
#
#   PEB - 01/04/2012 -> now()
#
# Ce script est placé sous la licence libre par défaut
# utilisée au Crans. Ayant la flemme de copier/coller
# celle-ci, démerdez-vous avec un des responsables de
# l'association pour les fioritures.

import os, sys
import sys
import re
from commands import getstatusoutput

# 1 avril 2012 - PEB :
# nécessite apparemment que l'objet conn soit bien créé lors de l'exec
# de annuaires_pg, il faut être root (ou dans je ne sais quel groupe)
# pour que l'authentification de l'user crans avec psycopg2 se fasse
# (plante lamentablement quand j'essaye avec mon compte sur vo, sous
# ipython. Mais si je sudo ipython, ça marche...

def liste_chambres_macs(switch, annuaire):
    u'''
    Fonction générant un dictionnaire (macs) contenant pour chaque prise une
    liste des macs qui y sont actives.
    Reçoit annuaires_pg en second argument, pour éviter l'ouverture de
    multiples connexions sql pour rien.
    '''
    liste_bats = ['a', 'b', 'c', 'g', 'h', 'i', 'j', 'm', 'p']
    
    split = switch.replace('.adm.crans.org', '').split('-')
    bat, num_switch = split[0][-1], int(split[1][0])
    if bat not in liste_bats:
        return {}
    data = walk(switch, 'STATISTICS-MIB::hpSwitchPortFdbAddress')

    liste_chbres = []
    macs = {}
    if data:
        for port in data:
            if port == '':
                continue
            else:
                mac = data[port]
                uplink = annuaire.uplink_prises[bat]
                prise = num_switch * 100 + port
                if prise in uplink:
                    continue

                result = annuaire.reverse(bat, prise)
                if result:
                    chbre = bat+result[0]
                    if chbre in liste_chbres:
                        macs[chbre].extend(mac)
                    else:
                        macs[chbre] = []
                        macs[chbre].extend(mac)
                        liste_chbres.append(chbre)
                    del chbre
                else:
                    # On droppe, c'est des bornes wifi ou autres.
                    pass
    else:
        print "Pas de données pour %s" % (switch)
    return macs

def walk(host, oid):
    u'''
    Hack sale remplaçant la fonction walk contenue dans hptools, qui
    splitte suivant des espaces, ce qui engendre des failles.
    Ici, snmpwalk -Ox (au lieu de -Oq) fait qu'on récupère bien des macs,
    et on splitte suivant le keyword Hex-STRING, qui n'est pas redondant, lui.
    '''
    received = __exec('snmpwalk -Ox -v 1 -c public %s %s' % (host, oid)).split('\n')
    result = {}
    for ligne in received:
        try:
            pport, pmac = ligne.split('Hex-STRING: ')

            port = int(pport.replace('STATISTICS-MIB::hpSwitchPortFdbAddress.', '').split('.')[0])
            mac = pmac.replace(' ', '').lower().replace('"', '')
            if not re.match('([0-9a-f]{2}){6}', mac):
                mac = mac.encode('hex').lower()
            mac = "%s:%s:%s:%s:%s:%s" % (mac[0:2], mac[2:4], mac[4:6], mac[6:8], mac[8:10], mac[10:12])
            
            if not result.has_key(port):
                result[port] = [mac]
            else:
                result[port].append(mac)
        except:
            print "Ligne moisie : %s de l'hôte : %s" % (ligne, host)
    return result
    

def __exec(cmd):
    u'''
    Hack sale pour pas loader inutilement hptools.py
    Exécute une commande et retourne son status et son output.
    '''
    status, response = getstatusoutput(cmd)
    if status:
        response = response.replace('snmpget: ','')
        print 'Erreur : '+response+' : '+cmd
    return response

if __name__ == '__main__':
    switchs = sys.argv[1:]
    for switch in switchs:
        macs = liste_chambres_macs(switch)

    print macs
