aboutsummaryrefslogtreecommitdiffstats
path: root/src/sosreport
diff options
context:
space:
mode:
Diffstat (limited to 'src/sosreport')
-rwxr-xr-xsrc/sosreport341
1 files changed, 124 insertions, 217 deletions
diff --git a/src/sosreport b/src/sosreport
index 37a88a47..888e0b54 100755
--- a/src/sosreport
+++ b/src/sosreport
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
"""
Gather information about a system and report it using plugins
supplied for application-specific information
@@ -28,26 +28,19 @@ supplied for application-specific information
import sys
import os
from optparse import OptionParser, Option
-import ConfigParser
import sos.policyredhat
from sos.helpers import *
from snack import *
from threading import Thread, activeCount
import signal
+import logging
from stat import *
from time import strftime, localtime, time
from pwd import getpwuid
import gettext
from threading import Semaphore
-# RHEL3 doesn't have a logging module
-try:
- import logging
-except ImportError:
- import sos.rhel3_logging
- logging = sos.rhel3_logging
-
-__version__ = 1.8
+__version__ = 1.7
__breakHits__ = 0 # Use this to track how many times we enter the exit routine
@@ -57,15 +50,10 @@ def exittermhandler(signum, frame):
def doExitCode():
from threading import enumerate
- global __breakHits__, loadedplugins, dstroot
-
+ global __breakHits__
__breakHits__ += 1
if ( ( activeCount() > 1 ) and ( __breakHits__ == 1 ) ):
print "SIGTERM received, multiple threads detected, waiting for all threads to exit"
-
- for plugname, plug in loadedplugins:
- plug.exit_please()
-
for thread in enumerate():
if thread.getName() == "MainThread":
continue
@@ -74,41 +62,20 @@ def doExitCode():
try:
thread.join()
except KeyboardInterrupt:
- doExitCode()
+ pass
else:
print "All threads ended, cleaning up."
- doExit(1)
-
- if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ):
- print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately."
+ 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)
- return
- elif ( ( activeCount() > 1 ) and ( __breakHits__ > 2 ) ):
- print "Multiple SIGTERMs, multiple threads, process suicides."
- os.kill(os.getpid(), signal.SIGKILL)
- elif ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ):
+# os.kill(os.getpid(), signal.SIGKILL)
+ print "Threads dead, cleaning up."
+ if ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ):
print "Multiple SIGTERMs, single thread, exiting without cleaning up."
- doExit(3)
-
- doExit("Abnormal exit")
-
-def doExit(error=0):
- global policy
- policy.cleanDstroot()
- sys.exit(error)
-
-def doException(type, value, tb):
- if hasattr(sys, 'ps1') or not sys.stderr.isatty():
- # we are in interactive mode or we don't have a tty-like
- # device, so we call the default hook
- sys.__excepthook__(type, value, tb)
- else:
- import traceback, pdb
- # we are NOT in interactive mode, print the exception...
- traceback.print_exception(type, value, tb)
- print
- # ...then start the debugger in post-mortem mode.
- pdb.pm()
+ 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)
@@ -117,6 +84,9 @@ signal.signal(signal.SIGTERM, exittermhandler)
## FIXME: Need to figure out how to IPC with child threads in case of
## multiple SIGTERMs.
+# for debugging
+__raisePlugins__ = 0
+
class OptionParser_extended(OptionParser):
def print_help(self):
OptionParser.print_help(self)
@@ -125,10 +95,10 @@ class OptionParser_extended(OptionParser):
print
print " enable cluster plugin only and collect dlm lockdumps:"
print " # sosreport -o cluster -k cluster.lockdump"
- print
+ print
print " disable memory and samba plugins, turn off rpm -Va collection:"
print " # sosreport -n memory,samba -k rpm.rpmva=off"
- print
+ print
class SosOption (Option):
"""Allow to specify comma delimited list of plugins"""
@@ -163,51 +133,39 @@ __cmdParser__.add_option("-k", action="extend", \
__cmdParser__.add_option("-a", "--alloptions", action="store_true", \
dest="usealloptions", default=False, \
help="enable all options for loaded plugins")
-__cmdParser__.add_option("-u", "--upload", action="store_true", \
- dest="upload", default=False, \
- help="upload the report to Red Hat support")
-#__cmdParser__.add_option("--encrypt", action="store_true", \
-# dest="encrypt", default=False, \
-# help="encrypt with GPG using Red Hat support's public key")
-__cmdParser__.add_option("--batch", action="store_true", \
- dest="batch", default=False, \
- help="do not ask any question (batch mode)")
-__cmdParser__.add_option("--no-colors", action="store_true", \
- dest="nocolors", default=False, \
- help="do not use terminal colors for text")
__cmdParser__.add_option("-v", "--verbose", action="count", \
dest="verbosity", \
help="increase verbosity")
-__cmdParser__.add_option("--debug", action="count", \
- dest="debug", \
- help="enabling debugging")
__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)
+__cmdParser__.add_option("--name", action="store", \
+ dest="name",type="string", \
+ help="first initial and last name.", default="")
+__cmdParser__.add_option("--ticket-number", action="store", \
+ dest="ticketnumber", type="string", \
+ help="ticket number.", default="")
if sys.argv[0].endswith("sysreport"):
- print
- print "WARNING: sysreport is deprecated, please use sosreport instead."
- if not sys.stdin.isatty():
- print
+ try:
+ ppid = os.getppid()
+ fp = open("/proc/%d/cmdline" % ppid, "r")
+ cmd = fp.read()
+ fp.close()
+ except:
+ cmd = ""
+ if not sys.stdin.isatty() or cmd.find("bash") < 0:
os.execl("/bin/sh", "/bin/sh", "-c", "/usr/sbin/sysreport.legacy")
- sys.exit(-1)
-
-if "-norpm" in sys.argv:
+ os.exit(-1)
print
- print """WARNING: sysreport's "-norpm" option is deprecated, please use "-k rpm.rpmva=off" instead."""
- print
- sys.exit(1)
+ print "WARNING: sysreport is deprecated, please use sosreport instead."
(__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args()
def textcolor(text, fg, raw=0):
- global __cmdLineOpts__
- if __cmdLineOpts__.nocolors:
- return text
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",
@@ -230,11 +188,11 @@ class progressBar:
self.last_amount_update = time()
self.update()
- def updateAmount(self, newAmount = 0, finished = False):
+ def updateAmount(self, newAmount = 0):
if newAmount < self.min:
newAmount = self.min
if newAmount > self.max:
- newAmount = self.max - 1
+ newAmount = self.max
if self.amount != newAmount:
self.last_amount_update = time()
self.amount = newAmount
@@ -249,8 +207,6 @@ class progressBar:
percentDone = round(timeElapsed * 100 / self.eta)
except:
percentDone = 0
- if percentDone >= 100 and not finished:
- percentDone = 99
if percentDone > 100:
percentDone = 100
ETA = timeElapsed
@@ -285,7 +241,7 @@ class progressBar:
self.updateAmount(self.amount+toInc)
def finished(self):
- self.updateAmount(self.max, finished = True)
+ self.updateAmount(self.max)
sys.stdout.write(self.progBar + '\n')
sys.stdout.flush()
@@ -359,14 +315,6 @@ class XmlReport:
outfn.write(self.doc.serialize(None,1))
outfn.close()
-# if debugging is enabled, allow plugins to raise exceptions
-
-if __cmdLineOpts__.debug:
- sys.excepthook = doException
- __raisePlugins__ = 1
-else:
- __raisePlugins__ = 0
-
def sosreport():
# pylint: disable-msg = R0912
# pylint: disable-msg = R0914
@@ -374,13 +322,6 @@ def sosreport():
"""
This is the top-level function that gathers and processes all sosreport information
"""
-
- global loadedplugins, dstroot, policy
-
- config = ConfigParser.ConfigParser()
- try: config.readfp(open('/etc/sos.conf'))
- except IOError: pass
-
loadedplugins = []
skippedplugins = []
alloptions = []
@@ -395,12 +336,8 @@ def sosreport():
pluginpath = path + "/sos/plugins"
# Set up common info and create destinations
-
- dstroot = policy.getDstroot()
- if not dstroot:
- print _("Could not create temporary directory.")
- doExit()
+ dstroot = sosFindTmpDir()
cmddir = os.path.join(dstroot, "sos_commands")
logdir = os.path.join(dstroot, "sos_logs")
rptdir = os.path.join(dstroot, "sos_reports")
@@ -409,7 +346,7 @@ def sosreport():
os.mkdir(rptdir, 0755)
# initialize i18n language localization
- gettext.install('sos', '/usr/share/locale', unicode=False)
+ gettext.install('sos', '/usr/share/locale', unicode=False)
# initialize logging
soslog = logging.getLogger('sos')
@@ -417,15 +354,12 @@ def sosreport():
logging.VERBOSE = logging.INFO - 1
logging.VERBOSE2 = logging.INFO - 2
- logging.VERBOSE3 = logging.INFO - 3
+ logging.VERBOSE3 = logging.INFO - 3
logging.addLevelName(logging.VERBOSE, "verbose")
logging.addLevelName(logging.VERBOSE2,"verbose2")
logging.addLevelName(logging.VERBOSE3,"verbose3")
- # if stdin is not a tty, disable colors and don't ask questions
- if not sys.stdin.isatty():
- __cmdLineOpts__.nocolors = True
- __cmdLineOpts__.batch = True
+ # FIXME: strip colours if terminal doesn't allow it
# log to a file
flog = logging.FileHandler(logdir + "/sos.log")
@@ -448,7 +382,7 @@ def sosreport():
# 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, 'cmdlineopts':__cmdLineOpts__, 'config':config }
+ 'xmlreport' : xmlrep }
# Make policy aware of the commons
policy.setCommons(commons)
@@ -456,11 +390,12 @@ def sosreport():
print
soslog.info ( _("sosreport (version %s)") % __version__)
print
-
+
# generate list of available plugins
plugins = os.listdir(pluginpath)
plugins.sort()
- plugin_names = []
+
+ # FIXME: should at least print a warning if the user references a plugin which does not exist
# validate and load plugins
for plug in plugins:
@@ -468,33 +403,36 @@ def sosreport():
if not plug[-3:] == '.py' or plugbase == "__init__":
continue
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
- # plug-in is valid, let's decide whether run it or not
- plugin_names.append(plugbase)
- if plugbase in __cmdLineOpts__.noplugins:
- soslog.log(logging.VERBOSE, _("plugin %s skipped (--skip-plugins)") % 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 --only-plugins list") % plug)
- skippedplugins.append((plugbase, pluginClass(plugbase, commons)))
- continue
- loadedplugins.append((plugbase, pluginClass(plugbase, commons)))
+ #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, _("plugin %s skipped (--skip-plugins)") % 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 --only-plugins 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 %s does not install, skipping") % plug)
+ soslog.warning(_("could not load plugin %s") % plug)
if __raisePlugins__:
raise
@@ -506,14 +444,6 @@ def sosreport():
if type(parms["enabled"])==bool:
parms["enabled"] = True
- # read plugin tunables from configuration file
- if config.has_section("tunables"):
- if not __cmdLineOpts__.plugopts:
- __cmdLineOpts__.plugopts = []
-
- for opt, val in config.items("tunables"):
- __cmdLineOpts__.plugopts.append(opt + "=" + val)
-
if __cmdLineOpts__.plugopts:
opts = {}
for opt in __cmdLineOpts__.plugopts:
@@ -523,7 +453,7 @@ def sosreport():
except:
val=True
else:
- if val.lower() in ["off", "disable", "disabled", "false"]:
+ if val == "off" or val == "disable" or val == "disabled":
val = False
else:
# try to convert string "val" to int()
@@ -531,11 +461,7 @@ def sosreport():
except: pass
# split up "general.syslogsize"
- try:
- plug, opt = opt.split(".")
- except:
- plug = opt
- opt = True
+ plug, opt = opt.split(".")
try: opts[plug]
except KeyError: opts[plug] = []
@@ -544,26 +470,10 @@ def sosreport():
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))
- if not plug.setOption(opt,val):
- soslog.error('no such option "%s" for plugin (%s)' % (opt,plugname))
- doExit(1)
- del opts[plugname]
- for plugname in opts.keys():
- soslog.error('unable to set option for disabled or non-existing plugin (%s)' % (plugname))
- doExit(1)
+ soslog.log(logging.VERBOSE, "setting option %s for plugin %s to %s" % (plugname,opt,val))
+ plug.setOption(opt,val)
del opt,opts,val
- # error if the user references a plugin which does not exist
- unk_plugs = [plugname.split(".")[0] for plugname in __cmdLineOpts__.onlyplugins if not plugname.split(".")[0] in plugin_names]
- unk_plugs += [plugname.split(".")[0] for plugname in __cmdLineOpts__.noplugins if not plugname.split(".")[0] in plugin_names]
- unk_plugs += [plugname.split(".")[0] for plugname in __cmdLineOpts__.enableplugins if not plugname.split(".")[0] in plugin_names]
- if len(unk_plugs):
- for plugname in unk_plugs:
- soslog.error('a non-existing plugin (%s) was specified in the command line' % (plugname))
- doExit(1)
- del unk_plugs
-
for plugname, plug in loadedplugins:
soslog.log(logging.VERBOSE3, _("processing options from plugin: %s") % plugname)
names, parms = plug.getAllOptions()
@@ -577,7 +487,7 @@ def sosreport():
if __cmdLineOpts__.listPlugins:
if not len(loadedplugins) and not len(skippedplugins):
soslog.error(_("no valid plugins found"))
- doExit(1)
+ sys.exit(1)
# FIXME: make -l output more concise
if len(loadedplugins):
@@ -620,22 +530,26 @@ def sosreport():
print _("No plugin options available.")
print
- doExit()
+ 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.')
- doExit(1)
+ 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"))
- doExit(1)
+ sys.exit(1)
- msg = _("""This utility will collect some detailed information about the
+ isUnattended = False
+ if len(__cmdLineOpts__.name) > 0 and len(__cmdLineOpts__.ticketnumber) > 0: isUnattended = True
+ if not isUnattended:
+ try:
+ raw_input(_("""This utility will collect some detailed information about the
hardware and setup of your Red Hat Enterprise Linux system.
The information is collected and an archive is packaged under
/tmp, which you can send to a support representative.
@@ -645,14 +559,11 @@ and it will be considered confidential information.
This process may take a while to complete.
No changes will be made to your system.
-""")
- if __cmdLineOpts__.batch:
- print msg
- else:
- msg += _("""Press ENTER to continue, or CTRL-C to quit.\n""")
- try: raw_input(msg)
- except: print ; doExit()
- del msg
+Press ENTER to continue, or CTRL-C to quit.
+"""))
+ except KeyboardInterrupt:
+ print
+ sys.exit(0)
# Call the diagnose() method for each plugin
tmpcount = 0
@@ -679,32 +590,37 @@ No changes will be made to your system.
fp.close()
print
- if not __cmdLineOpts__.batch:
- try:
- while True:
+ try:
+ while True:
+ if not isUnattended:
yorno = raw_input( _("Are you sure you would like to continue (y/n) ? ") )
- if yorno == _("y") or yorno == _("Y"):
- print
- break
- elif yorno == _("n") or yorno == _("N"):
- doExit(0)
- del yorno
- except KeyboardInterrupt:
- print
- doExit(0)
-
- policy.preWork()
+ else:
+ yorno = _("Y")
+
+ if yorno == _("y") or yorno == _("Y"):
+ print
+ break
+ elif yorno == _("n") or yorno == _("N"):
+ sys.exit(0)
+ del yorno
+ except KeyboardInterrupt:
+ print
+ sys.exit(0)
+
+ if isUnattended:
+ policy.preWork(__cmdLineOpts__.name, __cmdLineOpts__.ticketnumber)
+ else:
+ policy.preWork()
+
# 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)
try:
- plug.setup()
- except KeyboardInterrupt:
- raise
+ plug.setup()
except:
- if __raisePlugins__:
- raise
+ if __raisePlugins__:
+ raise
# Setup the progress bar
if __cmdLineOpts__.progressbar:
@@ -723,17 +639,15 @@ No changes will be made to your system.
# Call the collect method for each plugin
plugrunning = Semaphore(2)
for plugname, plug in loadedplugins:
- soslog.log(logging.VERBOSE, "requesting plugin %s" % plugname)
+ soslog.log(logging.VERBOSE, "executing plugin %s" % plugname)
try:
if not __cmdLineOpts__.nomultithread:
plug.copyStuff(threaded = True, semaphore = plugrunning)
else:
- plug.copyStuff()
+ plug.copyStuff()
if __cmdLineOpts__.progressbar:
pbar.incAmount(plug.eta_weight)
pbar.update()
- except KeyboardInterrupt:
- raise
except:
if __raisePlugins__:
raise
@@ -841,6 +755,8 @@ No changes will be made to your system.
rfd.close()
+ # Collect any needed user information (name, etc)
+
# Call the postproc method for each plugin
for plugname, plug in loadedplugins:
try:
@@ -851,23 +767,14 @@ No changes will be made to your system.
# package up the results for the support organization
policy.packageResults()
-
# delete gathered files
- policy.cleanDstroot()
-
- # let's encrypt the tar-ball
- #if __cmdLineOpts__.encrypt:
- # policy.encryptResults()
-
+ os.system("/bin/rm -rf %s" % dstroot)
# automated submission will go here
- if not __cmdLineOpts__.upload:
- policy.displayResults()
- else:
- policy.uploadResults()
# Close all log files and perform any cleanup
logging.shutdown()
-
+
+
if __name__ == '__main__':
try:
sosreport()