# -*- coding: utf-8 -*-

"""
Classe de génération du fichier de l'autostatus
Utilisé par generate.py
"""

# importation des fonctions et classes

import sys, os, commands
sys.path.append('/usr/scripts/gestion')
from ldap_crans import AssociationCrans, BorneWifi
from gen_confs import gen_config

# définition de la classe

def inform(string):
    pass
#    print string


class autostatus(gen_config) :

    # CONFIGURATION #
    #################

    # fichier de l'autostatus
    CONFFILE = '/usr/scripts/var/autostatus/hosts'

    # machines crans à ne pas mettre dans l'autostatus
    pasimportant = [
                    # Serveurs de tests
                    "test.adm.crans.org",
                    "bcfg2tmp0.adm.crans.org",
                    "bcfg2tmp0.crans.org",
                    "bcfg2tmp1.adm.crans.org",
                    "bcfg2tmp1.crans.org",
                    "diskless.crans.org",
                    "notyetbroken.crans.org",
                    "notyetbroken.adm.crans.org",
                    "willbreaksoon.crans.org",
                    "willbreaksoon.adm.crans.org",
                    "obm.crans.org",
                    "obm.adm.crans.org",
                    "batv-3.adm.crans.org",

                    # Config par défaut
                    "non-configure.wifi.crans.org",
                    "kiss.crans.org",
                    "freebox.crans.org",
                    "ssh2.crans.org",
                    "reboot-p1.crans.org",
                    "reboot-p2.crans.org",
                    "reboot-default.crans.org",
                    "minigiga.adm.crans.org",
                    "ytrap-llatsni.crans.org",
                    "pegase.adm.crans.org",

                    # Pas ou plus en production
                    "malloc.crans.org", # serveur inutilisé
                    "morgan.crans.org",
                    "venus.crans.org", # ancienne cableuse
                    "cableuse.crans.org",
                    "dyson-g.crans.org", # dyson n'est plus routeur du G
                    "ftp.federez.net",  # épave du 4J (?)
                    "sila.crans.org", # mort, cf charybde
                    "cerbere.crans.org",    # ne sert pas pour le moment
                    "rouge.crans.org",      # RIP --> domU redisdead
                    "slon.adm.crans.org",   # --> cf nols
                    "ragnarok.crans.org",   # RIP contrôleur disque...
                    "zamok.crans.org",         # c'est en fait fx
                    "bati-2.adm.crans.org",               # N'est plus en place

                    # Bornes wifi de test
                    "bullet5.wifi.crans.org",
                    "toto.wifi.crans.org",
                    "toto2.wifi.crans.org",

                    # Modules de surveillance des locaux
                    "vigile--1i.adm.crans.org",
                    "vigile-0a.adm.crans.org",
                    "vigile-0b.adm.crans.org",
                    "vigile-0c.adm.crans.org",
                    "vigile-0g.adm.crans.org",
                    "vigile-0h.adm.crans.org",
                    "vigile-0j.adm.crans.org",
                    "vigile-0m.adm.crans.org",
                    "vigile-2b.adm.crans.org",
                    "vigile-2g.adm.crans.org",
                    "vigile-4g.adm.crans.org",
                    "vigile-4j.adm.crans.org",
                    ]



    # matrice du fichier d'autostatus
    matrice = u"""# Format : name  address depend,list     contact description

# routeurs vers l'extérieur #
#############################

%%HTML: <TR><td colspan=3 class="table"><font size="+1"><B>Routeurs, dans l'ordre où ils sont entre le crans et l'extérieur :</font></b></TR>

%(route)s

# serveurs du crans #
#####################

%%HTML:  <TR> <TD class=table colSpan=3><p></TD></TR> <TR><td colspan=3 class="table"><font size="+1"><B>Serveurs :</font></b></TR>

%(serveurs)s

# ferme #
#########

%%HTML:  <TR> <TD class=table colSpan=3><p></TD></TR> <TR><td colspan=3 class="table"><font size="+1"><B>La ferme, diffusion de la télé :</font></b></TR>

%(ferme)s

# switchs #
###########

%%HTML:  <TR> <TD class=table colSpan=3><p></TD></TR> <TR><td colspan=3 class="table"><font size="+1"><B>Switchs :</font></b></TR>

%(switchs)s

# bornes wifi #
###############

%%HTML:  <TR> <TD class=table colSpan=3><p></TD></TR> <TR><td colspan=3 class="table"><font size="+1"><B>Bornes wifi :</font></b></TR>

%(bornes)s

# Sites web et Services #
#########################

%%HTML:  <TR> <TD class=table colSpan=3><p></TD></TR> <TR><td colspan=3 class="table"><font size="+1"><B>Sites web et Services HORS de l'ENS:</font></b></TR> <TR><td colspan=3 class="table"><font size="2">(21:FTP ; 80:HTTP)</TR>

%(exterieur)s
"""
    # quelque descriptions de routeurs triés par IP (pour la route vers l'extérieur)

    infos_routeurs = {}
    infos_routeurs [ '138.231.136.4' ] = ['Odlyd', u'Routeur principal du CRANS']
    infos_routeurs [ '138.231.132.1' ] = ['Pioneer.zrt', u'Routeur principal de l\'ENS (interne)']
    infos_routeurs [ '138.231.132.102' ] = ['Pioneer', u'Routeur principal de l\'ENS (interne)']
    infos_routeurs [ '138.231.176.1' ] = ['Pioneer', u'Routeur principal de l\'ENS']
    infos_routeurs [ '193.49.65.1' ] = ['RenaterCachan1' , u'Routeur Renater' ]
    infos_routeurs [ '193.51.181.186' ] = ['RenaterCachan2', u'Routeur Renater']
    infos_routeurs [ '193.51.189.237' ] = ['RenaterJussieu1', u'Routeur Renater']

    # services extérieurs (triés par clé de dictionnaire)
    # format [ nom, ip, port(0=ping), description ]

    services_exterieurs = {}
    services_exterieurs ['Videolan'] = [ 'Videolan', '88.191.250.2', 21, 'Le serveur FTP de Videolan. (Chatenay-Malabry, France)', 'nobody']
    services_exterieurs ['Free'] = [ 'Free', '212.27.60.27', 21, 'Le serveur FTP de free. (France)', 'nobody' ]
    services_exterieurs ['Monde'] = [ 'Monde', '195.154.120.129', 80, 'Est-ce que LeMonde.fr fonctionne ? (France)', 'nobody' ]
    services_exterieurs ['Yahoo!'] = [ 'Yahoo!', '206.190.36.45', 80, 'Est-ce que Yahoo! fonctionne ? (USA)', 'nobody' ]
    services_exterieurs ['Google'] = [ 'Google', '74.125.71.138', 80, 'Est-ce que Google fonctionne ? (USA)', 'nobody' ]

    # personnes à informer pour l'indiponibilité de certains serveurs
    contact = {}

    # service à redémarer
    restart_cmd = ""

    # FIN DE LA CONFIGURATION

    def __str__ (self) :
        return "autostatus"

    def make_config (self, dico ) :
        """
        Transforme le dico en suite lignes de configuration
        """
        liste = dico.keys()
        liste.sort()
        append = ""
        for i in  liste :
            append = append + " ".join( dico[i] ) + "\n"
        return append.encode('utf-8')

    def mail_contact (self, nom) :
        # retourne le mail à qui envoyer les avis pour un serveur
        if nom in self.contact.keys() :
            return self.contact[nom]
        else :
            return 'nobody'

    def _gen (self) :

        # machines crans
        ################
        inform(u"Récupération des machines du Cr@ns")
        machines = AssociationCrans().machines()
        # Quand un serveur est à la fois dans adm et dans autre chose,
        # on garde que le autre chose
        machines2 = machines
        for m in machines:
            if not m.nom().endswith(".adm.crans.org"):
                for n in machines:
                    nom_adm = u"%s.adm.crans.org" % m.nom().split(".")[0]
                    if n.nom() == nom_adm:
                        machines2 = filter(lambda x: x.nom() != nom_adm, machines2)
        machines = machines2

        # tri des machines par type
        bornes = {}
        switchs = {}
        serveurs = {}
        ferme = {}

        # tri des machines
        inform(u"tri des machines")
        for m in machines :

            # machine exclue
            if m.nom() in self.pasimportant :
                continue


            info = m.info()
            if any(i.startswith('<') for i in info):
                continue
            info = filter(lambda i: not i.startswith(';'), info) + ['']

            # les bornes
            if isinstance(m, BorneWifi):
                # C'est une borne
                if info:
                    # on regarde si c'est une borne de batiment
                    if ( info[0][0:3] == "Au " ) and ( len(info[0]) == 5 ) :
                        bornes[ "1-" + info[0][4]+info[0][3] + "-" + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , info[0] ]
                    else :
                        bornes[ "2-" + info[0] + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , info[0] ]
                else :
                    # on met les bornes non définies à la fin (ordre alphabétique)
                    # On ne les met pas, ça pollue l'autostatus
                    # bornes[ "3-" + m.nom() ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , 'Inutilise' ]
                    pass

            # les switchs
            elif any('switch' in i.lower() for i in info):
                # est ce que c'est un batiment
                if 'bat' == m.nom()[0:3] :
                    index = '1-' + m.nom().split(".")[0]
                else :
                    index = '0-' + m.nom().split(".")[0]

                # on ajoute au dictionnaire
                switchs[ index ] = [ m.nom().split(".")[0] , m.nom() , 'none' , self.mail_contact(m.nom()) , info[0] ]

            # la ferme
            elif '.ferme.crans.org' in m.nom() :
                nom = ".".join(m.nom().split(".")[0:2])
                if m.info() :
                    ferme[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , m.info()[0] ]
                else :
                    ferme[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , 'Infos non disponibles' ]

            # les serveurs
            else :
                if ".wifi.crans.org" in m.nom():
                    nom = m.nom().split(".")[0] + ".wifi"
                else :
                    nom = m.nom().split(".")[0]
                serveurs[ nom ] = [ nom , m.nom() , 'none' , self.mail_contact(m.nom()) , info[0] ]

        # route vers l'extérieur
        ########################
        inform(u"Récupération de la route vers l'extérieur")
        # on récupère la route vers l'extérieur
        traceroute = commands.getoutput("/usr/bin/traceroute -I www.free.fr 2> /dev/null | sed 's/\*//g' | sed 's/  */ /g' | sed 's/^ //g' | sed 's/[(,)]//g' | cut -d ' ' -f 2,3").split("\n")
        inform(u"Analyse de la route")
        # initialisation des variables
        in_renater = 0
        route_to_ext = ''
        depends_to_ext = ''

        for routeur in traceroute :

            # on commence à rentrer dans la chaine des routeurs renater
            if 'renater.fr' in routeur :
                in_renater = 1

            # on est plus dans les routeurs renater donc on arrête
            if in_renater and not 'renater.fr' in routeur :
                continue

            # ajout du routeur

            # ip
            try:
                tmp_ip = routeur.split(' ')[1]
            except IndexError:
                print "Skipping %r" % routeur
                continue

            # nom & desciption
            if tmp_ip in self.infos_routeurs.keys() :
                tmp_name = self.infos_routeurs[tmp_ip][0]
                tmp_desc = self.infos_routeurs[tmp_ip][1]
            else :
                tmp_name = routeur.split(' ')[0].split('.')[0]
                tmp_desc = 'Pas de description'

            # dépendances
            if not depends_to_ext :
                tmp_depends = 'none'
                depends_to_ext = tmp_name
            else :
                tmp_depends = depends_to_ext
                depends_to_ext += ',' + tmp_name

            # on l'ajoute à la route
            if route_to_ext :
                route_to_ext += '\n'
            route_to_ext += '%s %s %s %s %s' % (tmp_name, tmp_ip, tmp_depends,self.mail_contact(tmp_name),tmp_desc)

        # services extérieurs
        #####################
        inform(u"Services extérieurs")
        services_exterieurs = {}
        for key in self.services_exterieurs.keys() :
            s = self.services_exterieurs[key]
            if s[2] :
                services_exterieurs[ key ] = [ s[0] + ':' +  str(s[2]), s[1] , depends_to_ext, s[4] , s[3] ]
            else :
                services_exterieurs[ key ] = [ s[0] , s[1] , depends_to_ext, s[4] , s[3] ]

        # génération du fichier
        #######################

        file = self._open_conf(self.CONFFILE, "#")

        # génère le dictionnaire pour les modifications
        dico = {}
        dico['switchs'] = self.make_config(switchs)
        dico['bornes'] = self.make_config(bornes)
        dico['serveurs'] = self.make_config(serveurs)
        dico['ferme'] = self.make_config(ferme)
        dico['route'] = route_to_ext
        dico['exterieur'] = self.make_config(services_exterieurs)

        for item in dico:
            dico[item] = dico[item].decode('utf-8')

        # on écrit dans le fichier de configuration
        file.write( (self.matrice % dico).encode('utf-8') )

        # on ferme le fichier
        file.close()
