aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornavid <navid@ef72aa8b-4018-0410-8976-d6e080ef94d8>2007-09-04 08:27:59 +0000
committernavid <navid@ef72aa8b-4018-0410-8976-d6e080ef94d8>2007-09-04 08:27:59 +0000
commit92bf7d380893d3e376a5e358f3d7fe03fec80aae (patch)
tree54b3457d1a525ffc5f6bb0da7ec8b3bd1d8a410d
parent347c67b5d8fd925216eebda502182b3d69094090 (diff)
downloadsos-92bf7d380893d3e376a5e358f3d7fe03fec80aae.tar.gz
Merged branch navid-dev r372:389 into the trunk.
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/sos/trunk@390 ef72aa8b-4018-0410-8976-d6e080ef94d8
-rw-r--r--src/README10
-rwxr-xr-xsrc/extras/htmlog407
-rwxr-xr-xsrc/lib/sos/helpers.py64
-rw-r--r--src/lib/sos/plugins/autofs.py9
-rw-r--r--src/lib/sos/plugins/cluster.py52
-rw-r--r--src/lib/sos/plugins/devicemapper.py22
-rw-r--r--src/lib/sos/plugins/filesys.py24
-rw-r--r--src/lib/sos/plugins/general.py4
-rw-r--r--src/lib/sos/plugins/kernel.py4
-rw-r--r--src/lib/sos/plugins/named.py32
-rw-r--r--src/lib/sos/plugins/networking.py2
-rw-r--r--src/lib/sos/plugins/rpm.py4
-rw-r--r--src/lib/sos/plugins/squid.py6
-rw-r--r--src/lib/sos/plugins/yum.py8
-rw-r--r--src/lib/sos/plugintools.py14
-rwxr-xr-xsrc/lib/sos/policyredhat.py126
-rw-r--r--src/setup.py2
-rw-r--r--src/sos.spec3
-rwxr-xr-xsrc/sosreport80
-rw-r--r--src/sosreport.116
20 files changed, 534 insertions, 355 deletions
diff --git a/src/README b/src/README
index f1dbf2c7..b166c674 100644
--- a/src/README
+++ b/src/README
@@ -9,23 +9,23 @@ to contribute, and for more information, please visit there.
To access to the public source code repository for this project run:
- svn checkout https://sos.108.redhat.com/svn/sos/trunk sos
+ svn export http://svn.fedoraproject.org/svn/hosted/sos/trunk sos --username guest
-(all the following as root)
-to install locally ==> make install
+to install locally (as root) ==> make install
to build an rpm ==> make rpm
See the Makefile.
-Maintainers:
+Maintainer:
Navid Sheikhol-Eslami <navid@redhat.com>
-Contributors:
+Developers and Contributors:
Steve Conklin <sconklin@redhat.com>
Pierre Amadio <pamadio@redhat.com>
John Berninger <jwb@redhat.com>
+ Adam Stokes <astokes@redhat.com>
Thanks to:
diff --git a/src/extras/htmlog b/src/extras/htmlog
index 387a5d90..87d9e9c1 100755
--- a/src/extras/htmlog
+++ b/src/extras/htmlog
@@ -2,7 +2,7 @@
#from optparse import OptionParser, Option
import time, sys, os, glob
-import getopt
+import getopt, re
#__cmdParser__ = OptionParser()
#__cmdParser__.add_option("-i", "--input", action="append",
@@ -13,6 +13,178 @@ import getopt
# help="How obnoxious we're being about telling the user what we're doing.")
#(__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args()
+class htmlgen_class:
+
+ def __init__(self):
+ self.html_fname_base = "/tmp/something"
+ self.page_num = 0
+ self.page_line = 0
+ self.page_fp = None
+ self.cur_time = None
+ self.old_time = None
+
+ self.summary_fp = open(self.html_fname_base + ".html", "w")
+ self.summary_fp.write("<html><body><ul>")
+
+ def new_page(self):
+
+ # close previous page
+ if self.page_fp:
+ self.close_page()
+
+ self.page_fp = open( "%s_%d.html" % (self.html_fname_base, self.page_num), "w")
+ self.page_num += 1
+ self.page_line = 0
+
+ self.page_fp.write("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+<head>
+<title></title>
+<style type="text/css">
+<!--
+
+body {
+ font: normal 11px auto "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ color: #4f6b72;
+ background: #E6EAE9;
+}
+
+a {
+ color: #c75f3e;
+}
+
+#mytable {
+ width: 97%;
+ padding: 0;
+ margin: 0;
+}
+
+caption {
+ padding: 0 0 5px 0;
+ width: 97%;
+ font: italic 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ text-align: right;
+}
+
+th {
+ font: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ color: #4f6b72;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ text-align: left;
+ padding: 6px 6px 6px 12px;
+ background: #a50000 url(images/bg_header.jpg) no-repeat;
+ color: white;
+}
+
+th.nobg {
+ border-top: 0;
+ border-left: 0;
+ border-right: 1px solid #C1DAD7;
+ background: none;
+ color: black;
+}
+
+td {
+ border-right: 1px solid #C1DAD7;
+ border-bottom: 1px solid #C1DAD7;
+ background: #fff;
+ padding: 6px 6px 6px 12px;
+ color: #4f6b72;
+ letter-spacing: -1px;
+ white-space:pre-wrap;
+ font-family: monospace;
+}
+
+pre {
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+td.alt {
+ background: #ffbaba;
+ color: #797268;
+}
+
+th.newday {
+ text-align: right;
+ padding: 2px;
+}
+
+th.spec {
+ border-left: 1px solid #C1DAD7;
+ border-right: 1px solid #C1DAD7;
+ border-top: 0;
+ background: #fff url(images/bullet1.gif) no-repeat;
+ font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ color: #797268;
+}
+
+th.specalt {
+ border-left: 1px solid #C1DAD7;
+ border-right: 1px solid #C1DAD7;
+ border-top: 0;
+ background: #cecfce url(images/bullet2.gif) no-repeat;
+ font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
+ color: #797268;
+}
+
+-->
+</style>
+
+</head>
+<body>
+
+<table id="mytable" cellspacing="0" summary="The technical specifications of the Apple PowerMac G5 series">
+<caption>Generated by SOS htmlogger 1.0 on March 16th 2008</caption>
+""")
+
+ def new_line(self, new_time, events = []):
+ self.old_time = self.cur_time
+ self.cur_time = new_time
+
+ # close previous line
+ if self.page_line > 0:
+ self.page_fp.write("</TR>")
+
+ if self.page_line == 0 or self.page_line % 200 == 0:
+ self.page_fp.write("""<tr><th scope="col" abbr="Date/Time" class="nobg">Time</th><th scope="col" abbr="node-1">node-1</th><th scope="col" abbr="node-2">node-2</th><th scope="col" abbr="node-3">node-3</th></tr>""")
+
+ if self.page_line == 0 or self.page_line % 200 == 0 or time.strftime("%b %d", self.old_time) != time.strftime("%b %d", new_time):
+ self.page_fp.write("""<tr><th scope="row" class="newday" colspan=4>%s</th></tr>""" % time.strftime("%A, %B %d", new_time))
+
+ if self.page_line % 2 == 0: row_class = "spec"
+ else: row_class = "specalt"
+
+ if len(events) > 0:
+ stime = """<a name="row_%d">%s</a>""" % (self.page_line, time.strftime("%H:%M:%S", new_time))
+ for event in events:
+ self.summary_fp.write('<li><a href="something_%d.html#row_%s">%s</a>' % (self.page_num-1,self.page_line,event) )
+ else:
+ stime = time.strftime("%H:%M:%S", new_time)
+
+ if not self.old_time or self.old_time != new_time:
+ self.page_fp.write("""<TR><th scope="row" class="%s">%s</th>""" % (row_class, stime))
+ else:
+ self.page_fp.write("""<TR><th scope="row" class="%s" style="color: #cacaca">%s</th>""" % (row_class, stime))
+
+ self.page_line+=1
+
+ def new_tab(self,msg):
+ self.page_fp.write(" <TD>" + msg + "</TD>\n")
+
+ def close_page(self):
+ self.page_fp.write("</table></html>\n")
+ self.page_fp.close()
+
+ def finish(self):
+ self.close_page()
+
class host_class:
def __init__(self):
@@ -21,6 +193,8 @@ class host_class:
self.log_idx = 0 # first log
self.log_ptr = 0 # first char
+ self.cur_line = None
+
def add_log(self, logfile):
# if not logfile == logfile_class:
# raise "InvalidLogfile"
@@ -74,6 +248,7 @@ class host_class:
raise "Off_Boundaries"
def time(self):
+ return time.strptime(self.cur_line[0:15], "%b %d %H:%M:%S")
pos = self.tell()
try:
toret = time.strptime(self.readline()[0:15], "%b %d %H:%M:%S")
@@ -85,6 +260,9 @@ class host_class:
def fp(self):
return self.logs[self.log_idx]
+ def backline(self):
+ self.seek(-len(self.cur_line), 1)
+
def readline(self):
if self.eof():
return ""
@@ -100,6 +278,7 @@ class host_class:
return ""
if self.validate_line(toret) or toret == "":
+ self.cur_line = toret
return toret
else:
print "invalid line"
@@ -111,10 +290,12 @@ class host_class:
return False
return True
- def readmsg(self):
- toret = self.readline()
- if toret:
- return toret[18:]
+ def cur_msg(self):
+ if not hasattr(self,"_regex_cur_msg"):
+ self._regex_cur_msg = re.compile(r"""^.* %s (\S+:.*)$""" % self.hostname())
+
+ try: return self._regex_cur_msg.findall(self.cur_line)[0]
+ except: return self.cur_line
class logfile_class:
@@ -161,38 +342,8 @@ class logfile_class:
def tell(self):
return self.fp.tell()
- def parse(self):
- self.seek(0)
- while not self.eof:
- self.readline()
- self.parse_line()
- self.seek(0)
-
- def parse_line(self):
-
- # is valid log line ?
- if not self.time_current():
- return
-
- # store hostname, if we don't already have it
- if len(self.hostname) == 0:
- self.curline.split()[3]
-
- # system is booting
- if self.curmessage().startswith("kernel: Linux version"):
- self.add_event("system boot")
-
- # hostname has changed
- if len(self.hostname) and self.hostname != self.curline.split()[3]:
- self.add_event("hostname changed")
- self.hostname = self.curline.split()[3]
-
- # the clock is wrong wrong
- if self.prevline and time.strptime(self.prevline[0:15], "%b %d %H:%M:%S") > self.time_current():
- self.add_event("clock is messed up")
-
- def add_event(self, message):
- self.events.append( (self.curline_pos,len(self.curline),message) )
+ def validate_line(self):
+ return self.time_current(self.curmessage())
def time_current(self):
if len(self.curline) == 0: return None
@@ -239,136 +390,15 @@ for logname in cmdline["logfiles"]:
sys.stderr.write("finished adding logs\n")
-#print hosts["moka"].readline()
-#print hosts["moka"].readline()
-#print "DIRECT", hosts["moka"].fp().fp.tell()
-#print "HOST TELL", hosts["moka"].tell()
-#print hosts["moka"].readline()
-#print hosts["moka"].time()
-#print hosts["moka"].readline()
-#print hosts["moka"].time()
-#print hosts["moka"].readline()
-
-print """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
- "http://www.w3.org/TR/html4/strict.dtd">
-
-<html>
-<head>
-<title></title>
-<style type="text/css">
-<!--
-
-body {
- font: normal 11px auto "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
- color: #4f6b72;
- background: #E6EAE9;
-}
-
-a {
- color: #c75f3e;
-}
-
-#mytable {
- width: 97%;
- padding: 0;
- margin: 0;
-}
-
-caption {
- padding: 0 0 5px 0;
- width: 97%;
- font: italic 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
- text-align: right;
-}
-
-th {
- font: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
- color: #4f6b72;
- letter-spacing: 2px;
- text-transform: uppercase;
- text-align: left;
- padding: 6px 6px 6px 12px;
- background: #a50000 url(images/bg_header.jpg) no-repeat;
- color: white;
-}
-
-th.nobg {
- border-top: 0;
- border-left: 0;
- border-right: 1px solid #C1DAD7;
- background: none;
- color: black;
-}
-
-td {
- border-right: 1px solid #C1DAD7;
- border-bottom: 1px solid #C1DAD7;
- background: #fff;
- padding: 6px 6px 6px 12px;
- color: #4f6b72;
- letter-spacing: -1px;
- white-space:pre-wrap;
- font-family: monospace;
-}
-
-pre {
- white-space: pre-wrap; /* css-3 */
- white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
- white-space: -pre-wrap; /* Opera 4-6 */
- white-space: -o-pre-wrap; /* Opera 7 */
- word-wrap: break-word; /* Internet Explorer 5.5+ */
-}
-
-td.alt {
- background: #ffbaba;
- color: #797268;
-}
-
-th.newday {
- text-align: right;
- padding: 2px;
-}
-
-th.spec {
- border-left: 1px solid #C1DAD7;
- border-right: 1px solid #C1DAD7;
- border-top: 0;
- background: #fff url(images/bullet1.gif) no-repeat;
- font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
- color: #797268;
-}
-
-th.specalt {
- border-left: 1px solid #C1DAD7;
- border-right: 1px solid #C1DAD7;
- border-top: 0;
- background: #cecfce url(images/bullet2.gif) no-repeat;
- font: bold 10px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
- color: #797268;
-}
-
--->
-</style>
-
-</head>
-<body>
-"""
-
#print '<ul id="toc">'
#for log in logs:
# print logs[idx].fname, logs[idx].events
# for line, msglen, event in log.events:
# print ' <li><span>%s</span> <a href="#">Link</a><br /></li>' % event
-print '</ul>'
-
-print """
-<table id="mytable" cellspacing="0" summary="The technical specifications of the Apple PowerMac G5 series">
-<caption>Generated by SOS htmlogger 1.0 on March 16th 2008</caption>
-"""
+htmlgen = htmlgen_class()
previous_date = None
-inc = 0
while True:
# who is next ?
@@ -377,6 +407,8 @@ while True:
if hosts[host].eof():
continue
+ hosts[host].readline()
+
if lowest_date == None or hosts[host].time() < lowest_date:
lowest_date = hosts[host].time()
@@ -384,40 +416,49 @@ while True:
# all logs are EOF
break
- if inc == 0 or inc % 200 == 0:
- print """<tr><th scope="col" abbr="Date/Time" class="nobg">Time</th><th scope="col" abbr="node-1">node-1</th><th scope="col" abbr="node-2">node-2</th><th scope="col" abbr="node-3">node-3</th></tr>"""
+ events = []
+ for host in hosts:
+ if hosts[host].time() == lowest_date:
- if not previous_date or time.strftime("%b %d", previous_date) != time.strftime("%b %d", lowest_date):
- print """<tr><th scope="row" class="newday" colspan=4>%s</th></tr>""" % time.strftime("%A, %B %d", lowest_date)
+ if re.match(r'^kernel: Linux version', hosts[host].cur_msg()):
+ events.append("%s rebooted" % host)
- if inc % 2 == 0: row_class = "spec"
- else: row_class = "specalt"
+ elif re.match(r'^.*fencing node', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
- # FIXME: if this tick has an event, add <a name="...">
- if not previous_date or previous_date != lowest_date:
- print """<TR><th scope="row" class="%s">%s</th>""" % (row_class, time.strftime("%H:%M:%S", lowest_date) )
- else:
- print """<TR><th scope="row" class="%s" style="color: #cacaca">%s</th>""" % (row_class, time.strftime("%H:%M:%S", lowest_date) )
+ elif re.match(r'.*fence ".*" success', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
- for host in hosts:
- if hosts[host].time() == lowest_date:
-# print " <TD>%d</TD>" % hosts[host].tell()
- print " <TD>" + hosts[host].readmsg() + "</TD>"
-# print " <TD>%d</TD>" % hosts[host].tell()
- else:
- print " <TD></TD>"
- print " </TR>"
+ elif re.match(r'.*fence ".*" failed', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
+
+ elif re.match(r'.*quorum lost, blocking activity', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
+
+ elif re.match(r'.*quorum regained, resuming activity', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
+
+ elif re.match(r'.*segfault at', hosts[host].cur_msg()):
+ events.append(host + " " + hosts[host].cur_msg())
- previous_date = lowest_date
- inc += 1
+ elif not hosts[host].eof():
+ hosts[host].backline()
-print "</table>"
-
+ if len(events): print time.strftime("%A %B %d %H:%M:%S", lowest_date), events
-
+ if htmlgen.page_line == 0 or htmlgen.page_line > 10000:
+ print "creating new page #%d" % htmlgen.page_num
+ htmlgen.new_page()
+ htmlgen.new_line(lowest_date, events)
+ for host in hosts:
+ if hosts[host].time() == lowest_date:
+ htmlgen.new_tab(hosts[host].cur_msg())
+ else:
+ htmlgen.new_tab("")
+htmlgen.close_page()
diff --git a/src/lib/sos/helpers.py b/src/lib/sos/helpers.py
index bc9c51ff..7f2e335d 100755
--- a/src/lib/sos/helpers.py
+++ b/src/lib/sos/helpers.py
@@ -25,8 +25,8 @@
"""
helper functions used by sosreport and plugins
"""
-import os, popen2, fcntl, select, itertools, sys, commands, logging
-from time import time
+import os, popen2, fcntl, select, itertools, sys, commands, logging, signal
+from time import time, sleep
from tempfile import mkdtemp
def importPlugin(pluginname, name):
@@ -57,7 +57,7 @@ def makeNonBlocking(afd):
fcntl.fcntl(afd, fcntl.F_SETFL, fl | os.FNDELAY)
-def sosGetCommandOutput(command):
+def sosGetCommandOutput(command, timeout = 300):
""" Execute a command and gather stdin, stdout, and return status.
"""
soslog = logging.getLogger('sos')
@@ -73,14 +73,49 @@ def sosGetCommandOutput(command):
soslog.log(logging.VERBOSE, "binary '%s' does not exist or is not runnable" % cmdfile)
return (127, "", 0)
- stime = time()
- inpipe, pipe = os.popen4(command, 'r')
- inpipe.close()
- text = pipe.read()
- sts = pipe.close()
- if sts is None: sts = 0
- if text[-1:] == '\n': text = text[:-1]
- return (sts, text, time()-stime)
+ # these are file descriptors, not file objects
+ r, w = os.pipe()
+
+ pid = os.fork()
+
+ if pid:
+ # we are the parent
+ os.close(w) # use os.close() to close a file descriptor
+ r = os.fdopen(r) # turn r into a file object
+ stime=time()
+ txt = ""
+ while True:
+ # read output from pipe
+ txt = txt + r.read()
+ # is child still running ?
+ try: os.waitpid(pid, os.WNOHANG)
+ except: break
+ # has 5 secs timeout passed ?
+ if time() - stime > timeout:
+ soslog.log(logging.VERBOSE, 'killing hung child with pid %s after %d seconds (command was "%s")' % (pid,timeout,command) )
+ os.kill(pid, signal.SIGKILL)
+ break
+ sleep(0.1)
+ # make sure the child process gets cleaned up
+ try: sts = os.waitpid(pid, 0)[1]
+ except: sts = -1
+ if txt[-1:] == '\n': txt = txt[:-1]
+ return (sts, txt, time()-stime)
+ else:
+ # we are the child
+ os.dup2(r, 0)
+ os.dup2(w, 1)
+ os.dup2(w, 2)
+
+ import resource
+ maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
+ if (maxfd == resource.RLIM_INFINITY):
+ maxfd = MAXFD
+ for fd in range(3, maxfd):
+ try: os.close(fd)
+ except OSError: pass
+ os.execl("/bin/sh", "/bin/sh", "-c", command)
+ os._exit(127)
# FIXME: this needs to be made clean and moved to the plugin tools, so
# that it prints nice color output like sysreport if the progress bar
@@ -136,3 +171,10 @@ def sosRelPath(path1, path2, sep=os.path.sep, pardir=os.path.pardir):
if not common:
return path2 # leave path absolute if nothing at all in common
return sep.join( [pardir]*len(u1) + u2 )
+
+def sosReadFile(fname):
+ ''' reads a file and returns its contents'''
+ fp = open(fname,"r")
+ content = fp.read()
+ fp.close()
+ return content
diff --git a/src/lib/sos/plugins/autofs.py b/src/lib/sos/plugins/autofs.py
index 2cb22767..5e8be418 100644
--- a/src/lib/sos/plugins/autofs.py
+++ b/src/lib/sos/plugins/autofs.py
@@ -51,13 +51,8 @@ class autofs(sos.plugintools.PluginBase):
def setup(self):
self.addCopySpec("/etc/auto*")
self.addCopySpec("/etc/sysconfig/autofs")
- self.addCopySpec("/etc/init.d/autofs")
- self.collectExtOutput("/bin/rpm -qV autofs")
- self.collectExtOutput("/etc/init.d/autofs status")
- self.collectExtOutput("ps auxwww | grep automount")
- self.collectExtOutput("/bin/egrep -e 'automount|pid.*nfs' /proc/mounts")
- self.collectExtOutput("/bin/mount | egrep -e 'automount|pid.*nfs'")
- self.collectExtOutput("/sbin/chkconfig --list autofs")
+ self.addCopySpec("/etc/rc.d/init.d/autofs")
+ self.collectExtOutput("service autofs status")
# if debugging to file is enabled, grab that file too
daemon_debug_file = self.getdaemondebug()
diff --git a/src/lib/sos/plugins/cluster.py b/src/lib/sos/plugins/cluster.py
index 6067f9c4..280ad3b1 100644
--- a/src/lib/sos/plugins/cluster.py
+++ b/src/lib/sos/plugins/cluster.py
@@ -25,31 +25,21 @@ class cluster(sos.plugintools.PluginBase):
('taskdump', 'trigger 3 sysrq+t dumps every 5 seconds (dangerous)', 'slow', False)]
def checkenabled(self):
- # enable if any related package is installed
- rhelver = self.cInfo["policy"].rhelVersion()
- if rhelver == 4:
- pkgs_to_check = [ "ccs", "cman", "cman-kernel", "magma", "magma-plugins",
- "rgmanager", "fence", "dlm", "dlm-kernel", "gulm",
- "GFS", "GFS-kernel", "lvm2-cluster" ]
- elif rhelver == 5:
- pkgs_to_check = [ "rgmanager", "luci", "ricci", "system-config-cluster",
- "gfs-utils", "gnbd", "kmod-gfs", "kmod-gnbd", "lvm2-cluster" ]
- else:
- # can't guess what RHEL version we are running
- pkgs_to_check = []
-
- for pkg in pkgs_to_check:
- if self.cInfo["policy"].pkgByName(pkg) != None:
- return True
-
- # enable if any related file is present
- for fname in [ "/etc/cluster/cluster.conf", "/proc/cluster" ]:
- try: os.stat(fname)
- except:pass
- else: return True
-
- # no data related to RHCS/GFS exists
- return False
+ self.files = [ "/etc/yum.conf" ]
+ self.packages = [ "yum" ]
+
+ def checkenabled(self):
+ rhelver = self.cInfo["policy"].rhelVersion()
+ if rhelver == 4:
+ self.packages = [ "ccs", "cman", "cman-kernel", "magma", "magma-plugins",
+ "rgmanager", "fence", "dlm", "dlm-kernel", "gulm",
+ "GFS", "GFS-kernel", "lvm2-cluster" ]
+ elif rhelver == 5:
+ self.packages = [ "rgmanager", "luci", "ricci", "system-config-cluster",
+ "gfs-utils", "gnbd", "kmod-gfs", "kmod-gnbd", "lvm2-cluster" ]
+
+ self.files = [ "/etc/cluster/cluster.conf", "/proc/cluster" ]
+ return sos.plugintools.PluginBase.checkenabled(self)
def has_gfs(self):
try:
@@ -109,6 +99,8 @@ class cluster(sos.plugintools.PluginBase):
break
except IndexError:
pass
+ if found == 2:
+ break
if found == 0:
self.addDiagnose("required kernel package is missing: %s" % pkgname)
@@ -190,6 +182,10 @@ class cluster(sos.plugintools.PluginBase):
if status == 0 and conf_version != cluster_version:
self.addDiagnose("cluster.conf and in-memory configuration version differ (%s != %s)" % (conf_version, cluster_version) )
+ status, output = commands.getstatusoutput("/usr/sbin/rg_test test /etc/cluster/cluster.conf")
+ if output.find("Error: ") > 0:
+ self.addDiagnose("configuration errors are present according to rg_test")
+
# make sure the first part of the lock table matches the cluster name
# and that the locking protocol is sane
cluster_name = xpathContext.xpathEval("/cluster/@name")[0].content
@@ -223,9 +219,9 @@ class cluster(sos.plugintools.PluginBase):
self.collectExtOutput("/sbin/ipvsadm -L")
- if self.isOptionEnabled('gfslockdump'): self.do_gfslockdump()
- if self.isOptionEnabled('lockdump'): self.do_lockdump()
- if self.isOptionEnabled('taskdump'): self.do_taskdump()
+ if self.getOption('gfslockdump'): self.do_gfslockdump()
+ if self.getOption('lockdump'): self.do_lockdump()
+ if self.getOption('taskdump'): self.do_taskdump()
return
diff --git a/src/lib/sos/plugins/devicemapper.py b/src/lib/sos/plugins/devicemapper.py
index a670cae7..46662c70 100644
--- a/src/lib/sos/plugins/devicemapper.py
+++ b/src/lib/sos/plugins/devicemapper.py
@@ -13,19 +13,27 @@
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import sos.plugintools
+import os
+from sos.helpers import sosGetCommandOutput
class devicemapper(sos.plugintools.PluginBase):
"""device-mapper related information (dm, lvm, multipath)
"""
+
+ optionList = [("lvmdump", 'collect raw metadata from PVs', 'slow', False)]
+
+ def do_lvmdump(self):
+ """Collects raw metadata directly from the PVs using dd
+ """
+ sosGetCommandOutput("lvmdump -d %s" % os.path.join(self.cInfo['dstroot'],"lvmdump"), 120)
+
def setup(self):
self.collectExtOutput("/sbin/dmsetup info -c")
self.collectExtOutput("/sbin/dmsetup table")
self.collectExtOutput("/sbin/dmsetup status")
- self.collectExtOutput("/usr/bin/systool -v -C -b scsi")
-
- self.collectExtOutput("/usr/sbin/vgscan -vvv")
self.collectExtOutput("/usr/sbin/vgdisplay -vv", root_symlink = "vgdisplay")
+ self.collectExtOutput("/usr/sbin/vgscan -vvv")
self.collectExtOutput("/usr/sbin/pvscan -v")
self.collectExtOutput("/usr/sbin/lvs -a -o +devices")
self.collectExtOutput("/usr/sbin/pvs -a -v")
@@ -37,4 +45,12 @@ class devicemapper(sos.plugintools.PluginBase):
self.addCopySpec("/var/lib/multipath/bindings")
self.collectExtOutput("/sbin/multipath -v4 -ll")
+ self.collectExtOutput("/usr/bin/systool -v -C -b scsi")
+
+ self.collectExtOutput("/bin/ls -laR /dev")
+ self.collectExtOutput("/bin/ls -laR /sys/block")
+
+ if self.getOption('lvmdump'):
+ self.do_lvmdump()
+
return
diff --git a/src/lib/sos/plugins/filesys.py b/src/lib/sos/plugins/filesys.py
index 73bd3d88..46a3506d 100644
--- a/src/lib/sos/plugins/filesys.py
+++ b/src/lib/sos/plugins/filesys.py
@@ -13,7 +13,8 @@
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
import sos.plugintools
-import commands
+from sos.helpers import sosReadFile
+import os
class filesys(sos.plugintools.PluginBase):
"""information on filesystems
@@ -25,21 +26,18 @@ class filesys(sos.plugintools.PluginBase):
self.addCopySpec("/proc/mounts")
self.addCopySpec("/proc/mdstat")
self.addCopySpec("/etc/raidtab")
+ mounts = self.collectOutputNow("/bin/mount -l", root_symlink = "mount")
self.addCopySpec("/etc/mdadm.conf")
self.collectExtOutput("/bin/df -al", root_symlink = "df")
- self.collectExtOutput("/bin/mount -l", root_symlink = "mount")
self.collectExtOutput("/sbin/blkid")
- raiddevs = commands.getoutput("/bin/cat /proc/partitions | /bin/egrep -v \"^major|^$\" | /bin/awk '{print $4}' | /bin/grep \/ | /bin/egrep -v \"p[0123456789]$\"")
- disks = commands.getoutput("/bin/cat /proc/partitions | /bin/egrep -v \"^major|^$\" | /bin/awk '{print $4}' | /bin/grep -v / | /bin/egrep -v \"[0123456789]$\"")
- for disk in raiddevs.split('\n'):
- if '' != disk.strip():
- self.collectExtOutput("/sbin/fdisk -l /dev/%s" % (disk,))
- self.collectExtOutput("/sbin/tune2fs -l /dev/%s" % (disk,))
- for disk in disks.split('\n'):
- if '' != disk.strip():
- self.collectExtOutput("/sbin/fdisk -l /dev/%s" % (disk,))
- self.collectExtOutput("/sbin/tune2fs -l /dev/%s" % (disk,))
- return
+ for disk in os.listdir("/sys/block"):
+ if disk in [ ".", ".." ] or disk.startswith("ram") or sosReadFile("/sys/block/%s/removable" % disk ).strip() == "1":
+ continue
+ self.collectExtOutput("/sbin/fdisk -l /dev/%s" % (disk))
+
+ for extfs in self.doRegexFindAll(r"^(/dev/.+) on .+ type ext.\s+", mounts):
+ self.collectExtOutput("/sbin/tune2fs -l %s" % (extfs))
+ return
diff --git a/src/lib/sos/plugins/general.py b/src/lib/sos/plugins/general.py
index e4be4941..6f1f912c 100644
--- a/src/lib/sos/plugins/general.py
+++ b/src/lib/sos/plugins/general.py
@@ -28,9 +28,9 @@ class general(sos.plugintools.PluginBase):
self.addCopySpec("/proc/stat")
self.addCopySpec("/var/log/dmesg")
self.addCopySpec("/var/log/messages")
- self.addCopySpecLimit("/var/log/messages.*", sizelimit = self.isOptionEnabled("syslogsize"))
+ self.addCopySpecLimit("/var/log/messages.*", sizelimit = self.getOption("syslogsize"))
self.addCopySpec("/var/log/secure")
- self.addCopySpecLimit("/var/log/secure.*", sizelimit = self.isOptionEnabled("syslogsize"))
+ self.addCopySpecLimit("/var/log/secure.*", sizelimit = self.getOption("syslogsize"))
self.addCopySpec("/var/log/sa")
self.addCopySpec("/var/log/up2date")
self.collectExtOutput("/bin/hostname", root_symlink = "hostname")
diff --git a/src/lib/sos/plugins/kernel.py b/src/lib/sos/plugins/kernel.py
index a5ffd855..f2e6def3 100644
--- a/src/lib/sos/plugins/kernel.py
+++ b/src/lib/sos/plugins/kernel.py
@@ -50,7 +50,7 @@ class kernel(sos.plugintools.PluginBase):
self.collectExtOutput("/bin/uname -a", root_symlink = "uname")
self.moduleFile = self.collectOutputNow("/sbin/lsmod", root_symlink = "lsmod")
- if self.isOptionEnabled('modinfo'):
+ if self.getOption('modinfo'):
runcmd = ""
for kmod in commands.getoutput('/sbin/lsmod | /bin/cut -f1 -d" " 2>/dev/null | /bin/grep -v Module 2>/dev/null').split('\n'):
if '' != kmod.strip():
@@ -75,7 +75,7 @@ class kernel(sos.plugintools.PluginBase):
self.addCopySpec("/proc/driver")
self.addCopySpec("/proc/sys/kernel/tainted")
- if self.isOptionEnabled('sysrq') and os.access("/proc/sysrq-trigger", os.W_OK):
+ if self.getOption('sysrq') and os.access("/proc/sysrq-trigger", os.W_OK):
for key in ['m', 'p', 't']:
commands.getoutput("/bin/echo %s > /proc/sysrq-trigger" % (key,))
self.addCopySpec("/var/log/messages")
diff --git a/src/lib/sos/plugins/named.py b/src/lib/sos/plugins/named.py
index 421143cb..f4d24e19 100644
--- a/src/lib/sos/plugins/named.py
+++ b/src/lib/sos/plugins/named.py
@@ -20,21 +20,21 @@ class named(sos.plugintools.PluginBase):
"""named related information
"""
def checkenabled(self):
- if self.cInfo["policy"].pkgByName("bind") or os.path.exists("/etc/named.conf") or os.path.exists("/etc/sysconfig/named"):
- return True
- return False
+ self.files = [ "/etc/named.conf", "/etc/sysconfig/named" ]
+ self.packages = [ "bind" ]
+ return sos.plugintools.PluginBase.checkenabled(self)
def setup(self):
- dnsdir = ""
- self.addCopySpec("/etc/named.boot")
- self.addCopySpec("/etc/named.conf")
- self.addCopySpec("/etc/sysconfig/named")
- if os.access("/etc/named.conf", os.R_OK):
- dnsdir = commands.getoutput("/bin/grep -i directory /etc/named.conf | /bin/gawk '{print $2}' | /bin/sed 's/\\\"//g' | /bin/sed 's/\;//g'")
- if os.access("/etc/named.boot", os.R_OK):
- dnsdir = commands.getoutput("/bin/grep -i directory /etc/named.boot | /bin/gawk '{print $2}' | /bin/sed 's/\\\"//g' | /bin/sed 's/\;//g'")
- if '' != dnsdir.strip():
- self.addCopySpec(dnsdir)
- self.addForbiddenPath('/var/named/chroot/proc')
- self.addForbiddenPath('/var/named/chroot/dev')
- return
+ dnsdir = ""
+ self.addCopySpec("/etc/named.boot")
+ self.addCopySpec("/etc/named.conf")
+ self.addCopySpec("/etc/sysconfig/named")
+ # FIXME: use internal fileGrep() instead
+ if os.access("/etc/named.conf", os.R_OK):
+ dnsdir = commands.getoutput("/bin/grep -i directory /etc/named.conf | /bin/gawk '{print $2}' | /bin/sed 's/\\\"//g' | /bin/sed 's/\;//g'")
+ if os.access("/etc/named.boot", os.R_OK):
+ dnsdir = commands.getoutput("/bin/grep -i directory /etc/named.boot | /bin/gawk '{print $2}' | /bin/sed 's/\\\"//g' | /bin/sed 's/\;//g'")
+ if '' != dnsdir.strip():
+ self.addCopySpec(dnsdir)
+ self.addForbiddenPath('/var/named/chroot/proc')
+ self.addForbiddenPath('/var/named/chroot/dev')
diff --git a/src/lib/sos/plugins/networking.py b/src/lib/sos/plugins/networking.py
index aaf78234..164ed43a 100644
--- a/src/lib/sos/plugins/networking.py
+++ b/src/lib/sos/plugins/networking.py
@@ -65,7 +65,7 @@ class networking(sos.plugintools.PluginBase):
if ifconfigFile:
for eth in self.get_interface_name(ifconfigFile):
self.collectExtOutput("/sbin/ethtool "+eth)
- if self.isOptionEnabled("traceroute"):
+ if self.getOption("traceroute"):
self.collectExtOutput("/bin/traceroute -n rhn.redhat.com")
return
diff --git a/src/lib/sos/plugins/rpm.py b/src/lib/sos/plugins/rpm.py
index bcddaccb..279dde4c 100644
--- a/src/lib/sos/plugins/rpm.py
+++ b/src/lib/sos/plugins/rpm.py
@@ -23,10 +23,10 @@ class rpm(sos.plugintools.PluginBase):
def setup(self):
self.addCopySpec("/var/log/rpmpkgs")
- if self.isOptionEnabled("rpmq"):
+ if self.getOption("rpmq"):
self.collectExtOutput("/bin/rpm -qa --qf \"%{NAME}-%{VERSION}-%{RELEASE}-%{ARCH}\n\"", root_symlink = "installed-rpms")
- if self.isOptionEnabled("rpmva"):
+ if self.getOption("rpmva"):
self.eta_weight += 800 # this plugins takes 200x longer (for ETA)
self.collectExtOutput("/bin/rpm -Va", root_symlink = "rpm-Va")
return
diff --git a/src/lib/sos/plugins/squid.py b/src/lib/sos/plugins/squid.py
index 7e0c3376..3e9b3d8b 100644
--- a/src/lib/sos/plugins/squid.py
+++ b/src/lib/sos/plugins/squid.py
@@ -18,8 +18,10 @@ import os
class squid(sos.plugintools.PluginBase):
"""squid related information
"""
- files = [ "/etc/squid/squid.conf" ]
- packages = [ "squid" ]
+ def checkenabled(self):
+ self.files = [ "/etc/squid/squid.conf" ]
+ self.packages = [ "squid" ]
+ return sos.plugintools.PluginBase.checkenabled(self)
def setup(self):
self.addCopySpec("/etc/squid/squid.conf")
diff --git a/src/lib/sos/plugins/yum.py b/src/lib/sos/plugins/yum.py
index 0f0d049e..672451ee 100644
--- a/src/lib/sos/plugins/yum.py
+++ b/src/lib/sos/plugins/yum.py
@@ -22,9 +22,9 @@ class yum(sos.plugintools.PluginBase):
optionList = [("yumlist", "list repositories and packages", "slow", False)]
def checkenabled(self):
- if self.cInfo["policy"].pkgByName("yum") or os.path.exists("/etc/yum.conf"):
- return True
- return False
+ self.files = [ "/etc/yum.conf" ]
+ self.packages = [ "yum" ]
+ return sos.plugintools.PluginBase.checkenabled(self)
def analyze(self):
# repo sanity checking
@@ -42,7 +42,7 @@ class yum(sos.plugintools.PluginBase):
self.addCopySpec("/etc/yum.conf")
self.addCopySpec("/var/log/yum.log")
- if self.isOptionEnabled("yumlist"):
+ if self.getOption("yumlist"):
# Get a list of channels the machine is subscribed to.
self.collectExtOutput("/bin/echo \"repo list\" | /usr/bin/yum shell")
# List various information about available packages
diff --git a/src/lib/sos/plugintools.py b/src/lib/sos/plugintools.py
index f678297f..303e4fc5 100644
--- a/src/lib/sos/plugintools.py
+++ b/src/lib/sos/plugintools.py
@@ -233,14 +233,22 @@ class PluginBase:
"""
return (self.optNames, self.optParms)
- def setOption(self, optionname, enable):
- ''' enable or disable the named option.
+ def setOption(self, optionname, value):
+ ''' set the named option to value.
'''
for name, parms in zip(self.optNames, self.optParms):
if name == optionname:
- parms['enabled'] = enable
+ parms['enabled'] = value
+ return True
+ else:
+ return False
def isOptionEnabled(self, optionname):
+ ''' Deprecated, use getOption() instead
+ '''
+ return self.getOption(optionname)
+
+ def getOption(self, optionname):
''' see whether the named option is enabled.
'''
for name, parms in zip(self.optNames, self.optParms):
diff --git a/src/lib/sos/policyredhat.py b/src/lib/sos/policyredhat.py
index 9f61e68b..38ded430 100755
--- a/src/lib/sos/policyredhat.py
+++ b/src/lib/sos/policyredhat.py
@@ -27,6 +27,16 @@ import random
import re
import md5
import rpm
+import time
+
+sys.path.insert(0, "/usr/share/rhn/")
+try:
+ from up2date_client import up2dateAuth
+ from up2date_client import config
+ from rhn import rpclib
+except:
+ # might fail if non-RHEL
+ pass
#class SosError(Exception):
# def __init__(self, code, message):
@@ -73,9 +83,6 @@ class SosPolicy:
pkg = self.pkgByName(name)
return pkg['requirename']
- cmd = "/bin/rpm -q --requires %s" % (name)
- return [requires[:-1].split() for requires in os.popen(cmd).readlines()]
-
def allPkgsByName(self, name):
return self.allPkgs("name", name)
@@ -101,14 +108,20 @@ class SosPolicy:
return None
def allPkgs(self, ds = None, value = None):
+ # if possible return the cached values
+ try: return self._cache_rpm[ "%s-%s" % (ds,value) ]
+ except AttributeError: self._cache_rpm = {}
+ except KeyError: pass
+
ts = rpm.TransactionSet()
if ds and value:
mi = ts.dbMatch(ds, value)
else:
mi = ts.dbMatch()
- toret = [pkg for pkg in mi]
+
+ self._cache_rpm[ "%s-%s" % (ds,value) ] = [pkg for pkg in mi]
del mi, ts
- return toret
+ return self._cache_rpm[ "%s-%s" % (ds,value) ]
def runlevelByService(self, name):
ret = []
@@ -136,6 +149,9 @@ class SosPolicy:
def kernelVersion(self):
return commands.getoutput("/bin/uname -r").strip("\n")
+ def hostName(self):
+ return commands.getoutput("/bin/hostname").split(".")[0]
+
def rhelVersion(self):
try:
pkgname = self.pkgByName("redhat-release")["version"]
@@ -146,6 +162,15 @@ class SosPolicy:
except: pass
return False
+ def rhnUsername(self):
+ try:
+ cfg = config.initUp2dateConfig()
+
+ return rpclib.xmlrpclib.loads(up2dateAuth.getSystemId())[0][0]['username']
+ except:
+ # ignore any exception and return an empty username
+ return ""
+
def isKernelSMP(self):
if commands.getoutput("/bin/uname -v").split()[1] == "SMP":
return True
@@ -158,10 +183,22 @@ class SosPolicy:
name = "-".join(fields[:-3])
return (name, version, release, arch)
+ def getDstroot(self):
+ """Find a temp directory to form the root for our gathered information
+ and reports.
+ """
+ dstroot = "/tmp/%s-%s" % (self.hostName(), time.strftime("%Y%m%d%H%M%S"))
+ try:
+ os.mkdir(dstroot, 0700)
+ except:
+ return False
+ return dstroot
+
def preWork(self):
# this method will be called before the gathering begins
- localname = commands.getoutput("/bin/uname -n").split(".")[0]
+ localname = self.rhnUsername()
+ if len(localname) == 0: localname = self.hostName()
try:
self.reportName = raw_input(_("Please enter your first initial and last name [%s]: ") % localname)
@@ -178,70 +215,73 @@ class SosPolicy:
def packageResults(self):
- if len(self.ticketNumber):
- namestr = self.reportName + "." + self.ticketNumber
- else:
- namestr = self.reportName
-
- ourtempdir = gettempdir()
- tarballName = os.path.join(ourtempdir, "sosreport-" + namestr + ".tar.bz2")
+ self.report_file = os.path.join(gettempdir(), "sosreport-%s-%s.tar.bz2" % (self.reportName,time.strftime("%Y%m%d%H%M%S")))
- namestr = namestr + "-" + str(random.randint(1, 999999))
-
- aliasdir = os.path.join(ourtempdir, namestr)
-
- tarcmd = "/bin/tar -jcf %s %s" % (tarballName, namestr)
+ tarcmd = "/bin/tar -jcf %s %s" % (self.report_file, os.path.basename(self.cInfo['dstroot']))
print _("Creating compressed archive...")
- if not os.access(string.split(tarcmd)[0], os.X_OK):
- print "Unable to create tarball"
- return
- # FIXME: gotta be a better way...
- os.system("/bin/mv %s %s" % (self.cInfo['dstroot'], aliasdir))
curwd = os.getcwd()
- os.chdir(ourtempdir)
+ os.chdir(os.path.dirname(self.cInfo['dstroot']))
oldmask = os.umask(077)
- # pylint: disable-msg = W0612
status, shout, runtime = sosGetCommandOutput(tarcmd)
os.umask(oldmask)
os.chdir(curwd)
- # FIXME: use python internal command
- os.system("/bin/mv %s %s" % (aliasdir, self.cInfo['dstroot']))
- # FIXME: encrypt using gnupg
- # gpg --trust-model always --batch --keyring /usr/share/sos/rhsupport.pub --no-default-keyring --compress-level 0 --encrypt --recipient support@redhat.com --output filename.gpg filename.tar
+ return
- # add last 6 chars from md5sum to file name
- fp = open(tarballName, "r")
+ def cleanDstroot(self):
+ if not os.path.isdir(os.path.join(self.cInfo['dstroot'],"sos_commands")):
+ # doesn't look like a dstroot, refusing to clean
+ return False
+ os.system("/bin/rm -rf %s" % self.cInfo['dstroot'])
+
+ def encryptResults(self):
+ # make sure a report exists
+ if not self.report_file:
+ return False
+
+ print _("Encrypting archive...")
+ gpgname = self.report_file + ".gpg"
+ status, output = commands.getstatusoutput("/usr/bin/gpg --trust-model always --batch --keyring /usr/share/sos/rhsupport.pub --no-default-keyring --compress-level 0 --encrypt --recipient support@redhat.com --output %s %s" % (gpgname,self.report_file))
+ if status == 0:
+ os.unlink(self.report_file)
+ self.report_file = gpgname
+ else:
+ print _("There was a problem encrypting your report.")
+ sys.exit(1)
+
+ def displayResults(self):
+ # make sure a report exists
+ if not self.report_file:
+ return False
+
+ # calculate md5
+ fp = open(self.report_file, "r")
md5out = md5.new(fp.read()).hexdigest()
fp.close()
- oldtarballName = tarballName
- tarballName = os.path.join(ourtempdir, "sosreport-%s-%s.tar.bz2" % (namestr, md5out[-6:]) )
- os.system("/bin/mv %s %s" % (oldtarballName, tarballName) )
+
# store md5 to a file
- fp = open(tarballName + ".md5", "w")
+ fp = open(self.report_file + ".md5", "w")
fp.write(md5out + "\n")
fp.close()
- sys.stdout.write("\n")
- print _("Your sosreport has been generated and saved in:\n %s") % tarballName
+ print
+ print _("Your sosreport has been generated and saved in:\n %s") % self.report_file
print
if md5out:
print _("The md5sum is: ") + md5out
print
print _("Please send this file to your support representative.")
- sys.stdout.write("\n")
-
- self.report_file = tarballName
+ print
- return
-
def uploadResults(self):
# make sure a report exists
if not self.report_file:
return False
+ print
+
# make sure it's readable
try:
fp = open(self.report_file, "r")
@@ -261,7 +301,7 @@ class SosPolicy:
except:
print _("There was a problem uploading your report to Red Hat support.")
else:
- print _('Your report was uploaded successfully with name:')
+ print _("Your report was successfully uploaded to Red Hat's ftp server with name:")
print " " + upload_name
print
print _("Please communicate this name to your support representative.")
diff --git a/src/setup.py b/src/setup.py
index b64c3593..3272531f 100644
--- a/src/setup.py
+++ b/src/setup.py
@@ -9,6 +9,6 @@ setup(
packages = ['sos', 'sos.plugins'],
scripts = [],
package_dir = {'': 'lib',},
- data_files = [ ('/usr/sbin', ['sosreport', 'extras/sysreport/sysreport.legacy']), ('/usr/bin', ['extras/rh-upload-core']), ('/usr/share/sysreport', ['extras/sysreport/text.xsl', 'extras/sysreport/functions', 'extras/sysreport/sysreport-fdisk']), ('/usr/share/man/man1', ['sosreport.1']), ('/usr/share/locale/en', []), ('/usr/share/locale/it', []), ('/usr/share/locale/en/LC_MESSAGES', ['locale/en/LC_MESSAGES/sos.mo']), ('/usr/share/locale/it/LC_MESSAGES', ['locale/it/LC_MESSAGES/sos.mo']), ('/usr/share/locale/fr/LC_MESSAGES', ['locale/fr/LC_MESSAGES/sos.mo']), ('/usr/share/locale/ar/LC_MESSAGES', ['locale/ar/LC_MESSAGES/sos.mo'])
+ data_files = [ ('/usr/sbin', ['sosreport', 'extras/sysreport/sysreport.legacy']), ('/usr/bin', ['extras/rh-upload-core']), ('/usr/share/sos', ['gpgkeys/rhsupport.pub']), ('/usr/share/sysreport', ['extras/sysreport/text.xsl', 'extras/sysreport/functions', 'extras/sysreport/sysreport-fdisk']), ('/usr/share/man/man1', ['sosreport.1']), ('/usr/share/locale/en', []), ('/usr/share/locale/it', []), ('/usr/share/locale/en/LC_MESSAGES', ['locale/en/LC_MESSAGES/sos.mo']), ('/usr/share/locale/it/LC_MESSAGES', ['locale/it/LC_MESSAGES/sos.mo']), ('/usr/share/locale/fr/LC_MESSAGES', ['locale/fr/LC_MESSAGES/sos.mo']), ('/usr/share/locale/ar/LC_MESSAGES', ['locale/ar/LC_MESSAGES/sos.mo'])
]
)
diff --git a/src/sos.spec b/src/sos.spec
index 73182665..58a3f67b 100644
--- a/src/sos.spec
+++ b/src/sos.spec
@@ -2,7 +2,7 @@
%define name sos
%define version 1.7
-%define release 10pre0
+%define release 10pre1
%define _localedir %_datadir/locale
@@ -47,6 +47,7 @@ rm -rf ${RPM_BUILD_ROOT}
%files
%defattr(-,root,root,-)
%{_sbindir}/sosreport
+/usr/share/sos/rhsupport.pub
/usr/bin/rh-upload-core
/usr/sbin/sysreport
/usr/sbin/sysreport.legacy
diff --git a/src/sosreport b/src/sosreport
index 8e9d2697..88e50a97 100755
--- a/src/sosreport
+++ b/src/sosreport
@@ -70,9 +70,7 @@ def doExitCode():
doExitCode()
else:
print "All threads ended, cleaning up."
- if os.path.isdir(os.path.join(dstroot,"sos_commands")):
- os.system("/bin/rm -rf %s" % dstroot)
- sys.exit(1)
+ doExit(1)
if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ):
print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately"
@@ -83,10 +81,15 @@ def doExitCode():
os.kill(os.getpid(), signal.SIGKILL)
elif ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ):
print "Multiple SIGTERMs, single thread, exiting without cleaning up."
- sys.exit(3)
+ doExit(3)
# FIXME: Add code here to clean up /tmp
- sys.exit("Abnormal exit")
+ 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():
@@ -157,6 +160,9 @@ __cmdParser__.add_option("-a", "--alloptions", action="store_true", \
__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("-v", "--verbose", action="count", \
dest="verbosity", \
help="increase verbosity")
@@ -337,7 +343,7 @@ def sosreport():
This is the top-level function that gathers and processes all sosreport information
"""
- global loadedplugins, dstroot
+ global loadedplugins, dstroot, policy
loadedplugins = []
skippedplugins = []
@@ -354,7 +360,11 @@ def sosreport():
# Set up common info and create destinations
- dstroot = sosFindTmpDir()
+ dstroot = policy.getDstroot()
+ if not dstroot:
+ print _("Could not create temporary directory.")
+ doExit()
+
cmddir = os.path.join(dstroot, "sos_commands")
logdir = os.path.join(dstroot, "sos_logs")
rptdir = os.path.join(dstroot, "sos_reports")
@@ -411,8 +421,7 @@ def sosreport():
# generate list of available plugins
plugins = os.listdir(pluginpath)
plugins.sort()
-
- # FIXME: should at least print a warning if the user references a plugin which does not exist
+ plugin_names = []
# validate and load plugins
for plug in plugins:
@@ -426,6 +435,8 @@ def sosreport():
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)))
@@ -473,7 +484,11 @@ def sosreport():
except: pass
# split up "general.syslogsize"
- plug, opt = opt.split(".")
+ try:
+ plug, opt = opt.split(".")
+ except:
+ plug = opt
+ opt = True
try: opts[plug]
except KeyError: opts[plug] = []
@@ -482,10 +497,26 @@ 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))
- plug.setOption(opt,val)
+ 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)
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()
@@ -499,7 +530,7 @@ def sosreport():
if __cmdLineOpts__.listPlugins:
if not len(loadedplugins) and not len(skippedplugins):
soslog.error(_("no valid plugins found"))
- sys.exit(1)
+ doExit(1)
# FIXME: make -l output more concise
if len(loadedplugins):
@@ -542,20 +573,20 @@ def sosreport():
print _("No plugin options available.")
print
- sys.exit()
+ doExit()
# 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)
+ doExit(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)
+ doExit(1)
try:
raw_input(_("""This utility will collect some detailed information about the
@@ -572,7 +603,7 @@ Press ENTER to continue, or CTRL-C to quit.
"""))
except:
print
- sys.exit(0)
+ doExit()
# Call the diagnose() method for each plugin
tmpcount = 0
@@ -606,11 +637,11 @@ Press ENTER to continue, or CTRL-C to quit.
print
break
elif yorno == _("n") or yorno == _("N"):
- sys.exit(0)
+ doExit(0)
del yorno
except KeyboardInterrupt:
print
- sys.exit(0)
+ doExit(0)
policy.preWork()
@@ -770,11 +801,18 @@ Press ENTER to continue, or CTRL-C to quit.
# package up the results for the support organization
policy.packageResults()
+
# delete gathered files
- os.system("/bin/rm -rf %s" % dstroot)
+ policy.cleanDstroot()
+
+ # let's encrypt the tar-ball
+ if __cmdLineOpts__.encrypt:
+ policy.encryptResults()
# automated submission will go here
- if __cmdLineOpts__.upload:
+ if not __cmdLineOpts__.upload:
+ policy.displayResults()
+ else:
policy.uploadResults()
# Close all log files and perform any cleanup
diff --git a/src/sosreport.1 b/src/sosreport.1
index cd7d34df..3ae187a8 100644
--- a/src/sosreport.1
+++ b/src/sosreport.1
@@ -44,19 +44,21 @@ Do not display a progress bar (ETA will not be available).
.TP
.B \--no-multithread
Disable multithreaded collection and analysis of the sosreport data.
-.SH MAINTAINERS
+.SH MAINTAINER
.nf
Navid Sheikhol-Eslami <navid@redhat.com>
.fi
-.SH TRANSLATIONS
-.nf
-Eva Schaller <eschalle@redhat.com> [Italian]
-Imed Chihi <ichihi@redhat.com> [Arabic] [French]
-.fi
.SH AUTHORS
.nf
Steve Conklin <sconklin@redhat.com>
John Berninger <jwb@redhat.com>
-Navid Sheikhol-Eslami <navid@redhat.com>
Pierre Amadio <pamadio@redhat.com>
+Adam Stokes <astokes@redhat.com>
+.fi
+.SH THANKS TO
+.nf
+Eva Schaller <eschaller@redhat.com> for providing an Italian translation
+Marco Ceci <mceci@redhat.com> for helping me out with the cluster plugin
+Leonardo Macchia <lmacchia@redhat.com> for being my personal regexp generator
+Imed Chihi <ichihi@redhat.com> for providing Arabic and French translations
.fi