#!/usr/bin/env python ## sosreport.py ## Implement policies required for the sos system support tool ## Copyright (C) 2006 Steve Conklin ### 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. import sys import os import curses from optparse import OptionParser import sos.policyredhat from sos.helpers import * from snack import * from threading import Thread if os.getuid() != 0: print 'You must run sosreport as root!' sys.exit(1) # for debugging raiseplugins = 1 cmdParser=OptionParser() cmdParser.add_option("-a","--alloptions",action="store_true",dest="alloptions",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("-l","--list-plugins",action="store_true",dest="listPlugins",default=False,help="list existing plugins") cmdParser.add_option("-n","--noplugin",action="append",dest="noplugins",help="list of plugin _not_ to load") 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("-m","--multithreaded",action="store_true",dest="multithread",help="Use the multithreaded information gathering mode to speed up the report") (cmdLineOpts,cmdLineArgs)=cmdParser.parse_args() #print cmdLineOpts def get_curse_options(alloptions): #http://www.amk.ca/python/howto/curses/ #http://gnosis.cx/publish/programming/charming_python_6.html #http://www.wanware.com/tsgdocs/snack.html # /usr/share/doc/newt-devel-0.51.6/ # # allooptions is an array of (plug, plugname, optname, parms(dictionary)) tuples plugName=[] out=[] # get a sorted list of all plugin names for p in alloptions: if p[1] not in plugName: plugName.append(p[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 optName=opt[2] enabled=opt[3]['enabled'] speed=opt[3]['speed'] optDesc=opt[3]['desc'] snt=optName+" ("+optDesc+") is "+speed plugCbox.addItem(snt,(countOpt,snackArgs['append']),item=optDicCounter,selected=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() for i in range(0, optDicCounter): froo, wantit = plugCbox.getEntryValue(i) optDic[i][3]['enabled'] = wantit out.append((optDic[i])) return out def sosreport(): "This is the top-level function that gathers and processes all sosreport information" loadedplugins = [] alloptions = [] threads = [] # TODO 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" # TODO process command line to: # load unsigned plugins # disable one or more plugins # set fast or slow collection without options menu presentation # Set up common info and create destinations dstroot = sosFindTmpDir() os.chmod(dstroot, 0755) 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) # open log file logfd = open(logdir + "/sos.log", "w") # set up dict so everyone can share the following commons = {'dstroot': dstroot, 'cmddir': cmddir, 'logdir': logdir, 'rptdir': rptdir, 'logfd': logfd, 'policy': policy} # validate and load plugins plugins = os.listdir(pluginpath) if cmdLineOpts.listPlugins: for plug in plugins: try: if ((plug[-3:] == '.py') and (plug != "__init__.py")): plugbase = plug[:-3] pidot = "sos.plugins." + plugbase print plugbase except: print "ouch" sys.exit() for plug in plugins: if ((plug[-3:] == '.py') and (plug != "__init__.py")): try: plugbase = plug[:-3] pidot = "sos.plugins." + plugbase #print "importing plugin: %s" % plugbase try: if policy.validatePlugin(pluginpath + plug): PluginClass = importPlugin(pidot, plugbase) else: print "Plugin %s does not validate, skipping" % plug continue loadedplugins.append((plugbase, PluginClass(plugbase, commons))) except: print "Plugin %s does not install, skipping" % plug raise continue except: # TODO do better if raiseplugins: raise print "plugin load failed for %s" % plug # Iterate over plugins for each stage # First, gather and process options for plugname, plug in loadedplugins: if cmdLineOpts.verbosity > 3: print "processing options from plugin: %s" % plugname try: len(cmdLineOpts.noplugins) if plugname not in cmdLineOpts.noplugins: names, parms = plug.getAllOptions() for optname, optparm in zip(names, parms): alloptions.append((plug, plugname, optname, optparm)) except: names, parms = plug.getAllOptions() for optname, optparm in zip(names, parms): alloptions.append((plug, plugname, optname, optparm)) if not cmdLineOpts.fastoptions and not cmdLineOpts.alloptions: cursedOptions=get_curse_options(alloptions) elif cmdLineOpts.fastoptions: for i in range(len(alloptions)): for plug, plugname, optname, optparm in alloptions: if optparm['speed']=='fast': plug.setOption(optname,1) elif cmdLineOpts.alloptions: for i in range(len(alloptions)): for plug, plugname, optname, optparm in alloptions: plug.setOption(optname,1) # Call the setup method for each plugin for plugname, plug in loadedplugins: if cmdLineOpts.verbosity > 1: print "Setting up plugin module %s" % plugname, plug.setup() # Call the collect method for each plugin for plugname, plug in loadedplugins: if cmdLineOpts.verbosity > 0: print "Executing plugin %s" % plugname, if cmdLineOpts.multithread: plug.doCollect(cmdLineOptions.verbosity) else: plug.copyStuff(cmdLineOptions.verbosity) # Wait for all the collection threads to exit for plugname, plug in loadedplugins: if cmdLineOpts.verbosity > 1: print "Waiting for plugin %s to return" % plugname, plug.wait() # Call the analyze method for each plugin for plugname, plug in loadedplugins: if cmdLineOpts.verbosity > 1: print "Analyzing results of plugin %s" % plugname, plug.analyze(cmdLineOpts.verbosity) # Sort the module names to do the report in alphabetical order loadedplugins.sort() # Generate the header for the html output file rfd = open(rptdir + "/" + "sosreport.html", "w") rfd.write(""" Sos System Report """) rfd.write("Sosreport version blah blah
") # Make a pass to gather Alerts and a list of module names allAlerts = [] plugNames = [] for plugname, plug in loadedplugins: for alert in plug.alerts: # TODO include the plugin as a target of a link here allAlerts.append('%s: %s' % (plugname, plugname, alert)) plugNames.append(plugname) # Create a table of links to the module info rfd.write("

Loaded Plugins:

") rfd.write("\n") qq = 0 rr = 0 for i in range(len(plugNames)): rfd.write('\n' % (plugNames[i], plugNames[i])) qq, rr = divmod(i,4) if (rr == 3): rfd.write('') if not (rr == 3): rfd.write('') rfd.write('
%s
\n') rfd.write('

Alerts:

') rfd.write('') # Call the report method for each plugin for plugname, plug in loadedplugins: html = plug.report() rfd.write(html) rfd.write("") rfd.close() # Collect any needed user information (name, etc) # Clean up left over files, make tarball, whatever. # Close all log files and perform any cleanup logfd.close() # Call the postproc method for each plugin for plugname, plug in loadedplugins: root = plug.postproc(dstroot) if root == dstroot: print "The report is in " + rptdir + "/" + "sosreport.html" if __name__ == '__main__': sosreport()