#! /usr/bin/env python
# -*- coding: utf-8 -*-

"""
Détection des déménagements non signalés

Auteur : Étienne Chové
"""

import sys, os
sys.path.append('/usr/scripts/gestion')
from hptools import hpswitch
from annuaires_pg import all_switchs, bat_switchs, reverse, uplink_prises
from ldap_crans import crans_ldap
from affich_tools import anim, OK
from email_tools import send_email
import sqlite
import time

# On redirige les sorties si invoqué via cron
if 'cron' in sys.argv[0]:
    so = file('/dev/null', 'a+', 0)
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(so.fileno(), sys.stderr.fileno())

conn = sqlite.connect('/var/lib/misc/demenagement')
conn.autocommit = True
curs = conn.cursor()
try:
    curs.execute("CREATE TABLE machines (host TEXT(128), debut INTEGER);")
    print "SQL : Table machines recrée"
except:
    pass

if '--list' in sys.argv:
    curs.execute("SELECT * FROM machines ORDER BY debut;")
    for r in curs.fetchall():
        print '%25s  %s' % (r[0], time.strftime('%d/%m/%Y %H:%M',time.localtime(r[1])))
    sys.exit(0)

# exemptions :
# liste de tuple à deux éléments :
#      - la machine concernée
#      - la chambre(local) *en minuscules* dans laquelle peut se trouver la machine
#        sans envoyer de mail
# exemple : exempt = [ ("shosur.crans.org", "b511d"), ("blabla.crans.org","bcl2") ]
exempt = []

# nombre minimal de jours pour dire que quelqu'un a déménagé
min_jours = 7
# envoie un mail tous les X jours
re_mail = 7

# construction de rev = { bat : { prise : chbre } }
rev = {}
for bat in bat_switchs:
    rev[bat] = reverse(bat)

# remplissage de l'annuaire chambre = { mac : prise } en interrogeant les switchs
switchs = all_switchs()
progression = anim('Interrogation des switchs',len(switchs))
chambre = {}
for host in switchs:
    progression.cycle()
    switch = hpswitch(host)
    try:
        nb_prises = switch.nb_prises()
    except:
        continue
    for prise in range(1, nb_prises+1):
        if prise < 10:
            prise = '0%d'%prise
        else :
            prise = str(prise)
            
        for mac in switch.show_prise_mac(prise):
            try:
                chambre[mac] = [ host[3] + x for x in rev[host[3]][ host[5] + prise ] ]
            except:
                pass
progression.reinit()
print OK

# interrogation de la base ldap
progression = anim('Interrogation de la base LDAP')
base = crans_ldap().search('paiement=ok')
progression.reinit()
proprios = base['adherent']
print OK

# recherche des erreurs
progression = anim('Recherche des erreurs',len(proprios))

now = int(time.time())
msg=u''
for proprio in proprios:
    if proprio.chbre()=='EXT':
        continue
    progression.cycle()
    for machine in proprio.machines_fixes():
        if not chambre.has_key(machine.mac()):
            # mac non trouvée sur switch
            continue
        
        if proprio.chbre().lower() in chambre[machine.mac()]:
            # la machine est dans sa chambre
            curs.execute("DELETE FROM machines WHERE host='%s';"%machine.nom())
        
        else:
            # on regarde la chambre dans la base
            curs.execute("SELECT debut FROM machines WHERE host='%s';" % machine.nom())
            result = curs.fetchall()
            
            if result:
                # mise à jour de l'entrée, si vu il y a au moins une semaine
                if result[0][0] < now-86400*min_jours:
                    if (machine.nom(),'/'.join(chambre[machine.mac()])) not in exempt:
                        print type(machine.nom())
                        print type(u'/'.join(chambre[machine.mac()]))
                        print type(proprio.chbre())
                        msg += u'%s vu en chambre %s mais déclaré en %s\n' % (
                            machine.nom(),
                            '/'.join(chambre[machine.mac()]),
                            proprio.chbre().lower())
                    # prochain rappel dans 1 semaine
                    curs.execute("UPDATE machines SET debut = '%d' WHERE host = '%s';" % (now+(re_mail-min_jours)*86400, machine.nom()))
            else:
                # nouvelle entrée
                curs.execute("INSERT INTO machines (host,debut) VALUES ('%s', '%d');" % (machine.nom(),now))

progression.reinit()
print OK

# sys.stderr.write(msg.encode('iso8859-15'))
# sys.stderr.flush()
if msg:
    print "Envoi du mail... ",
    send_email('disconnect@crans.org', 'disconnect@crans.org', u'Déménagement(s) non déclaré(s)',
               msg + u'\n\n-- \nGénéré par demenagement.py\n')
    print OK
