diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/lib/sos/plugins/cluster.py | 115 | ||||
-rw-r--r-- | src/lib/sos/plugins/general.py | 4 | ||||
-rw-r--r-- | src/lib/sos/plugins/kernel.py | 8 | ||||
-rw-r--r-- | src/lib/sos/plugins/networking.py | 2 | ||||
-rw-r--r-- | src/lib/sos/plugins/process.py | 42 | ||||
-rw-r--r-- | src/lib/sos/plugins/rpm.py | 4 | ||||
-rw-r--r-- | src/lib/sos/plugintools.py | 31 | ||||
-rwxr-xr-x | src/lib/sos/policyredhat.py | 22 | ||||
-rw-r--r-- | src/sos.spec | 2 | ||||
-rwxr-xr-x | src/sosreport | 252 |
11 files changed, 259 insertions, 225 deletions
diff --git a/src/Makefile b/src/Makefile index 9e052778..3d0b6920 100644 --- a/src/Makefile +++ b/src/Makefile @@ -61,12 +61,14 @@ release: clean install:mo python setup.py install + @rm -rf build/lib version: @echo "The version is $(NAME)-$(VERSION)" clean: @rm -fv *~ .*~ changenew ChangeLog.old $(NAME)-$(VERSION).tar.bz2 sosreport.1.gz + @rm -rfv build/* rpm: mo @test -f sos.spec diff --git a/src/lib/sos/plugins/cluster.py b/src/lib/sos/plugins/cluster.py index 02fede4f..62315bc6 100644 --- a/src/lib/sos/plugins/cluster.py +++ b/src/lib/sos/plugins/cluster.py @@ -13,7 +13,7 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import sos.plugintools -import commands, os +import commands, os, re import time, libxml2 class cluster(sos.plugintools.PluginBase): @@ -22,7 +22,7 @@ class cluster(sos.plugintools.PluginBase): optionList = [("gfslockdump", 'gather output of gfs lockdumps', 'slow', False), ('lockdump', 'gather dlm lockdumps', 'slow', False), - ('taskdump', 'trigger 3 SysRq+t dumps every 5 seconds', 'slow', False)] + ('taskdump', 'trigger 3 sysrq+t dumps every 5 seconds (dangerous)', 'slow', False)] def checkenabled(self): # enable if any related package is installed @@ -33,7 +33,7 @@ class cluster(sos.plugintools.PluginBase): return True # enable if any related file is present - for fname in [ "/etc/cluster/cluster.conf" ]: + for fname in [ "/etc/cluster/cluster.conf", "/proc/cluster" ]: try: os.stat(fname) except:pass else: return True @@ -93,6 +93,13 @@ class cluster(sos.plugintools.PluginBase): if not ((self.cInfo["policy"].pkgByName("dlm") and self.cInfo["policy"].pkgByName("dlm-kernel")) or self.cInfo["policy"].pkgByName("gulm")): self.addDiagnose("required packages are missing: (dlm, dlm-kernel) || gulm") + # let's make modules are loaded + mods_check = [ "cman", "dlm" ] + if self.has_gfs(): mods_check.append("gfs") + for module in mods_check: + if len(self.fileGrep("^%s " % module, "/proc/modules")) == 0: + self.addDiagnose("required package is present but not loaded: %s" % module) + # check if all the needed daemons are active at sosreport time # check if they are started at boot time in RHEL4 RHCS (cman, ccsd, rgmanager, fenced) # and GFS (gfs, ccsd, clvmd, fenced) @@ -102,29 +109,59 @@ class cluster(sos.plugintools.PluginBase): status, output = commands.getstatusoutput("/sbin/service %s status" % service) if status: self.addDiagnose("service %s is not running" % service) + else: + # service is running, extra sanity checks + if service == "fenced": + # also make sure fenced is a registered cluster service + try: + if len(self.fileGrep("^Fence Domain:\W", "/proc/cluster/services")) == 0: + self.addDiagnose("fencing service is not registered with cman") + except: + pass + elif service == "rgmanager": + # also make sure rgmanager is a registered cluster service + try: + if len(self.fileGrep("^User:\W*usrm::manager", "/proc/cluster/services")) == 0: + self.addDiagnose("rgmanager is not registered with cman") + except: + pass if not self.cInfo["policy"].runlevelDefault() in self.cInfo["policy"].runlevelByService(service): self.addDiagnose("service %s is not started in default runlevel" % service) + # FIXME: any cman service whose state != run ? + # Fence Domain: "default" 2 2 run - + # is cluster quorate if not self.is_cluster_quorate(): self.addDiagnose("cluster node is not quorate") # if there is no cluster.conf, diagnose() finishes here. - try: os.stat("/etc/cluster/cluster.conf") - except: return + try: + os.stat("/etc/cluster/cluster.conf") + except: + self.addDiagnose("/etc/cluster/cluster.conf is missing") + return # setup XML xpath context xml = libxml2.parseFile("/etc/cluster/cluster.conf") xpathContext = xml.xpathNewContext() - # check fencing (warn on empty or manual) + # check fencing (warn on no fencing) if len(xpathContext.xpathEval("/cluster/clusternodes/clusternode[not(fence/method/device)]")): self.addDiagnose("one or more nodes have no fencing agent configured") + # check fencing (warn on manual) if len(xpathContext.xpathEval("/cluster/clusternodes/clusternode[/cluster/fencedevices/fencedevice[@agent='fence_manual']/@name=fence/method/device/@name]")): self.addDiagnose("one or more nodes have manual fencing agent configured (data integrity is not guaranteed)") + # if fence_ilo or fence_drac, make sure acpid is not running + hostname = commands.getoutput("/bin/uname -n").split(".")[0] + if len(xpathContext.xpathEval('/cluster/clusternodes/clusternode[@name = "%s" and /cluster/fencedevices/fencedevice[@agent="fence_rsa" or @agent="fence_drac"]/@name=fence/method/device/@name]' % hostname )): + status, output = commands.getstatusoutput("/sbin/service acpid status") + if status == 0 or self.cInfo["policy"].runlevelDefault() in self.cInfo["policy"].runlevelByService("acpid"): + self.addDiagnose("acpid is enabled, this may cause problems with your fencing method.") + # check for fs exported via nfs without nfsid attribute if len(xpathContext.xpathEval("/cluster/rm/service//fs[not(@fsid)]/nfsexport")): self.addDiagnose("one or more nfs file-system doesn't have a fsid attribute set.") @@ -142,16 +179,15 @@ class cluster(sos.plugintools.PluginBase): # and that the locking protocol is sane cluster_name = xpathContext.xpathEval("/cluster/@name")[0].content - fp = open("/etc/fstab","r") - for fs in fp.readline().split(): -# fs = fs.split() - if not fs or fs[0] == "#" or len(fs) < 6 or fs[2]!="gfs": continue - lockproto = get_gfs_sb_field(fs[1], "sb_lockproto") - if lockproto != "lock_" + get_locking_proto: + for fs in self.fileGrep(r'^[^#][/\w]*\W*[/\w]*\W*gfs', "/etc/fstab"): + # for each gfs entry + fs = fs.split() + + lockproto = self.get_gfs_sb_field(fs[0], "sb_lockproto") + if lockproto and lockproto != self.get_locking_proto(): self.addDiagnose("gfs mountpoint (%s) is using the wrong locking protocol (%s)" % (fs[0], lockproto) ) - locktable = get_gfs_sb_field(fs[1], "sb_locktable") - if not locktable: continue + locktable = self.get_gfs_sb_field(fs[0], "sb_locktable") try: locktable = locktable.split(":")[0] except: continue if locktable != cluster_name: @@ -178,11 +214,15 @@ class cluster(sos.plugintools.PluginBase): return def do_taskdump(self): + if not os.access("/proc/sysrq-trigger", os.W_OK): + return + commands.getstatusoutput("echo t > /proc/sysrq-trigger") - time.sleep(3) + time.sleep(5) commands.getstatusoutput("echo t > /proc/sysrq-trigger") - time.sleep(3) + time.sleep(5) commands.getstatusoutput("echo t > /proc/sysrq-trigger") + self.addCopySpec("/var/log/messages") def do_lockdump(self): @@ -200,22 +240,27 @@ class cluster(sos.plugintools.PluginBase): def get_locking_proto(self): # FIXME: what's the best way to find out ? - return "dlm" - return "gulm" + return "lock_dlm" + return "lock_gulm" def do_gfslockdump(self): fp = open("/proc/mounts","r") for line in fp.readlines(): mntline = line.split(" ") if mntline[2] == "gfs": - self.collectExtOutput("/sbin/gfs_tool lockdump %s" % mntline[1]) + self.collectExtOutput("/sbin/gfs_tool lockdump %s" % mntline[1], root_symlink = "gfs_lockdump_" + self.mangleCommand(mntline[1]) ) fp.close() + def do_rgmgr_bt(self): + # FIXME: threads backtrace + return + def postproc(self): self.doRegexSub("/etc/cluster/cluster.conf", r"(\s*\<fencedevice\s*.*\s*passwd\s*=\s*)\S+(\")", r"\1***") return def is_cluster_quorate(self): + # FIXME: use self.fileGrep() instead output = commands.getoutput("/bin/cat /proc/cluster/status | grep '^Membership state: '") try: if output[18:] == "Cluster-Member": @@ -226,32 +271,8 @@ class cluster(sos.plugintools.PluginBase): pass return None - def get_gfs_sb_field(self, mntpoint, field): - for line in commands.getoutput("/sbin/gfs_tool sb %s all" % fs[1]): - tostrip = " " + field + " = " - if line.startwith(tostrip): - return line[len(tostrip):] - return None - - def xpath_query_count(self, fname, query): - return len(self.xpath_query(fname, query)) - - def xpath_query(self, fname, query): - xml = libxml2.parseFile(fname) - xpathContext = xml.xpathNewContext() - return xpathContext.xpathEval(query) - - # FIXME: use python libxml internals - tmpout = commands.getoutput("/bin/echo xpath %s | /usr/bin/xmllint --shell /etc/cluster/cluster.conf") - for tmpline in tmpout: - if tmpline.startswith("Set contains "): - tmpvalue = tmpline[14:].split(" ")[0] - if tmpvalue == "NULL": return 0 - try: tmpvalue = int(tmpvalue) - except: return False - return tmpvalue + def get_gfs_sb_field(self, device, field): + for line in commands.getoutput("/sbin/gfs_tool sb %s all" % device).split("\n"): + if re.match('^\W*%s = ' % field, line): + return line.split("=")[1].strip() return False - - - - diff --git a/src/lib/sos/plugins/general.py b/src/lib/sos/plugins/general.py index 06f55228..fd18136b 100644 --- a/src/lib/sos/plugins/general.py +++ b/src/lib/sos/plugins/general.py @@ -16,10 +16,10 @@ import sos.plugintools import glob class general(sos.plugintools.PluginBase): - """very basic system information + """basic system information """ - optionList = [("syslogsize", "maximum size (in MiB) of logs to collect per syslog file", "", 15)] + optionList = [("syslogsize", "max size (MiB) to collect per syslog file", "", 15)] def setup(self): self.addCopySpec("/etc/redhat-release") diff --git a/src/lib/sos/plugins/kernel.py b/src/lib/sos/plugins/kernel.py index 07cc6ac7..9a752c13 100644 --- a/src/lib/sos/plugins/kernel.py +++ b/src/lib/sos/plugins/kernel.py @@ -18,8 +18,8 @@ import commands, os, re class kernel(sos.plugintools.PluginBase): """kernel related information """ - optionList = [("modinfo", 'Gathers module information on all modules', 'fast', True), - ('sysrq', 'Trigger SysRq dumps', 'fast', False)] + optionList = [("modinfo", 'gathers module information on all modules', 'fast', True), + ('sysrq', 'trigger SysRq+t dumps', 'fast', False)] moduleFile = "" taintList = [ {'regex':'mvfs*', 'description':'Clearcase module'}, @@ -72,9 +72,7 @@ class kernel(sos.plugintools.PluginBase): self.addCopySpec("/proc/cmdline") self.addCopySpec("/proc/driver") self.addCopySpec("/proc/sys/kernel/tainted") - # trigger some sysrq's. I'm not sure I like doing it this way, but - # since we end up with the sysrq dumps in syslog whether we run the - # syslog report before or after this, I suppose I can live with it. + # FIXME: both RHEL4 and RHEL5 don't need sysrq to be enabled to trigger via sysrq-trigger if self.isOptionEnabled('sysrq') and os.access("/proc/sysrq-trigger", os.W_OK) and os.access("/proc/sys/kernel/sysrq", os.R_OK): sysrq_state = commands.getoutput("/bin/cat /proc/sys/kernel/sysrq") commands.getoutput("/bin/echo 1 > /proc/sys/kernel/sysrq") diff --git a/src/lib/sos/plugins/networking.py b/src/lib/sos/plugins/networking.py index 6d11146b..b7331849 100644 --- a/src/lib/sos/plugins/networking.py +++ b/src/lib/sos/plugins/networking.py @@ -57,7 +57,7 @@ class networking(sos.plugintools.PluginBase): self.addCopySpec("/etc/xinetd.d") self.addCopySpec("/etc/host*") self.addCopySpec("/etc/resolv.conf") - ifconfigFile=self.collectExtOutput("/sbin/ifconfig -a", root_symlink = "ifconfig") + ifconfigFile=self.collectOutputNow("/sbin/ifconfig -a", root_symlink = "ifconfig") self.collectExtOutput("/sbin/route -n", root_symlink = "route") self.collectExtOutput("/sbin/ipchains -nvL") self.collectIPTable("filter") diff --git a/src/lib/sos/plugins/process.py b/src/lib/sos/plugins/process.py index 7ab6e6f5..baa185b4 100644 --- a/src/lib/sos/plugins/process.py +++ b/src/lib/sos/plugins/process.py @@ -13,6 +13,9 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. import sos.plugintools +import commands +import time +import os class process(sos.plugintools.PluginBase): """process information @@ -20,8 +23,41 @@ class process(sos.plugintools.PluginBase): def setup(self): self.collectExtOutput("/bin/ps auxww", root_symlink = "ps") self.collectExtOutput("/usr/bin/pstree", root_symlink = "pstree") - self.collectExtOutput("/usr/bin/ipcs -a") - self.collectExtOutput("/usr/bin/ipcs -u") - self.collectExtOutput("/usr/bin/ipcs -l") return + def find_mountpoint(s): + if (os.path.ismount(s) or len(s)==0): return s + else: return mountpoint(os.path.split(s)[0]) + + def diagnose(self): + # check that no process is in state D + dpids = [] + status, output = commands.getstatusoutput("/bin/ps -A -o state,pid --no-heading") + if not status: + for line in output.split("\n"): + line = line.split() + if line[0] == "D": + # keep an eye on the process to see if the stat changes + for inc in range(1,10): + try: + if len(self.fileGrep("^State: D", " /proc/%d/status" % int(line[1]))) == 0: + # status is not D, good. let's get out of the loop. + time.sleep(0.1) + continue + except IOError: + # this should never happen... + pass + else: + dpids.append(int(line[1])) + + # FIXME: for each hung PID, list file-systems from /proc/$PID/fd +# for pid in dpids: +# realpath + + if len(dpids): + self.addDiagnose("one or more processes are in state D") + + return + + + diff --git a/src/lib/sos/plugins/rpm.py b/src/lib/sos/plugins/rpm.py index 9c6f2659..c899d141 100644 --- a/src/lib/sos/plugins/rpm.py +++ b/src/lib/sos/plugins/rpm.py @@ -17,8 +17,8 @@ import sos.plugintools class rpm(sos.plugintools.PluginBase): """RPM information """ - optionList = [("rpmq", "Queries for package information via rpm -q", "fast", True), - ("rpmva", "Runs a verify on all packages", "slow", True)] + optionList = [("rpmq", "queries for package information via rpm -q", "fast", True), + ("rpmva", "runs a verify on all packages", "slow", True)] def setup(self): self.addCopySpec("/var/log/rpmpkgs") diff --git a/src/lib/sos/plugintools.py b/src/lib/sos/plugintools.py index 8f07fb62..f58c8151 100644 --- a/src/lib/sos/plugintools.py +++ b/src/lib/sos/plugintools.py @@ -313,13 +313,27 @@ class PluginBase: """ self.collectProgs.append( (exe,suggest_filename,root_symlink) ) + def fileGrep(self, regexp, fname): + results = [] + + fp = open(fname, "r") + for line in fp.readlines(): + if re.match(regexp, line): + results.append(line) + fp.close() + return results + + def mangleCommand(self, exe): + # FIXME: this can be improved + mangledname = re.sub(r"^/(usr/|)(bin|sbin)/", "", exe) + mangledname = re.sub(r"[^\w\-\.\/]+", "_", mangledname) + mangledname = re.sub(r"/", ".", mangledname).strip(" ._-")[0:64] + return mangledname + def makeCommandFilename(self, exe): """ The internal function to build up a filename based on a command """ - mangledname = re.sub(r"[^\w\-\.\/]+", "_", exe) - mangledname = re.sub(r"/", ".", mangledname).strip(" ._-")[0:64] - - outfn = self.cInfo['cmddir'] + "/" + self.piName + "/" + mangledname + outfn = self.cInfo['cmddir'] + "/" + self.piName + "/" + self.mangleCommand(exe) # check for collisions if os.path.exists(outfn): @@ -341,6 +355,8 @@ class PluginBase: if not os.access(exe.split()[0], os.X_OK): self.soslog.log(logging.VERBOSE, "binary '%s' does not exist or is not runnable, trying anyways" % exe.split()[0]) + # FIXME: we should have a timeout or we may end waiting forever + # pylint: disable-msg = W0612 status, shout, runtime = sosGetCommandOutput(exe) @@ -363,16 +379,17 @@ class PluginBase: os.symlink(outfn[len(self.cInfo['dstroot'])+1:], root_symlink.strip("/.")) os.chdir(curdir) - outfn = outfn[len(self.cInfo['cmddir'])+1:] + outfn_strip = outfn[len(self.cInfo['cmddir'])+1:] else: self.soslog.log(logging.VERBOSE, "could not run command: %s" % exe) outfn = None + outfn_strip = None # sosStatus(status) # save info for later - self.executedCommands.append({'exe': exe, 'file':outfn}) # save in our list - self.cInfo['xmlreport'].add_command(cmdline=exe,exitcode=status,f_stdout=outfn,runtime=runtime) + self.executedCommands.append({'exe': exe, 'file':outfn_strip}) # save in our list + self.cInfo['xmlreport'].add_command(cmdline=exe,exitcode=status,f_stdout=outfn_strip,runtime=runtime) return outfn def writeTextToCommand(self, exe, text): diff --git a/src/lib/sos/policyredhat.py b/src/lib/sos/policyredhat.py index 7382f740..cbf76d26 100755 --- a/src/lib/sos/policyredhat.py +++ b/src/lib/sos/policyredhat.py @@ -24,6 +24,7 @@ import string from tempfile import gettempdir from sos.helpers import * import random +import re SOME_PATH = "/tmp/SomePath" @@ -114,9 +115,11 @@ class SosPolicy: try: name = raw_input("Please enter your first initial and last name [%s]: " % localname) + name = re.sub(r"[^a-zA-Z.0-9]", "", name) if len(name) == 0: name = localname ticketNumber = raw_input("Please enter the case number that you are generating this report for: ") + ticketNumber = re.sub(r"[^0-9]", "", ticketNumber) except KeyboardInterrupt: print _("<interrupted>") print _("Temporary files have been stored in %s") % self.cInfo['dstroot'] @@ -155,8 +158,25 @@ class SosPolicy: # FIXME: use python internal command os.system("/bin/mv %s %s" % (aliasdir, self.cInfo['dstroot'])) + # add last 6 chars from md5sum to file name + status, md5out = commands.getstatusoutput('''/usr/bin/md5sum "%s"''' % tarballName) + if not status and len(md5out): + oldtarballName = tarballName + try: + md5out = md5out.strip().split()[0] + tarballName = os.path.join(ourtempdir, "sosreport-%s-%s.tar.bz2" % (namestr, md5out[-6:]) ) + os.system("/bin/mv %s %s" % (oldtarballName, tarballName) ) + except: + md5out = False + else: + md5out = False + sys.stdout.write("\n") - print "Your sosreport has been generated and saved in %s" % tarballName + print "Your sosreport has been generated and saved in:\n %s" % tarballName + print + if md5out: + print "The md5sum is: " + md5out + print print "Please send this file to your support representative." sys.stdout.write("\n") diff --git a/src/sos.spec b/src/sos.spec index 5a61a5d0..1c979f58 100644 --- a/src/sos.spec +++ b/src/sos.spec @@ -2,7 +2,7 @@ %define name sos %define version 1.7 -%define release 2 +%define release 3 %define _localedir %_datadir/locale diff --git a/src/sosreport b/src/sosreport index 6607c453..89242fa0 100755 --- a/src/sosreport +++ b/src/sosreport @@ -27,12 +27,11 @@ supplied for application-specific information 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 +from threading import Thread, activeCount import signal import logging from stat import * @@ -56,7 +55,7 @@ def doExitCode(): print "SIGTERM received, multiple threads detected, waiting for all threads to exit" for thread in enumerate(): if thread.getName() != "MainThread": - thread.join() + 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" @@ -80,6 +79,19 @@ signal.signal(signal.SIGTERM, exittermhandler) # for debugging __raisePlugins__ = 1 +class OptionParser_extended(OptionParser): + def print_help(self): + OptionParser.print_help(self) + print + print "Some examples:" + print + print " enable cluster plugin only and collect dlm lockdumps:" + print " # sosreport -o cluster -k cluster.lockdump" + print + print " disable memory and samba plugins, turn off rpm -Va collection:" + print " # sosreport -n memory,samba -k rpm.rpmva=off" + print + class SosOption (Option): """Allow to specify comma delimited list of plugins""" ACTIONS = Option.ACTIONS + ("extend",) @@ -94,46 +106,37 @@ class SosOption (Option): 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__ = OptionParser_extended(option_class=SosOption) __cmdParser__.add_option("-l", "--list-plugins", action="store_true", \ dest="listPlugins", default=False, \ - help="list existing plugins") -__cmdParser__.add_option("-n", "--noplugin", action="extend", \ + help="list plugins and available plugin options") +__cmdParser__.add_option("-n", action="extend", \ dest="noplugins", type="string", \ help="skip these plugins", default = []) -__cmdParser__.add_option("-o", "--onlyplugin", action="extend", \ +__cmdParser__.add_option("-e", action="extend", \ + dest="enableplugins", type="string", \ + help="enable these plugins", default = []) +__cmdParser__.add_option("-o", 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", \ +__cmdParser__.add_option("-k", action="extend", \ dest="plugopts", type="string", \ - help="plugin options in plugin_name.option=value format") + help="plugin options in plugname.option=value format (see -l)") +__cmdParser__.add_option("-a", "--alloptions", action="store_true", \ + dest="usealloptions", default=False, \ + help="enable all options for loaded plugins") __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.") + help="increase verbosity") __cmdParser__.add_option("--no-progressbar", action="store_false", \ dest="progressbar", default=True, \ - help="Do not display a progress bar.") + 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) + help="disable multi-threaded gathering mode (slower)", default=False) (__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args() -def textcolor(text, fg, bg=None, raw=0): +def textcolor(text, fg, 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", @@ -144,60 +147,6 @@ def textcolor(text, fg, bg=None, raw=0): 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 @@ -211,8 +160,10 @@ class progressBar: self.update() def updateAmount(self, newAmount = 0): - if newAmount < self.min: newAmount = self.min - if newAmount > self.max: newAmount = self.max + 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 @@ -225,34 +176,34 @@ class progressBar: if timeElapsed >= 10 and self.amount > 0: percentDone = round(timeElapsed * 100 / self.eta) if percentDone > 100: - percentDone = 100 - ETA = timeElapsed + percentDone = 100 + ETA = timeElapsed elif self.eta < timeElapsed: - ETA = timeElapsed + ETA = timeElapsed else: - ETA = self.eta + ETA = self.eta ETA = "[%02d:%02d/%02d:%02d]" % (int(timeElapsed/60), timeElapsed % 60, round(ETA/60), ETA % 60) else: ETA = "[%02d:%02d/--:--]" % (int(timeElapsed/60), timeElapsed % 60) if self.amount < self.max: - percentDone = 0 + percentDone = 0 else: - percentDone = 100 + 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 + self.progBar = "" + for inc in range(0,allFull): + if inc == int(allFull / 2): + self.progBar = self.progBar + textcolor("%d%%" % percentDone, "blue") + elif inc < numHashes: + self.progBar = self.progBar + textcolor('#', "green") + else: + self.progBar = self.progBar + ' ' + self.progBar = " Progress [" + self.progBar + "]" + ETA def incAmount(self, toInc = 1): self.updateAmount(self.amount+toInc) @@ -281,7 +232,7 @@ class XmlReport: 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): + 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) @@ -351,9 +302,8 @@ def sosreport(): # find the plugins path paths = sys.path for path in paths: - if path.strip()[-len("site-packages"):] == "site-packages": + if path.strip()[-len("site-packages"):] == "site-packages": pluginpath = path + "/sos/plugins" - reporterpath = path + "/sos/reporters" # Set up common info and create destinations @@ -372,6 +322,8 @@ def sosreport(): soslog = logging.getLogger('sos') soslog.setLevel(logging.DEBUG) + # FIXME: strip colours if terminal doesn't allow it + # log to a file flog = logging.FileHandler(logdir + "/sos.log") flog.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s')) @@ -448,34 +400,40 @@ def sosreport(): soslog.warning(_("plugin %s does not install, skipping") % plug) raise except: - soslog.warning(_("could not load plugin %s") % plug) - if __raisePlugins__: + soslog.warning(_("could not load plugin %s") % plug) + if __raisePlugins__: raise # First, gather and process options # using the options specified in the command line (if any) + if __cmdLineOpts__.usealloptions: + for plugname, plug in loadedplugins: + for name, parms in zip(plug.optNames, plug.optParms): + if type(parms["enabled"])==bool: + parms["enabled"] = True + if __cmdLineOpts__.plugopts: opts = {} for opt in __cmdLineOpts__.plugopts: - # split up "general.syslogsize=5" - try: - opt, val = opt.split("=") - except: - val=True - else: - if val == "off" or val == "disable" or val == "disabled": - val = False - else: - # try to convert string "val" to int() - try: val = int(val) - except: pass + # split up "general.syslogsize=5" + try: + opt, val = opt.split("=") + except: + val=True + else: + if val == "off" or val == "disable" or val == "disabled": + val = False + else: + # try to convert string "val" to int() + try: val = int(val) + except: pass - # split up "general.syslogsize" - plug, opt = opt.split(".") + # split up "general.syslogsize" + plug, opt = opt.split(".") - try: opts[plug] - except KeyError: opts[plug] = [] - opts[plug].append( (opt,val) ) + try: opts[plug] + except KeyError: opts[plug] = [] + opts[plug].append( (opt,val) ) for plugname, plug in loadedplugins: if opts.has_key(plugname): @@ -483,24 +441,6 @@ def sosreport(): 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: - # FIXME: with int and bool options, fast/slow/all breaks - 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) for plugname, plug in loadedplugins: soslog.log(logging.VERBOSE3, _("processing options from plugin: %s") % plugname) @@ -518,19 +458,19 @@ def sosreport(): 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()) + 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 _("No plugin enabled.") print if len(skippedplugins): print _("The following plugins are currently disabled:") print for (plugname,plugclass) in skippedplugins: - print " %-25s %s" % (textcolor(plugname,"blue"),plugclass.get_description()) + print " %-25s %s" % (textcolor(plugname,"lgray"),plugclass.get_description()) print if len(alloptions): @@ -599,7 +539,7 @@ Press ENTER to continue, or CTRL-C to quit. raise tmpcount += len(plug.diagnose_msgs) if tmpcount > 0: - print _("One or more plugin has detected a problem in your configuration.") + print _("One or more plugins have detected a problem in your configuration.") print _("Please review the following messages:") print for plugname, plug in loadedplugins: @@ -751,17 +691,17 @@ Press ENTER to continue, or CTRL-C to quit. # Call the postproc method for each plugin for plugname, plug in loadedplugins: - plug.postproc() + try: + plug.postproc() + except: + if __raisePlugins__: + raise - 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 + # 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() |