#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# uname_bornes.py
# ---------------
# Copyright : (c) 2009, Jeremie Dimino <jeremie@dimino.org>
# Licence   : BSD3

"""Script qui fait un uname sur toute les bornes à la fois.

La sortie est la sortie de `uname -v` sur chaque borne."""

import sys, os, commands
from optparse import OptionParser

def bornes():
    """Renvoie la liste des bornes

    Moyen rapide, mais peut-être un peu crade pour récupérer la liste des bornes:
    on regarde les machines présentes dans 138.231.148.1/24"""
    names = []
    for line in commands.getoutput("host -l wifi.crans.org").splitlines():
        # Chaque ligne est de la forme:
        # "truc.wifi.crans.org has address 138.231.148.42"
        fields = line.split()
        name = fields[0].split(".")[0]
        ip = fields[3]
        network = ip.rsplit(".", 1)[0]
        # On ne prend que les machines du réseau 138.231.148.0/24, à part
        # ragnarok:
        if network == "138.231.148" and ip != "138.231.148.1":
            names.append(name)
    return names

def ssh_exec(host, cmd):
    """Execute une commande en ssh sur une machine et renvoie le résultat"""
    (stdin, stdout, stderr) = os.popen3("ssh -T -x -o BatchMode=yes -o ConnectTimeout=5 %(host)s exec %(cmd)s" % locals())
    stdin.close()
    stderr.close()
    return stdout

def munin(config, cmd, process=(lambda x: x)):
    """plugin munin"""

    if 'autoconf' in sys.argv:
        print 'yes'
        sys.exit(0)

    names = bornes()

    if 'config' in sys.argv:
        print config
        for borne in names:
            print "%s.label %s"% (borne, borne)
        sys.exit(0)

    outputs = {}
    for name in names:
        outputs[name] = ssh_exec(name+".wifi", cmd)

    for name, res in outputs.iteritems():
        value = process(res.read()).split('\n', 1)[0].strip()
        print '%s.value %s' % (name, value)

def main():
    parser = OptionParser(usage=usage)

    parser.add_option('-v', '--uname', help=u"renvoie le uname -v",
                      action='store_const', const='uname -v', dest='cmd', default='uname -v')
    parser.add_option('-u', '--uptime', help=u"renvoie l'uptime",
                      action='store_const', const='uptime', dest='cmd')
    (options, args) = parser.parse_args()

    names = bornes()
    outputs = {}
    for name in names:
        outputs[name] = ssh_exec(name+".wifi", options.cmd)

    # On attend que tous les fils qu'on a lancé terminent, avec une petite
    # animation si la sortie est un terminal:
    count = 0
    total = len(names)
    show_anim = sys.stderr.isatty()
    message = "Réception des résultats: %d/%d"
    if show_anim: sys.stderr.write(message % (count, total))
    while count < total:
        try: os.wait()
        except OSError: break
        count += 1
    if show_anim: sys.stderr.write("\r" + message % (count, total))
    if show_anim: sys.stderr.write("\n")

    # On lit tout les résultats:
    results = {}
    for name, output in outputs.iteritems():
        results[name] = output.read().strip()
        output.close()

    results = results.items()
    results.sort(key=lambda x: x[0])

    for name, result in results:
        if not result:
            print "%-15s failure" % (name + ":")

    for name, result in results:
        if result:
            print "%-15s %s" % (name + ":", result)


if __name__ == "__main__":
    usage = u"""usage:       %prog [OPTION]
Récupère la liste des bornes et récupère le résultat d'une commande sur
toutes les bornes"""
    if len(sys.argv[0].split('_', 1)) > 1:
        plugin = sys.argv[0].split('_', 1)[0]
        if plugin == 'uptime':
            config = """graph_title Uptime Bornes
graph_args --base 1000 -l 0
graph_vlabel uptime in days"""
            def process(uptime):
                if uptime:
#                    print (int (uptime.split()[1]) / (24 * 3600))
                    return str(float (uptime.split()[1]) / (24 * 3600))
                else: return '0'
            munin(config, 'cat /proc/uptime', process=process)
        else: raise NotImplementedError

    else:
        main()
