aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorshnavid <shnavid@ef72aa8b-4018-0410-8976-d6e080ef94d8>2007-07-31 15:11:27 +0000
committershnavid <shnavid@ef72aa8b-4018-0410-8976-d6e080ef94d8>2007-07-31 15:11:27 +0000
commite60b7c5a10a03ebca251da29f21e2eb446d3fa60 (patch)
tree66feb12d80d087d8d181656171a430f0de30fa5f /src
parent349400ba1f8d54283dec1d1083f7b5ca3ce90a04 (diff)
downloadsos-e60b7c5a10a03ebca251da29f21e2eb446d3fa60.tar.gz
Merged navid-dev r276 into the trunk
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/sos/trunk@278 ef72aa8b-4018-0410-8976-d6e080ef94d8
Diffstat (limited to 'src')
-rw-r--r--src/Makefile2
-rw-r--r--src/lib/sos/plugins/cluster.py115
-rw-r--r--src/lib/sos/plugins/general.py4
-rw-r--r--src/lib/sos/plugins/kernel.py8
-rw-r--r--src/lib/sos/plugins/networking.py2
-rw-r--r--src/lib/sos/plugins/process.py42
-rw-r--r--src/lib/sos/plugins/rpm.py4
-rw-r--r--src/lib/sos/plugintools.py31
-rwxr-xr-xsrc/lib/sos/policyredhat.py22
-rw-r--r--src/sos.spec2
-rwxr-xr-xsrc/sosreport252
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()