#!/usr/bin/env python # -*- coding: utf-8 -*- # statistics-summary.py # --------------------- # Copyright (C) 2008-2009 Michel Blockelet # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This file is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. """Outil pour créer un résumé des statistiques de bcfg2.""" # Importations import os, sys, time import xml.dom.minidom ## Configuration # Fichier de statistiques statsfile = '/var/lib/bcfg2/etc/statistics.xml' # Nombre de jours à partir desquels l'hôte est considéré comme vieux daysold = 2 def processHost(node, ignore): """Traite les statistiques d'un hôte à partir de son noeud XML.""" # On prend les statistiques les plus récentes (le fichier de statistiques # peut contenir plusieurs runs) stamps = node.getElementsByTagName('OpStamps') curtime = 0 for stamp in stamps: if float(stamp.getAttribute('start')) > curtime: curtime = float(stamp.getAttribute('start')) stats = stamp.parentNode # On regarde l'état if stats.getAttribute('state') == 'clean': state = 'clean' lines = [u' * %s - %s - clean' % (node.getAttribute('name'), stats.getAttribute('time'))] else: # On récupère les différents points pas à jour bad = stats.getElementsByTagName('Bad')[0] nbbad = (int(stats.getAttribute('total')) - int(stats.getAttribute('good'))) cfgfiles = bad.getElementsByTagName('ConfigFile') packages = bad.getElementsByTagName('Package') services = bad.getElementsByTagName('Service') actions = bad.getElementsByTagName('Action') # On ignore ce qu'il faut ignored = 0 ignorestr = u'' if 'config' in ignore and len(cfgfiles) > 0: ignored += len(cfgfiles) ignorestr += u' %d configfiles' % len(cfgfiles) if 'packages' in ignore and len(packages) > 0: ignored += len(packages) ignorestr += u' %d packages' % len(packages) if 'actions' in ignore and len(actions) > 0: ignored += len(actions) ignorestr += u' %d actions' % len(actions) if 'services' in ignore and len(services) > 0: ignored += len(services) ignorestr += u' %d services' % len(services) if ignored > 0: ignorestr = u' - %d ignored :%s' % (ignored, ignorestr) # On affiche tous les trucs pas bons if ignored == nbbad: # On a tout ignoré state = 'ignored' lines = [u' * %s - %s%s' % (node.getAttribute('name'), stats.getAttribute('time'), ignorestr)] else: # On a des trucs à afficher state = 'bad' lines = [] lines.append(u' * %s - %s' % (node.getAttribute('name'), stats.getAttribute('time'))) lines.append(u' State : %s - %d bad%s' % (stats.getAttribute('state'), nbbad, ignorestr)) # Fichiers de configuration if len(cfgfiles) > 0 and 'config' not in ignore: lines.append(u' * Config files :') for cfgfile in cfgfiles: if cfgfile.getAttribute('current_exists') == 'false': lines.append(u' + %s' % cfgfile.getAttribute('name')) else: lines.append(u' * %s' % cfgfile.getAttribute('name')) # Paquets if len(packages) > 0 and 'packages' not in ignore: lines.append(u' * Packages :') for package in packages: if package.getAttribute('current_version') == '': lines.append(u' + %s :: %s' % (package.getAttribute('name'), package.getAttribute('version'))) else: lines.append(u' * %s :: %s -> %s' % (package.getAttribute('name'), package.getAttribute('current_version'), package.getAttribute('version'))) # Actions if len(actions) > 0 and 'actions' not in ignore: lines.append(u' * Actions :') for action in actions: lines.append(u' * %s' % action.getAttribute('name')) # Services if len(services) > 0 and 'services' not in ignore: lines.append(u' * Services :') for service in services: lines.append(u' * %s' % service.getAttribute('name')) lines.append('') return (time.time()-float(stamp.getAttribute('start')) > daysold * 24*60*60, state, lines) if __name__ == '__main__': if '-h' in sys.argv: # Message d'utilisation print u'Outil pour créer un résumé des statistiques de bcfg2.' print u'' print u'Usage :' print u' -c ou --no-config pour ignorer les ConfigFiles' print u' -p ou --no-packages pour ignorer les Packages' print u' -a ou --no-actions pour ignorer les Actions' print u' -s ou --no-services pour ignorer les Services' else: # Lecture des options ignore = [] if '-c' in sys.argv or '--no-config' in sys.argv: ignore.append('config') if '-p' in sys.argv or '--no-packages' in sys.argv: ignore.append('packages') if '-a' in sys.argv or '--no-actions' in sys.argv: ignore.append('actions') if '-s' in sys.argv or '--no-services' in sys.argv: ignore.append('services') # On traite le fichier de statistiques if os.access(statsfile, os.F_OK): doc = xml.dom.minidom.parse(statsfile) oldlines = [] finallines = [u'', u'*** Clean hosts (or with ignored dirtyness) :'] # On récupère les informations des différents hôtes for curnode in doc.getElementsByTagName('Node'): (isold, state, hostlines) = processHost(curnode, ignore) if isold: if state in ['clean', 'ignored']: oldlines += hostlines else: oldlines = hostlines + oldlines else: if state in ['clean', 'ignored']: finallines += hostlines else: finallines = hostlines + finallines # Hôtes vieux print u'*** Old hosts (more than %s days) :' % daysold for line in oldlines: print line print '' # Hôtes à jour print u'*** Bad hosts :' for line in finallines: print line else: print u'Impossible d\'accéder au fichier de statistiques :' print u' %s !' % statsfile