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

import os, sys, commands, time

"""
Permet d'intégrer au wiki les résultats de Monit.

La macro wiki est :
    [[MonitStatus(hotes=host,categories=[All|Process|File],services=[All|Off|On])]]

Exemple :
    [[MonitStatus(All|Off|service@host)
"""

statusfolder = '/usr/scripts/var/monit/status'

def is_ok(state):
    return state.lower() in ['running','accessible', 'status ok']

def NotRunningHosts() :
    """
    Retourne la liste des hotes ou Monit ne tourne pas ou que
    le fichier de status est trop vieux
    """
    hosts = []
    for host in os.listdir(statusfolder) :
        if os.path.getmtime('%s/%s' % (statusfolder,host)) < time.time() - 240 :
            hosts.append(host)
    return hosts

def HostStatus (host) :
    """
    Retourne un dictionnaire représentation de l'état des services de
    la machine.
    """

    status = {}

    f = open('%s/%s' % (statusfolder,host) )

    # c'est un hote sous Debian
    ###########################

    # s est le service qu'on est en trainde parser
    s = None
    for line in f.readlines()[2:] :
        line = line.strip()
        if not line :
            # ligne vide, on passe au service suivant
            s = None
        elif not s :
            # création d'un nouveau service
            s = line.split(' ')[1][1:-1]
            t = line.split(' ')[0]
            # ajout du type s'il n'est pas dedans
            if not status.has_key(t) :
                status[t] = {}
            status[t][s]         = {}
        else :
            # on ajoute les données
            status[t][s][line[:34].strip()] = line[34:].strip()

    # on supprime les données system
    try :
        status.pop('System')
    except :
        pass

    return status

def AllStatus () :
    """
    Retourne la configuration de toutes les machines
    """
    status = {}
    for host in os.listdir(statusfolder) :
        status[host] = HostStatus(host)
    return status

def AllStatusOff () :
    """
    Retourne status avec juste les services off
    """

    status = AllStatus()

    for h in status.keys() :

        # si c'est un host qui est down, on le laisse tel quel pour éviter qu'il le supprime
        if h in NotRunningHosts() :
            continue

        # on supprime les types
        for t in status[h].keys() :

            for s in status[h][t].keys() :

                # on supprime un status s'il est Up
                if is_ok(status[h][t][s]['status']):
                    status[h][t].pop(s)

            # reste-t-il des services dans le groupe
            if not status[h][t] :
                status[h].pop(t)

        # reste-t-il des groupes dans l'hote
        if not status[h] :
            status.pop(h)

    return status

def FormatService(Type, Service, Data, f) :
    """
    Retourne le code HTML d'un sercice
    Type    : type de service
    Service : Nom du service
    Data    : dictionnaire contenant toutes les données Data[info]
    f       : formatter
    """

    result = ''
    result += f.table_row(1)
    result += f.table_cell(1,{'style':'background-color:silver'})
    if Type == 'Device' :
        Service = Service[2:]
    elif Type == 'File' :
        Service = Service[4:]
    result += f.strong(1)
    result += f.text(Service)
    result += f.strong(0)
    result += f.table_cell(0)
    if is_ok(Data['status']):
        result += f.table_cell(1,{'style':'background-color:lime'})
    else :
        result += f.table_cell(1,{'style':'background-color:red'})
    result += f.text(Data['status'])
    result += f.table_cell(0)
    result += f.table_row(0)
    return result

def FormatType(Type, Data, f) :
    """
    Retourne le code HTML d'une liste de services
    Host : nom de l'hote
    Data : dictionnaire contenant toutes les données Data[service][info]
    f    : formatter
    """

    result = ''

    # titre
    result += f.heading(1,3)
    result += f.text(Type)
    result += f.heading(0,3)

    # les services
    result += f.table(1)
    for s in Data.keys() :
        result += FormatService(Type,s,Data[s],f)
    result += f.table(0)

    return result

def FormatHost (Host, Data, f) :
    """
    Retourne le code HTML d'un hôte
    Host : nom de l'hote
    Data : dictionnaire contenant toutes les données Data[type][service][info]
    f    : formatter
    """

    result = ''

    result += f.div(1,id=Host)

    # titre
    result += f.heading(1,2)
    result += f.text(Host)[0].upper() + f.text(Host)[1:]
    result += f.heading(0,2)

    # si monit ne tourne pas
    if Host in NotRunningHosts() :
        return result + Cellule('Monit ne semble pas tourner sur %s' % Host,'yellow',f)

    result += f.table(1)
    result += f.table_row(1)
    for t in Data.keys() :
        result += f.table_cell(1,{'valign':'top'})
        result += FormatType(t,Data[t],f)
        result += f.table_cell(0)

    result += f.table_row(0)
    result += f.table(0)
    result += f.div(0)

    return result

def FormatHosts(Data, f) :
    """
    Retourne le code HTML de tous les hotes fournis
    Data : dictionnaire contenant toutes les données Data[hote][type][service][info]
    f    : formatter
    """

    result = ''

    for h in Data.keys() :
        result += FormatHost(h,Data[h],f)

    return result

def Cellule(texte, couleur, f) :
    """
    Retourne le code HTML d'une cellule formattée aver le formatter f
    """
    code  = f.table(1)
    code += f.table_row(1)
    code += f.table_cell(1,{'style':'background-color:%s' % couleur })
    code += f.text(texte)
    code += f.table_cell(0)
    code += f.table_row(0)
    code += f.table(0)
    return code

def execute(macro, filtre) :
    """
    Corps principal de la macro
    """
    f = macro.formatter

    # on met en forme le filtre
    if not filtre :
        filtre = 'all'
    else :
        filtre = filtre.lower()

    if filtre == 'off' :
        # tous les services off
        status = AllStatusOff()
        if status :
            return FormatHosts(status, f)
        else :
            # aucun service off, on affiche OK
            return Cellule(u'Tous les services semblent opérationnels.','lime',f)

    elif filtre == 'all' :
        # tous les services
        status = AllStatus()
        return FormatHosts(status, f)

    elif '@' in filtre :
        # affichage d'un service simple

        host    = filtre.split('@')[1]
        service = filtre.split('@')[0]
        status  = HostStatus(host)

        # recherche du service dans la config
        s = {}
        for t in status.keys() :
            if service in status[t].keys() :
                s = status[t][service]

        if not s :
            # service non trouvé
            code  = f.table_cell(0)
            code += f.table_cell(1,{'style':'background-color:yellow'})
            code += f.text(u'Service introuvable')
            return code

        # création de la chaine de retour
        code  = f.table_cell(0)
        if is_ok(s['status']):
            code += f.table_cell(1,{'style':'background-color:lime'})
        else :
            code += f.table_cell(1,{'style':'background-color:red'})
        code += f.text(s['status'])
        return code

    else :
        return Cellule('Erreur de filtre','yellow',f)
