diff options
author | shnavid <shnavid@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2007-07-12 07:29:36 +0000 |
---|---|---|
committer | shnavid <shnavid@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2007-07-12 07:29:36 +0000 |
commit | 9af40ceda54d5979730d95999359da33191839fe (patch) | |
tree | e09e2ee395d84ba973ae049ef7a4a3e2b7fbebd5 | |
parent | c96eab04123db867ca2ef23f51dccea46e8b9801 (diff) | |
download | sos-9af40ceda54d5979730d95999359da33191839fe.tar.gz |
* bumped version to 1.7r1.7
* curses menu disabled by default (enable with -c)
* sosreport output friendlier to the user (and similar to sysreport)
* smarter plugin listing which also shows options and disable/enabled plugins
* require root permissions only for actual sosreport generation
* fix in -k where option value was treated as string instead of int
* made progressbar wider (60 chars)
* selinux plugin is enabled only if selinux is also enabled on the system
* made some errors less verbose to the user
* made sosreport not copy files pointed by symbolic links (same as sysreport, we don't need /usr/bin/X or /sbin/ifup)
* copy links as links (cp -P)
* added plugin get_description() that returns a short decription for the plugin
* guess sosreport name from system's name
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/sos/trunk@195 ef72aa8b-4018-0410-8976-d6e080ef94d8
-rw-r--r-- | src/TODO | 2 | ||||
-rw-r--r-- | src/lib/sos/plugins/selinux.py | 9 | ||||
-rw-r--r-- | src/lib/sos/plugintools.py | 35 | ||||
-rwxr-xr-x | src/lib/sos/policyredhat.py | 23 | ||||
-rw-r--r-- | src/setup.py | 2 | ||||
-rw-r--r-- | src/sos.spec | 4 | ||||
-rwxr-xr-x | src/sosreport | 166 |
7 files changed, 134 insertions, 107 deletions
@@ -5,6 +5,8 @@ To Do List: * Make sosreport a drop-in replacement for sysreport + * Allow to use a different rootdir than / + * Add support for distributions other than Fedora. * Make it easier to select a policy module and perhaps optionally include diff --git a/src/lib/sos/plugins/selinux.py b/src/lib/sos/plugins/selinux.py index 2e56964a..925c2ad7 100644 --- a/src/lib/sos/plugins/selinux.py +++ b/src/lib/sos/plugins/selinux.py @@ -13,6 +13,7 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import sos.plugintools +import commands class selinux(sos.plugintools.PluginBase): """This plugin gathers selinux related information @@ -25,3 +26,11 @@ class selinux(sos.plugintools.PluginBase): self.collectExtOutput("/bin/rpm -q -V selinux-policy-strict") return + def checkenabled(self): + # is selinux enabled ? + try: + if commands.getoutput("/usr/sbin/sestatus").split(":")[1].strip() == "disabled": + return False + except: + pass + return True diff --git a/src/lib/sos/plugintools.py b/src/lib/sos/plugintools.py index 3d80df44..15fccfdf 100644 --- a/src/lib/sos/plugintools.py +++ b/src/lib/sos/plugintools.py @@ -85,7 +85,7 @@ class PluginBase: except KeyboardInterrupt: raise KeyboardInterrupt except Exception, e: - self.cInfo['soslog'].error("Problem at path %s (%s)\n" % (abspath,e)) + self.cInfo['soslog'].warning("Problem at path %s (%s)\n" % (abspath,e)) break return False @@ -141,7 +141,7 @@ class PluginBase: except KeyboardInterrupt: raise KeyboardInterrupt except Exception, e: - self.cInfo['soslog'].error("Problem at path %s (%s)" % (srcpath+'/'+afile, e)) + self.cInfo['soslog'].warning("Problem at path %s (%s)" % (srcpath+'/'+afile, e)) # if on forbidden list, abspath is null if not abspath == '': dstslname = sosRelPath(self.cInfo['rptdir'], abspath) @@ -156,22 +156,8 @@ class PluginBase: except KeyboardInterrupt: raise KeyboardInterrupt except Exception, e: - self.cInfo['soslog'].error("Problem at path %s (%s)" % (srcpath, e)) + self.cInfo['soslog'].debug("Problem at path %s (%s)" % (srcpath, e)) - - # Recurse to copy whatever it points to - newpath = os.path.normpath(os.path.join(os.path.dirname(srcpath), link)) - try: - self.doCopyFileOrDir(newpath) - except SystemExit: - raise SystemExit - except KeyboardInterrupt: - raise KeyboardInterrupt - except EnvironmentError, (errno, strerror): - if (errno != 17): - # we ignore 'file exists' errors - self.cInfo['soslog'].error("Problem at path %s ([%d] %s)" % (newpath, errno, strerror)) - return abspath else: @@ -195,7 +181,7 @@ class PluginBase: """ try: # pylint: disable-msg = W0612 - status, shout, sherr, runtime = sosGetCommandOutput("/bin/cp --parents -p " + src +" " + self.cInfo['dstroot']) + status, shout, sherr, runtime = sosGetCommandOutput("/bin/cp --parents -P --preserve=mode,ownership,timestamps,links " + src +" " + self.cInfo['dstroot']) if status: self.cInfo['soslog'].debug(shout) self.cInfo['soslog'].debug(sherr) @@ -272,10 +258,9 @@ class PluginBase: """ Execute a command independantly of the output gathering part of sosreport """ - # First check to make sure the binary exists and is runnable. + # Log if binary is not runnable or does not exist if not os.access(prog.split()[0], os.X_OK): - self.cInfo['soslog'].log(logging.VERBOSE2, "Binary '%s' does not exist or is not runnable" % prog.split()[0]) - return + self.cInfo['soslog'].log(logging.VERBOSE, "binary '%s' does not exist or is not runnable" % prog.split()[0]) # pylint: disable-msg = W0612 status, shout, sherr, runtime = sosGetCommandOutput(prog) @@ -333,6 +318,7 @@ class PluginBase: outfd.close() if root_symlink: + # FIXME: use python's internal commands os.system('cd "%s" && ln -s "%s" "%s"' % (self.cInfo['dstroot'], outfn[len(self.cInfo['dstroot'])+1:], root_symlink)) if len(sherr) > 0: @@ -422,6 +408,13 @@ class PluginBase: except: self.cInfo['soslog'].log(logging.VERBOSE, "Error collecting output of '%s'" % prog,) + def get_description(self): + """ This function will return the description for the plugin""" + try: + return self.__doc__.strip() + except: + return "<no description available>" + def checkenabled(self): """ This function can be overidden to let the plugin decide whether it should run or not. diff --git a/src/lib/sos/policyredhat.py b/src/lib/sos/policyredhat.py index 80643576..34177347 100755 --- a/src/lib/sos/policyredhat.py +++ b/src/lib/sos/policyredhat.py @@ -18,6 +18,7 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import os +import commands import sys import string from tempfile import gettempdir @@ -75,16 +76,11 @@ class SosPolicy: return (name, version, release, arch) def packageResults(self): - print "Packaging results to send to support..." + localname = commands.getoutput("/bin/uname -n").split(".")[0] + name = raw_input("Please enter your first initial and last name [%s]: " % localname) + if len(name) == 0: name = localname - name="" - while len(name)==0: - print "Please enter your first initial and last name (jsmith): ", - name = sys.stdin.readline()[:-1] - - print "Please enter the case number that you are generating this", - print "report for: ", - ticketNumber = sys.stdin.readline()[:-1] + ticketNumber = raw_input("Please enter the case number that you are generating this report for: ") if len(ticketNumber): namestr = name + "." + ticketNumber @@ -92,7 +88,7 @@ class SosPolicy: namestr = name ourtempdir = gettempdir() - tarballName = os.path.join(ourtempdir, namestr + ".tar.bz2") + tarballName = os.path.join(ourtempdir, "sosreport-" + namestr + ".tar.bz2") namestr = namestr + "-" + str(random.randint(1, 999999)) @@ -100,12 +96,13 @@ class SosPolicy: tarcmd = "/bin/tar -jcf %s %s" % (tarballName, namestr) + print print "Creating compressed tar archive..." if not os.access(string.split(tarcmd)[0], os.X_OK): print "Unable to create tarball" return - # gotta be a better way... + # FIXME: gotta be a better way... os.system("/bin/mv %s %s" % (self.cInfo['dstroot'], aliasdir)) curwd = os.getcwd() os.chdir(ourtempdir) @@ -117,7 +114,9 @@ class SosPolicy: os.system("/bin/mv %s %s" % (aliasdir, self.cInfo['dstroot'])) sys.stdout.write("\n") - print "Your sosreport has been generated and saved in %s" % tarballName + print "Your sosreport has been generated and saved in %s" % tarballName + print "Please send this file to your support representative." sys.stdout.write("\n") + return diff --git a/src/setup.py b/src/setup.py index b6030227..23e9a4f4 100644 --- a/src/setup.py +++ b/src/setup.py @@ -9,7 +9,7 @@ import sys,os,time # change version in spec file along with this string setup( name = 'sos', - version = '1.6', + version = '1.7', license = 'GPL', description = 'System Support Tools', long_description = """Sos is a set of tools that gathers information about system diff --git a/src/sos.spec b/src/sos.spec index 24e0dced..dd1755ca 100644 --- a/src/sos.spec +++ b/src/sos.spec @@ -1,8 +1,8 @@ %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} %define name sos -%define version 1.6 -%define release 5 +%define version 1.7 +%define release 0 Summary: A set of tools to gather troubleshooting information from a system Name: %{name} diff --git a/src/sosreport b/src/sosreport index 34f6172f..ae8d6609 100755 --- a/src/sosreport +++ b/src/sosreport @@ -39,6 +39,8 @@ from stat import * from time import strftime, localtime from pwd import getpwuid +__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 @@ -106,13 +108,13 @@ __cmdParser__.add_option("-l", "--list-plugins", action="store_true", \ help="list existing plugins") __cmdParser__.add_option("-n", "--noplugin", action="extend", \ dest="noplugins", type="string", \ - help="list of plugins _not_ to load") + help="list of plugins _not_ to load", default = []) __cmdParser__.add_option("-o", "--onlyplugin", action="extend", \ dest="onlyplugins", type="string", \ - help="list of plugins to load") + help="list of plugins to load", default = []) __cmdParser__.add_option("-e", "--enableplugin", action="extend", \ dest="enableplugins", type="string", \ - help="list of plugins to enable") + help="list of plugins to enable", default = []) __cmdParser__.add_option("-k", "--pluginopts", action="extend", \ dest="plugopts", type="string", \ help="plugin options in plugin_name.option=value format") @@ -122,6 +124,9 @@ __cmdParser__.add_option("-v", "--verbose", action="count", \ __cmdParser__.add_option("-b", "--no-progressbar", action="store_false", \ dest="progressbar", default=True, \ help="Do not display a progress bar.") +__cmdParser__.add_option("-c", "--curses", action="store_false", \ + dest="use_curses", default=False, \ + help="Do not display a progress bar.") __cmdParser__.add_option("-m", "--multithreaded", action="store_true", \ dest="multithread", \ help="Use the multithreaded information gathering mode to speed up the report (experimental)") @@ -304,6 +309,7 @@ def sosreport(): This is the top-level function that gathers and processes all sosreport information """ loadedplugins = [] + skippedplugins = [] alloptions = [] # perhaps we should automatically locate the policy module?? @@ -363,121 +369,139 @@ def sosreport(): # Make policy aware of the commons policy.setCommons(commons) + + sys.stdout.write("\n") + soslog.info("sosreport (version %s)" % (__version__) ) + sys.stdout.write("\n") - # print list of available plugins + # generate list of available plugins plugins = os.listdir(pluginpath) - if __cmdLineOpts__.listPlugins: - print "Available plugins:" - print - for plug in plugins: - try: - if ((plug[-3:] == '.py') and (plug != "__init__.py")): - plugbase = plug[:-3] - if policy.validatePlugin(pluginpath + plug): - pluginClass = importPlugin("sos.plugins." + plugbase, plugbase) - else: - soslog.warning("plugin %s does not validate, skipping" % plug) - continue - if not pluginClass(plugbase, commons).checkenabled(): - print "* %s (inactive)" % plugbase - continue - if not pluginClass(plugbase, commons).defaultenabled(): - print "* %s (disabled by default)" % plugbase - continue - print " " + plugbase - except: - print "ouch" - print - sys.exit() - - # to go anywhere further than listing the plugins we will need root permissions. - # - if os.getuid() != 0: - print 'You must run sosreport as root!' - sys.exit(1) + plugins.sort() # validate and load plugins for plug in plugins: plugbase = plug[:-3] if not plug[-3:] == '.py' or plugbase == "__init__": continue - if __cmdLineOpts__.noplugins and plugbase not in __cmdLineOpts__.noplugins: - soslog.log(logging.VERBOSE, "plug %s skipped" % plugbase) - continue - if __cmdLineOpts__.onlyplugins and not plugbase in __cmdLineOpts__.onlyplugins: - soslog.log(logging.VERBOSE, "plug %s skipped" % plugbase) - 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) + 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 __cmdLineOpts__.onlyplugins and not pluginClass(plugbase, commons).defaultenabled(): - if __cmdLineOpts__.enableplugins and plugbase in __cmdLineOpts__.enableplugins: - soslog.log(logging.VERBOSE, "plugin %s manually activated" % plugbase) - else: - soslog.log(logging.VERBOSE, "Plugin %s not loaded by default." % plug) - continue - if not pluginClass(plugbase, commons).checkenabled(): - soslog.log(logging.VERBOSE, "Plugin %s is inactive." % plug) + 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("plugin load failed for %s" % plug) if __raisePlugins__: raise - soslog.warning("plugin load failed for %s" % plug) + + # 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) + + print "The following plugins are currently enabled:" + print + for (plugname,plug) in loadedplugins: + print " %-15s %s" % (plugname,plug.get_description()) + + print + print "The following plugin options are available:" + print + for (plug, plugname, optname, optparm) in alloptions: + print " %-15s %s [%d]" % (plugname + "." + optname, optparm["desc"], optparm["enabled"]) + + print + print "The following plugins are currently disabled:" + print + for (plugname,plugclass) in skippedplugins: + print " %-15s %s" % (plugname,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) - sys.stdout.write("\n") - soslog.info("Welcome to sosreport (%d plugins loaded)" % (len(loadedplugins))) - sys.stdout.write("\n") + 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. - # Iterate over plugins for each stage +This process may take a while to complete. +No changes will be made to your system. - # First, gather and process options - for plugname, plug in loadedplugins: - soslog.log(logging.VERBOSE3, "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)) +Press ENTER to continue, or CTRL-C to quit. +""") + except KeyboardInterrupt: + print + sys.exit(0) + # Iterate over plugins for each stage 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): + if len(alloptions) and __cmdLineOpts__.use_curses: try: get_curse_options(alloptions) except "Cancelled": sys.exit("Exiting.") - else: - soslog.info("no options available for selected plugins") elif __cmdLineOpts__.fastoptions: for i in range(len(alloptions)): for plug, plugname, optname, optparm in alloptions: @@ -492,7 +516,7 @@ def sosreport(): # Setup the progress bar if __cmdLineOpts__.progressbar: - pbar = progressBar(0, len(loadedplugins) * 33, 40) + pbar = progressBar(0, len(loadedplugins) * 33, totalWidth = 60) # Call the setup method for each plugin for plugname, plug in loadedplugins: @@ -613,7 +637,7 @@ def sosreport(): # package up the results for the support organization policy.packageResults() # delete gathered files - os.system("rm -rf %s" % dstroot) + os.system("/bin/rm -rf %s" % dstroot) # automated submission will go here # Close all log files and perform any cleanup |