diff --git a/bcfg2/statistics-summary.py b/bcfg2/statistics-summary.py index 213146f1..51973c12 100755 --- a/bcfg2/statistics-summary.py +++ b/bcfg2/statistics-summary.py @@ -1,115 +1,197 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# + # statistics-summary.py -# ------------------ -# Copyright (C) 2008 Michel Blockelet +# --------------------- -'''Outil pour créer un résumé des statistiques de bcfg2.''' +# Copyright (C) 2008-2009 Michel Blockelet -import os, sys +# 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): - stamps = node.getElementsByTagName('OpStamps') - curtime = 0 - for stamp in stamps: - if float(stamp.getAttribute('start')) > curtime: - curtime = float(stamp.getAttribute('start')) - stats = stamp.parentNode + """Traite les statistiques d'un hôte à partir de son noeud XML.""" - if stats.getAttribute('state') == 'clean': - return u' * %s - %s - clean' % (node.getAttribute('name'), stats.getAttribute('time')) - else: - 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 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 - 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 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') - if ignored == nbbad: - return u' * %s - %s%s' % (node.getAttribute('name'), stats.getAttribute('time'), ignorestr) - else: - print u' * %s - %s' % (node.getAttribute('name'), stats.getAttribute('time')) - print u' State : %s - %d bad%s' % (stats.getAttribute('state'), nbbad, ignorestr) + # 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) - if len(cfgfiles) > 0 and 'config' not in ignore: - print u' * Config files :' - for cfgfile in cfgfiles: - if cfgfile.getAttribute('current_exists') == 'false': - print u' + %s' % cfgfile.getAttribute('name') - else: - print u' * %s' % cfgfile.getAttribute('name') - - if len(packages) > 0 and 'packages' not in ignore: - print u' * Packages :' - for package in packages: - if package.getAttribute('current_version') == '': - print u' + %s :: %s' % (package.getAttribute('name'), package.getAttribute('version')) - else: - print u' * %s :: %s -> %s' % (package.getAttribute('name'), package.getAttribute('current_version'), package.getAttribute('version')) - - if len(actions) > 0 and 'actions' not in ignore: - print u' * Actions :' - for action in actions: - print u' * %s' % action.getAttribute('name') + # 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)) - if len(services) > 0 and 'services' not in ignore: - print u' * Services :' - for service in services: - print u' * %s' % service.getAttribute('name') + # 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) - print '' - return '' if __name__ == '__main__': - if '-h' in sys.argv: - 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: - 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') - statsfile = '/var/lib/bcfg2/etc/statistics.xml' - if os.access(statsfile, os.F_OK): - doc = xml.dom.minidom.parse(statsfile) - cleans = [] - print u'* Bad hosts :' - for node in doc.getElementsByTagName('Node'): - cleans.append(processHost(node, ignore)) - print u'* Clean hosts (or with ignored dirtyness) :' - for clean in cleans: - if clean != '': - print clean - else: - print u'Impossible d\'accéder au fichier de statistiques : %s !' % statsfile + 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