aboutsummaryrefslogtreecommitdiffstats
path: root/trunk/src/sosreport
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/sosreport')
-rwxr-xr-xtrunk/src/sosreport725
1 files changed, 725 insertions, 0 deletions
diff --git a/trunk/src/sosreport b/trunk/src/sosreport
new file mode 100755
index 00000000..86d66b4d
--- /dev/null
+++ b/trunk/src/sosreport
@@ -0,0 +1,725 @@
+#!/usr/bin/env python
+"""
+Gather information about a system and report it using plugins
+supplied for application-specific information
+"""
+## sosreport.py
+## gather information about a system and report it
+
+## Copyright (C) 2006 Steve Conklin <sconklin@redhat.com>
+
+### This program 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 program 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# pylint: disable-msg = W0611
+# pylint: disable-msg = W0702
+
+import sys
+import os
+#import curses
+from optparse import OptionParser, Option
+import sos.policyredhat
+from sos.helpers import *
+from snack import *
+from threading import Thread, activeCount, enumerate
+import signal
+import logging
+from stat import *
+from time import strftime, localtime, time
+from pwd import getpwuid
+import gettext
+from threading import Semaphore
+
+__version__ = 1.7
+
+__breakHits__ = 0 # Use this to track how many times we enter the exit routine
+
+## Set up routines to be linked to signals for termination handling
+def exittermhandler(signum, frame):
+ doExitCode()
+
+def doExitCode():
+ global __breakHits__
+ __breakHits__ += 1
+ if ( ( activeCount() > 1 ) and ( __breakHits__ == 1 ) ):
+ print "SIGTERM received, multiple threads detected, waiting for all threads to exit"
+ for thread in enumerate():
+ if thread.getName() != "MainThread":
+ thread.join()
+ print "All threads ended, cleaning up."
+ if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ):
+ print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately"
+ ## FIXME: Add thread-kill code (see FIXME below)
+ print "Threads dead, cleaning up."
+ if ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ):
+ print "Multiple SIGTERMs, single thread, exiting without cleaning up."
+ sys.exit(3)
+
+ # FIXME: Add code here to clean up /tmp
+ sys.exit("Abnormal exit")
+
+# Handle any sort of exit signal cleanly
+# Currently, we intercept only sig 15 (TERM)
+signal.signal(signal.SIGTERM, exittermhandler)
+
+## FIXME: Need to figure out how to IPC with child threads in case of
+## multiple SIGTERMs.
+## FIXME: Need to figure out how to handle SIGKILL - we can't intercept it.
+
+# for debugging
+__raisePlugins__ = 1
+
+class SosOption (Option):
+ """Allow to specify comma delimited list of plugins"""
+ ACTIONS = Option.ACTIONS + ("extend",)
+ STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
+ TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
+
+ def take_action(self, action, dest, opt, value, values, parser):
+ if action == "extend":
+ try: lvalue = value.split(",")
+ except: pass
+ else: values.ensure_value(dest, []).extend(lvalue)
+ else:
+ Option.take_action(self, action, dest, opt, value, values, parser)
+
+__cmdParser__ = OptionParser(option_class=SosOption)
+__cmdParser__.add_option("-a", "--alloptions", action="store_true", \
+ dest="usealloptions", default=False, \
+ help="Use all options for loaded plugins")
+__cmdParser__.add_option("-f", "--fastoptions", action="store_true", \
+ dest="fastoptions", default=False, \
+ help="Use only fast options for loaded plugins")
+__cmdParser__.add_option("-g", "--gatheronly", action="store_true", \
+ dest="gatheronly", default=False, \
+ help="Gather information locally but don't package or submit")
+__cmdParser__.add_option("-l", "--list-plugins", action="store_true", \
+ dest="listPlugins", default=False, \
+ help="list existing plugins")
+__cmdParser__.add_option("-n", "--noplugin", action="extend", \
+ dest="noplugins", type="string", \
+ help="skip these plugins", default = [])
+__cmdParser__.add_option("-o", "--onlyplugin", action="extend", \
+ dest="onlyplugins", type="string", \
+ help="enable these plugins only", default = [])
+__cmdParser__.add_option("-e", "--enableplugin", action="extend", \
+ dest="enableplugins", type="string", \
+ help="list of inactive plugins to be enabled", default = [])
+__cmdParser__.add_option("-k", "--pluginopts", action="extend", \
+ dest="plugopts", type="string", \
+ help="plugin options in plugin_name.option=value format")
+__cmdParser__.add_option("-v", "--verbose", action="count", \
+ dest="verbosity", \
+ help="How obnoxious we're being about telling the user what we're doing.")
+__cmdParser__.add_option("-c", "--curses", action="store_true", \
+ dest="use_curses", default=False, \
+ help="Display a text GUI menu to modify plugin options.")
+__cmdParser__.add_option("--no-progressbar", action="store_false", \
+ dest="progressbar", default=True, \
+ help="Do not display a progress bar.")
+__cmdParser__.add_option("--no-multithread", action="store_true", \
+ dest="nomultithread", \
+ help="Disable multi-threaded gathering mode (slower)", default=False)
+(__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args()
+
+def textcolor(text, fg, bg=None, raw=0):
+ colors = { "black":"30", "red":"31", "green":"32", "brown":"33", "blue":"34",
+ "purple":"35", "cyan":"36", "lgray":"37", "gray":"1;30", "lred":"1;31",
+ "lgreen":"1;32", "yellow":"1;33", "lblue":"1;34", "pink":"1;35",
+ "lcyan":"1;36", "white":"1;37" }
+ opencol = "\033["
+ closecol = "m"
+ clear = opencol + "0" + closecol
+ f = opencol + colors[fg] + closecol
+ return "%s%s%s" % (f, text, clear)
+
+def get_curse_options(alloptions):
+ """
+ use curses to enable the user to select some options
+ """
+ # alloptions is an array of (plug, plugname, optname, parms(dictionary)) tuples
+ plugName = []
+ out = []
+
+ # get a sorted list of all plugin names
+ for rrr in alloptions:
+ if rrr[1] not in plugName:
+ plugName.append(rrr[1])
+
+ plugName.sort()
+ plugCbox = CheckboxTree(height=5, scroll=1)
+
+ countOpt = -1
+
+ optDic = {}
+ optDicCounter = 0
+
+ # iterate over all plugins with options
+ for curPlugName in plugName:
+ plugCbox.addItem(curPlugName, (snackArgs['append'],))
+ countOpt = countOpt+1
+
+ for opt in alloptions:
+ if opt[1] != curPlugName:
+ continue
+
+ snt = opt[2] + " ("+opt[3]['desc']+") is " + opt[3]['speed']
+ plugCbox.addItem(snt, (countOpt, snackArgs['append']), item = optDicCounter, selected = opt[3]['enabled'])
+ optDic[optDicCounter] = opt
+ optDicCounter += 1
+
+
+ screen = SnackScreen()
+ bb = ButtonBar(screen, (("Ok", "ok"), ("Cancel", "cancel")))
+ g = GridForm(screen, "Select Sosreport Options", 1, 10)
+ g.add(plugCbox, 0, 0)
+ g.add(bb, 0, 1, growx = 1)
+ result = g.runOnce()
+
+ screen.finish()
+
+ if bb.buttonPressed(result) == "cancel":
+ raise "Cancelled"
+
+ for rrr in range(0, optDicCounter):
+ optDic[rrr][3]['enabled'] = plugCbox.getEntryValue(rrr)[1]
+ out.append((optDic[rrr]))
+
+ return out
+
+class progressBar:
+ def __init__(self, minValue = 0, maxValue = 10, totalWidth=40):
+ self.progBar = "[]" # This holds the progress bar string
+ self.min = minValue
+ self.max = maxValue
+ self.width = totalWidth
+ self.amount = 0 # When amount == max, we are 100% done
+ self.time_start = time()
+ self.eta = 0
+ self.last_amount_update = time()
+ self.update()
+
+ def updateAmount(self, newAmount = 0):
+ if newAmount < self.min: newAmount = self.min
+ if newAmount > self.max: newAmount = self.max
+ if self.amount != newAmount:
+ self.last_amount_update = time()
+ self.amount = newAmount
+ last_update_relative = round(self.last_amount_update - self.time_start)
+ self.eta = round(last_update_relative * self.max / self.amount)
+
+ # generate ETA
+ timeElapsed = round(time() - self.time_start)
+ last_update_relative = round(self.last_amount_update - self.time_start)
+ if timeElapsed >= 10 and self.amount > 0:
+ percentDone = round(timeElapsed * 100 / self.eta)
+ if percentDone > 100:
+ percentDone = 100
+ ETA = timeElapsed
+ elif self.eta < timeElapsed:
+ ETA = timeElapsed
+ else:
+ ETA = self.eta
+ ETA = "[%02d:%02d/%02d:%02d]" % (round(timeElapsed/60), timeElapsed % 60, round(ETA/60), ETA % 60)
+ else:
+ ETA = "[%02d:%02d/--:--]" % (round(timeElapsed/60), timeElapsed % 60)
+ if self.amount < self.max:
+ percentDone = 0
+ else:
+ percentDone = 100
+
+ # Figure out how many hash bars the percentage should be
+ allFull = self.width - 2
+ numHashes = (percentDone / 100.0) * allFull
+ numHashes = int(round(numHashes))
+
+ # build a progress bar with hashes and spaces
+ self.progBar = " [" + '#'*numHashes + ' '*(allFull-numHashes) + "]"
+
+ # figure out where to put the percentage, roughly centered
+ percentPlace = (len(self.progBar) / 2) - len(str(percentDone))
+ percentString = str(percentDone) + "%"
+
+ # slice the percentage into the bar
+ self.progBar = " Progress" + self.progBar[0:percentPlace] + percentString + self.progBar[percentPlace+len(percentString):] + ETA
+
+ def incAmount(self, toInc = 1):
+ self.updateAmount(self.amount+toInc)
+
+ def finished(self):
+ self.updateAmount(self.max)
+ sys.stdout.write(self.progBar + '\n')
+ sys.stdout.flush()
+
+ def update(self):
+ self.updateAmount(self.amount)
+ sys.stdout.write(self.progBar + '\r')
+ sys.stdout.flush()
+
+class XmlReport:
+ def __init__(self):
+ try:
+ import libxml2
+ except:
+ self.enabled = False
+ return
+ else:
+ self.enabled = True
+ self.doc = libxml2.newDoc("1.0")
+ self.root = self.doc.newChild(None, "sos", None)
+ self.commands = self.root.newChild(None, "commands", None)
+ self.files = self.root.newChild(None, "files", None)
+
+ def add_command(self,cmdline,exitcode,stdout = None,stderr = None,f_stdout=None,f_stderr=None, runtime=None):
+ if not self.enabled: return
+
+ cmd = self.commands.newChild(None, "cmd", None)
+
+ cmd.setNsProp(None, "cmdline", cmdline)
+
+ cmdchild = cmd.newChild(None, "exitcode", str(exitcode))
+
+ if runtime:
+ cmd.newChild(None, "runtime", str(runtime))
+
+ if stdout or f_stdout:
+ cmdchild = cmd.newChild(None, "stdout", stdout)
+ if f_stdout:
+ cmdchild.setNsProp(None, "file", f_stdout)
+
+ if stderr or f_stderr:
+ cmdchild = cmd.newChild(None, "stderr", stderr)
+ if f_stderr:
+ cmdchild.setNsProp(None, "file", f_stderr)
+
+ def add_file(self,fname,stats):
+ if not self.enabled: return
+
+ cfile = self.files.newChild(None,"file",None)
+
+ cfile.setNsProp(None, "fname", fname)
+
+ cchild = cfile.newChild(None, "uid", str(stats[ST_UID]))
+ cchild.setNsProp(None,"name", getpwuid(stats[ST_UID])[0])
+ cchild = cfile.newChild(None, "gid", str(stats[ST_GID]))
+ cchild.setNsProp(None,"name", getpwuid(stats[ST_GID])[0])
+ cfile.newChild(None, "mode", str(oct(S_IMODE(stats[ST_MODE]))))
+ cchild = cfile.newChild(None, "ctime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_CTIME])))
+ cchild.setNsProp(None,"tstamp", str(stats[ST_CTIME]))
+ cchild = cfile.newChild(None, "atime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_ATIME])))
+ cchild.setNsProp(None,"tstamp", str(stats[ST_ATIME]))
+ cchild = cfile.newChild(None, "mtime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_MTIME])))
+ cchild.setNsProp(None,"tstamp", str(stats[ST_MTIME]))
+
+ def serialize(self):
+ if not self.enabled: return
+
+ print self.doc.serialize(None, 1)
+
+ def serialize_to_file(self,fname):
+ if not self.enabled: return
+
+ outfn = open(fname,"w")
+ outfn.write(self.doc.serialize(None,1))
+ outfn.close()
+
+def sosreport():
+ # pylint: disable-msg = R0912
+ # pylint: disable-msg = R0914
+ # pylint: disable-msg = R0915
+ """
+ This is the top-level function that gathers and processes all sosreport information
+ """
+ loadedplugins = []
+ skippedplugins = []
+ alloptions = []
+
+ # perhaps we should automatically locate the policy module??
+ policy = sos.policyredhat.SosPolicy()
+
+ # find the plugins path
+ paths = sys.path
+ for path in paths:
+ if path.strip()[-len("site-packages"):] == "site-packages":
+ pluginpath = path + "/sos/plugins"
+ reporterpath = path + "/sos/reporters"
+
+ # Set up common info and create destinations
+
+ dstroot = sosFindTmpDir()
+ cmddir = os.path.join(dstroot, "sos_commands")
+ logdir = os.path.join(dstroot, "sos_logs")
+ rptdir = os.path.join(dstroot, "sos_reports")
+ os.mkdir(cmddir, 0755)
+ os.mkdir(logdir, 0755)
+ os.mkdir(rptdir, 0755)
+
+ # initialize i18n language localization
+ gettext.install('sos', '/usr/share/locale', unicode=False)
+
+ # initialize logging
+ soslog = logging.getLogger('sos')
+ soslog.setLevel(logging.DEBUG)
+
+ # log to a file
+ flog = logging.FileHandler(logdir + "/sos.log")
+ flog.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s'))
+ flog.setLevel(logging.DEBUG)
+ soslog.addHandler(flog)
+
+ # define a Handler which writes INFO messages or higher to the sys.stderr
+ console = logging.StreamHandler(sys.stderr)
+ if __cmdLineOpts__.verbosity > 0:
+ console.setLevel(20 - __cmdLineOpts__.verbosity)
+ __cmdLineOpts__.progressbar = False
+ else:
+ console.setLevel(logging.INFO)
+ console.setFormatter(logging.Formatter('%(message)s'))
+ soslog.addHandler(console)
+
+ logging.VERBOSE = logging.INFO - 1
+ logging.VERBOSE2 = logging.INFO - 2
+ logging.VERBOSE3 = logging.INFO - 3
+ logging.addLevelName(logging.VERBOSE, "verbose")
+ logging.addLevelName(logging.VERBOSE2,"verbose2")
+ logging.addLevelName(logging.VERBOSE3,"verbose3")
+
+ xmlrep = XmlReport()
+
+ # set up dict so everyone can share the following
+ commons = {'dstroot': dstroot, 'cmddir': cmddir, 'logdir': logdir, 'rptdir': rptdir,
+ 'soslog': soslog, 'policy': policy, 'verbosity' : __cmdLineOpts__.verbosity,
+ 'xmlreport' : xmlrep }
+
+ # Make policy aware of the commons
+ policy.setCommons(commons)
+
+ print
+ soslog.info ( _("sosreport (version %s)") % __version__)
+ print
+
+ # generate list of available plugins
+ plugins = os.listdir(pluginpath)
+ plugins.sort()
+
+ # validate and load plugins
+ for plug in plugins:
+ plugbase = plug[:-3]
+ if not plug[-3:] == '.py' or plugbase == "__init__":
+ continue
+ try:
+ #print "importing plugin: %s" % plugbase
+ try:
+ if policy.validatePlugin(pluginpath + plug):
+ pluginClass = importPlugin("sos.plugins." + plugbase, plugbase)
+ else:
+ soslog.warning(_("plugin %s does not validate, skipping") % plug)
+ skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ continue
+ if plugbase in __cmdLineOpts__.noplugins:
+ soslog.log(logging.VERBOSE, _("plug %s skipped (noplugins)") % plugbase)
+ skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ continue
+ if not pluginClass(plugbase, commons).checkenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins:
+ soslog.log(logging.VERBOSE, _("plugin %s is inactive (use -e or -o to enable).") % plug)
+ skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ continue
+ if not pluginClass(plugbase, commons).defaultenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins:
+ soslog.log(logging.VERBOSE, "plugin %s not loaded by default (use -e or -o to enable)." % plug)
+ skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ continue
+ if __cmdLineOpts__.onlyplugins and not plugbase in __cmdLineOpts__.onlyplugins:
+ soslog.log(logging.VERBOSE, _("plugin %s not specified in --onlyplugin list") % plug)
+ skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ continue
+ loadedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ except:
+ soslog.warning(_("plugin %s does not install, skipping") % plug)
+ raise
+ except:
+ soslog.warning(_("could not load plugin %s") % plug)
+ if __raisePlugins__:
+ raise
+
+ # First, gather and process options
+ for plugname, plug in loadedplugins:
+ soslog.log(logging.VERBOSE3, _("processing options from plugin: %s") % plugname)
+ names, parms = plug.getAllOptions()
+ for optname, optparm in zip(names, parms):
+ alloptions.append((plug, plugname, optname, optparm))
+
+ if __cmdLineOpts__.listPlugins:
+ if not len(loadedplugins) and not len(skippedplugins):
+ soslog.error(_("no valid plugins found"))
+ sys.exit(1)
+
+ if len(loadedplugins):
+ print _("The following plugins are currently enabled:")
+ print
+ for (plugname,plug) in loadedplugins:
+ print " %-25s %s" % (textcolor(plugname,"lblue"),plug.get_description())
+ else:
+ print _("No plugin enabled.")
+ print
+
+ if len(alloptions):
+ print _("The following plugin options are available:")
+ print
+ for (plug, plugname, optname, optparm) in alloptions:
+ print " %-25s %s [%d]" % (plugname + "." + optname, optparm["desc"], optparm["enabled"])
+ else:
+ print _("No plugin options available.")
+
+ if len(skippedplugins):
+ print
+ print _("The following plugins are currently disabled:")
+ print
+ for (plugname,plugclass) in skippedplugins:
+ print " %-25s %s" % (textcolor(plugname,"blue"),plugclass.get_description())
+
+ print
+ sys.exit()
+
+ # to go anywhere further than listing the plugins we will need root permissions.
+ #
+ if os.getuid() != 0:
+ print _('sosreport requires root permissions to run.')
+ sys.exit(1)
+
+ # we don't need to keep in memory plugins we are not going to use
+ del skippedplugins
+
+ if not len(loadedplugins):
+ soslog.error(_("no valid plugins were enabled"))
+ sys.exit(1)
+
+ try:
+ raw_input(_("""This utility will collect some detailed information about the
+hardware and setup of your Red Hat Enterprise Linux system.
+This information will be used to diagnose problems with your
+system and will be considered confidential information.
+Red Hat will use this information for diagnostic purposes ONLY.
+
+This process may take a while to complete.
+No changes will be made to your system.
+
+Press ENTER to continue, or CTRL-C to quit.
+"""))
+ except KeyboardInterrupt:
+ print
+ sys.exit(0)
+
+ # setup plugin options
+ if __cmdLineOpts__.plugopts:
+ opts = {}
+ for opt in __cmdLineOpts__.plugopts:
+ try: opt, val = opt.split("=")
+ except: val=1
+ plug, opt = opt.split(".")
+ try: val = int(val) # try to convert string "val" to int()
+ except: pass
+ try: opts[plug]
+ except KeyError: opts[plug] = []
+ opts[plug].append( (opt,val) )
+ for plugname, plug in loadedplugins:
+ if opts.has_key(plugname):
+ for opt,val in opts[plugname]:
+ soslog.log(logging.VERBOSE, "setting option %s for plugin %s to %s" % (plugname,opt,val))
+ plug.setOption(opt,val)
+ del opt,opts,val
+ elif not __cmdLineOpts__.fastoptions and not __cmdLineOpts__.usealloptions:
+ if len(alloptions) and __cmdLineOpts__.use_curses:
+ try:
+ get_curse_options(alloptions)
+ except "Cancelled":
+ sys.exit(_("Exiting."))
+ elif __cmdLineOpts__.fastoptions:
+ for i in range(len(alloptions)):
+ for plug, plugname, optname, optparm in alloptions:
+ if optparm['speed'] == 'fast':
+ plug.setOption(optname, 1)
+ else:
+ plug.setOption(optname, 0)
+ elif __cmdLineOpts__.usealloptions:
+ for i in range(len(alloptions)):
+ for plug, plugname, optname, optparm in alloptions:
+ plug.setOption(optname, 1)
+
+ # Call the diagnose() method for each plugin
+ tmpcount = 0
+ for plugname, plug in loadedplugins:
+ soslog.log(logging.VERBOSE2, "Performing sanity check for plugin %s" % plugname)
+ plug.diagnose()
+ tmpcount += len(plug.diagnose_msgs)
+ if tmpcount > 0:
+ print _("One or more plugin has detected a problem in your configuration.")
+ print _("Please review the following messages:")
+ print
+ for plugname, plug in loadedplugins:
+ for msg in plug.diagnose_msgs:
+ soslog.warning(" * %s: %s", plugname, msg)
+ print
+ try:
+ raw_input( _("Press ENTER to continue, or CTRL-C to quit.\n") )
+ except KeyboardInterrupt:
+ print
+ sys.exit(0)
+
+ # Call the setup() method for each plugin
+ for plugname, plug in loadedplugins:
+ soslog.log(logging.VERBOSE2, "Preloading files and commands to be gathered by plugin %s" % plugname)
+ plug.setup()
+
+ # Setup the progress bar
+ if __cmdLineOpts__.progressbar:
+ # gather information useful for generating ETA
+ eta_weight = len(loadedplugins)
+ for plugname, plug in loadedplugins:
+ eta_weight += plug.eta_weight
+ pbar = progressBar(minValue = 0, maxValue = eta_weight)
+ # pbar.max = number_of_plugins + weight (default 1 per plugin)
+
+ if __cmdLineOpts__.nomultithread:
+ soslog.log(logging.VERBOSE, "using single-threading")
+ else:
+ soslog.log(logging.VERBOSE, "using multi-threading")
+
+ # Call the collect method for each plugin
+ plugrunning = Semaphore(2)
+ for plugname, plug in loadedplugins:
+ soslog.log(logging.VERBOSE, "executing plugin %s" % plugname)
+ if not __cmdLineOpts__.nomultithread:
+ plug.copyStuff(threaded = True, semaphore = plugrunning)
+ else:
+ plug.copyStuff()
+ if __cmdLineOpts__.progressbar:
+ pbar.incAmount(plug.eta_weight)
+ pbar.update()
+ del plugrunning
+
+ # Wait for all the collection threads to exit
+ if not __cmdLineOpts__.nomultithread:
+ finishedplugins = []
+ while len(loadedplugins) > 0:
+ plugname, plug = loadedplugins.pop(0)
+ if not plug.wait(0.5):
+ finishedplugins.append((plugname,plug))
+ soslog.log(logging.VERBOSE2, "plugin %s has returned" % plugname)
+ if __cmdLineOpts__.progressbar:
+ pbar.incAmount(plug.eta_weight)
+ else:
+ soslog.log(logging.VERBOSE3, "plugin %s still hasn't returned" % plugname)
+ loadedplugins.append((plugname,plug))
+ if __cmdLineOpts__.progressbar:
+ pbar.update()
+ loadedplugins = finishedplugins
+ del finishedplugins
+
+ xmlrep.serialize_to_file(rptdir + "/" + "sosreport.xml")
+
+ # Call the analyze method for each plugin
+ for plugname, plug in loadedplugins:
+ soslog.log(logging.VERBOSE2, "Analyzing results of plugin %s" % plugname,)
+ try:
+ plug.analyze()
+ except:
+ # catch exceptions in analyse() and keep working
+ pass
+ if __cmdLineOpts__.progressbar:
+ pbar.incAmount()
+ pbar.update()
+
+ if __cmdLineOpts__.progressbar:
+ pbar.finished()
+ sys.stdout.write("\n")
+
+ # Generate the header for the html output file
+ rfd = open(rptdir + "/" + "sosreport.html", "w")
+ rfd.write("""
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
+ <head>
+ <link rel="stylesheet" type="text/css" media="screen" href="donot.css" />
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>Sos System Report</title>
+ </head>
+
+ <body>
+ """)
+
+
+ # Make a pass to gather Alerts and a list of module names
+ allAlerts = []
+ plugNames = []
+ for plugname, plug in loadedplugins:
+ for alert in plug.alerts:
+ allAlerts.append('<a href="#%s">%s</a>: %s' % (plugname, plugname, alert))
+ plugNames.append(plugname)
+
+
+
+ # Create a table of links to the module info
+ rfd.write("<hr/><h3>Loaded Plugins:</h3>")
+ rfd.write("<table><tr>\n")
+ rr = 0
+ for i in range(len(plugNames)):
+ rfd.write('<td><a href="#%s">%s</a></td>\n' % (plugNames[i], plugNames[i]))
+ rr = divmod(i, 4)[1]
+ if (rr == 3):
+ rfd.write('</tr>')
+ if not (rr == 3):
+ rfd.write('</tr>')
+ rfd.write('</table>\n')
+
+ rfd.write('<hr/><h3>Alerts:</h3>')
+ rfd.write('<ul>')
+ for alert in allAlerts:
+ rfd.write('<li>%s</li>' % alert)
+ rfd.write('</ul>')
+
+
+ # Call the report method for each plugin
+ for plugname, plug in loadedplugins:
+ html = plug.report()
+ rfd.write(html)
+
+ rfd.write("</body></html>")
+
+ rfd.close()
+
+ # Collect any needed user information (name, etc)
+
+ # Call the postproc method for each plugin
+ for plugname, plug in loadedplugins:
+ plug.postproc()
+
+ if __cmdLineOpts__.gatheronly:
+ soslog.info(_("Collected information is in ") + dstroot)
+ soslog.info(_("Your html report is in ") + rptdir + "/" + "sosreport.html")
+ else:
+ # package up the results for the support organization
+ policy.packageResults()
+ # delete gathered files
+ os.system("/bin/rm -rf %s" % dstroot)
+ # automated submission will go here
+
+ # Close all log files and perform any cleanup
+ logging.shutdown()
+
+
+if __name__ == '__main__':
+ try:
+ sosreport()
+ except KeyboardInterrupt:
+ doExitCode()