diff options
-rwxr-xr-x | src/lib/sos/helpers.py | 57 | ||||
-rw-r--r-- | src/lib/sos/plugins/autofs.py | 31 | ||||
-rw-r--r-- | src/lib/sos/plugins/cluster.py | 4 | ||||
-rw-r--r-- | src/lib/sos/plugins/devicemapper.py | 16 | ||||
-rw-r--r-- | src/lib/sos/plugins/general.py | 12 | ||||
-rw-r--r-- | src/lib/sos/plugins/hardware.py | 17 | ||||
-rw-r--r-- | src/lib/sos/plugins/kernel.py | 4 | ||||
-rw-r--r-- | src/lib/sos/plugins/ldap.py | 21 | ||||
-rw-r--r-- | src/lib/sos/plugins/named.py | 15 | ||||
-rw-r--r-- | src/lib/sos/plugins/pam.py | 2 | ||||
-rw-r--r-- | src/lib/sos/plugins/rpm.py | 4 | ||||
-rw-r--r-- | src/lib/sos/plugintools.py | 35 | ||||
-rwxr-xr-x | src/lib/sos/policyredhat.py | 57 | ||||
-rw-r--r-- | src/sos.spec | 5 | ||||
-rwxr-xr-x | src/sosreport | 86 |
15 files changed, 192 insertions, 174 deletions
diff --git a/src/lib/sos/helpers.py b/src/lib/sos/helpers.py index 61ce8487..77f85b01 100755 --- a/src/lib/sos/helpers.py +++ b/src/lib/sos/helpers.py @@ -25,9 +25,29 @@ """ helper functions used by sosreport and plugins """ -import os, popen2, fcntl, select, itertools, sys, commands, logging, signal +import os, popen2, fcntl, select, sys, commands, signal from time import time, sleep -from tempfile import mkdtemp + +if sys.version_info[0] <= 2 and sys.version_info[1] <= 2: + # it's a RHEL3, activate work-arounds + # + import sos.rhel3_logging + logging = sos.rhel3_logging + + def mkdtemp(suffix = "", prefix = "temp_"): + import random + while True: + tempdir = "/tmp/%s_%d%s" % (prefix, random.randint(1,9999999), suffix) + if not os.path.exists(tempdir): break + os.mkdir(tempdir) + return tempdir + + os.path.sep = "/" + os.path.pardir = ".." +else: + # RHEL4+, business as usual + import logging + from tempfile import mkdtemp def importPlugin(pluginname, name): """ Import a plugin to extend capabilities of sosreport @@ -81,16 +101,16 @@ def sosGetCommandOutput(command, timeout = 300): if pid: # we are the parent os.close(w) # use os.close() to close a file descriptor - oldr = r - r = os.fdopen(r) # turn r into a file object + r_fd = os.fdopen(r) # turn r into a file object stime=time() txt = "" sts = -1 + soslog.log(logging.VERBOSE2, 'forked command "%s" with pid %d, timeout is %d' % (command, pid, timeout) ) while True: # read output from pipe - ready = select.select([oldr],[],[],1) - if len(ready[0]): - txt = txt + r.read() + ready = select.select([r], [], [], 1) + if r in ready[0]: + txt = txt + r_fd.read() # is child still running ? try: os.waitpid(pid, os.WNOHANG) except: @@ -101,7 +121,8 @@ def sosGetCommandOutput(command, timeout = 300): # has 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) + try: os.kill(pid, signal.SIGKILL) + except: pass break if txt[-1:] == '\n': txt = txt[:-1] return (sts, txt, time()-stime) @@ -113,6 +134,8 @@ def sosGetCommandOutput(command, timeout = 300): import resource maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] + if not hasattr(resource, "RLIM_INFINITY"): + resource.RLIM_INFINITY = -1L if (maxfd == resource.RLIM_INFINITY): maxfd = MAXFD for fd in range(3, maxfd): @@ -144,23 +167,11 @@ def allEqual(elements): return False return True - -def commonPrefix(*sequences): +def commonPrefix(l1, l2, common = []): ''' return a list of common elements at the start of all sequences, then a list of lists that are the unique tails of each sequence. ''' - # if there are no sequences at all, we're done - if not sequences: - return [], [] - # loop in parallel on the sequences - common = [] - for elements in itertools.izip(*sequences): - # unless all elements are equal, bail out of the loop - if not allEqual(elements): - break - # got one more common element, append it and keep looping - common.append(elements[0]) - # return the common prefix and unique tails - return common, [ sequence[len(common):] for sequence in sequences ] + if len(l1) < 1 or len(l2) < 1 or l1[0] != l2[0]: return common, [l1, l2] + return commonPrefix(l1[1:], l2[1:], common+[l1[0]]) def sosRelPath(path1, path2, sep=os.path.sep, pardir=os.path.pardir): ''' return a relative path from path1 equivalent to path path2. diff --git a/src/lib/sos/plugins/autofs.py b/src/lib/sos/plugins/autofs.py index 5e8be418..16a8d3fb 100644 --- a/src/lib/sos/plugins/autofs.py +++ b/src/lib/sos/plugins/autofs.py @@ -25,38 +25,7 @@ class autofs(sos.plugintools.PluginBase): return True return False - def checkdebug(self): - """ - Probably not needed? I think we can pretty much assume that if daemon.* is - set in /etc/syslog.conf then debugging is enabled. - FIXME: remove checkdebug if not needed in future release - """ - pass - # Global debugging - optlist=[] - opt = self.doRegexFindAll(r"^(DEFAULT_LOGGING|DAEMONOPTIONS)=(.*)", "/etc/sysconfig/autofs") - for opt1 in opt: - optlist.append(opt1)[1] - for dtest in optlist: - if dtest == "--debug" or dtest == "debug": - return True - - def getdaemondebug(self): - """ capture daemon debug output - """ - debugout=self.doRegexFindAll(r"^daemon.*\s+(\/var.*)", "/etc/syslog.conf") - for i in debugout: - return i - def setup(self): self.addCopySpec("/etc/auto*") self.addCopySpec("/etc/sysconfig/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() - if daemon_debug_file: - self.addCopySpec(daemon_debug_file) - return - diff --git a/src/lib/sos/plugins/cluster.py b/src/lib/sos/plugins/cluster.py index 280ad3b1..1ef4fe2a 100644 --- a/src/lib/sos/plugins/cluster.py +++ b/src/lib/sos/plugins/cluster.py @@ -25,10 +25,6 @@ class cluster(sos.plugintools.PluginBase): ('taskdump', 'trigger 3 sysrq+t dumps every 5 seconds (dangerous)', 'slow', False)] def checkenabled(self): - 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", diff --git a/src/lib/sos/plugins/devicemapper.py b/src/lib/sos/plugins/devicemapper.py index c2be8eba..5a1b63c2 100644 --- a/src/lib/sos/plugins/devicemapper.py +++ b/src/lib/sos/plugins/devicemapper.py @@ -22,11 +22,6 @@ class devicemapper(sos.plugintools.PluginBase): 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")) - def setup(self): self.collectExtOutput("/sbin/dmsetup info -c") self.collectExtOutput("/sbin/dmsetup table") @@ -51,11 +46,12 @@ class devicemapper(sos.plugintools.PluginBase): self.collectExtOutput("/bin/ls -laR /sys/block") if self.getOption('lvmdump'): - self.do_lvmdump() + sosGetCommandOutput("lvmdump -d %s" % os.path.join(self.cInfo['dstroot'],"lvmdump")) - for disk in os.listdir("/sys/block"): - if disk in [ ".", ".." ] or disk.startswith("ram"): - continue - self.collectExtOutput("/usr/bin/udevinfo -ap /sys/block/%s" % (disk)) + if os.path.isdir("/sys/block"): + for disk in os.listdir("/sys/block"): + if disk in [ ".", ".." ] or disk.startswith("ram"): + continue + self.collectExtOutput("/usr/bin/udevinfo -ap /sys/block/%s" % (disk)) return diff --git a/src/lib/sos/plugins/general.py b/src/lib/sos/plugins/general.py index 6f1f912c..c124c001 100644 --- a/src/lib/sos/plugins/general.py +++ b/src/lib/sos/plugins/general.py @@ -12,6 +12,7 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +import os import sos.plugintools import glob @@ -19,7 +20,8 @@ class general(sos.plugintools.PluginBase): """basic system information """ - optionList = [("syslogsize", "max size (MiB) to collect per syslog file", "", 15)] + optionList = [("syslogsize", "max size (MiB) to collect per syslog file", "", 15), + ("all_logs", "collect all log files defined in syslog.conf", "", False)] def setup(self): self.addCopySpec("/etc/redhat-release") @@ -37,6 +39,14 @@ class general(sos.plugintools.PluginBase): self.collectExtOutput("/bin/date", root_symlink = "date") self.collectExtOutput("/usr/bin/uptime", root_symlink = "uptime") self.collectExtOutput("/bin/env") + + if self.getOption('all_logs'): + logs=self.doRegexFindAll(r"^\S+\s+(\S+)", "/etc/syslog.conf") + for i in logs: + i = i.lstrip("-") + if not os.path.isfile(i): continue + self.addCopySpec(i) + return def postproc(self): diff --git a/src/lib/sos/plugins/hardware.py b/src/lib/sos/plugins/hardware.py index 22f13e6d..ad4a5537 100644 --- a/src/lib/sos/plugins/hardware.py +++ b/src/lib/sos/plugins/hardware.py @@ -36,23 +36,12 @@ class hardware(sos.plugintools.PluginBase): self.addCopySpec("/proc/dasd") self.addCopySpec("/proc/s390dbf/tape") self.collectExtOutput("/usr/share/rhn/up2dateclient/hardware.py") - self.collectExtOutput("""/bin/echo "lspci:" ; /bin/echo ; /sbin/lspci ; /bin/echo ; /bin/echo "lspci -nvv:" ; /bin/echo ; /sbin/lspci -nvv""", suggest_filename = "lspci", root_symlink = "lspci") + self.collectExtOutput("""/bin/echo -e "lspci:\n" ; /sbin/lspci ; /bin/echo -e "\nlspci -nvv:\n" ; /sbin/lspci -nvv ; /bin/echo -e "\nlspci -tv:\n" ; /sbin/lspci -tv""", suggest_filename = "lspci", root_symlink = "lspci") self.collectExtOutput("/usr/sbin/dmidecode", root_symlink = "dmidecode") - # FIXME: if arch == i386: -# self.collectExtOutput("/usr/sbin/x86info -a") - - # FIXME: what is this for? - self.collectExtOutput("/bin/dmesg | /bin/grep -e 'e820.' -e 'agp.'") - - # FIXME: what is this for? - tmpreg = "" - for hwmodule in commands.getoutput('cat /lib/modules/$(uname -r)/modules.pcimap | cut -d " " -f 1 | grep "[:alpha:]" | sort -u').split("\n"): - hwmodule = hwmodule.strip() - if len(hwmodule): - tmpreg = tmpreg + "|" + hwmodule - self.collectExtOutput("/bin/dmesg | /bin/egrep '(%s)'" % tmpreg[1:]) + if self.cInfo["policy"].getArch().endswith("386"): + self.collectExtOutput("/usr/sbin/x86info -a") self.collectExtOutput("/sbin/lsusb") self.collectExtOutput("/usr/bin/lshal") diff --git a/src/lib/sos/plugins/kernel.py b/src/lib/sos/plugins/kernel.py index f2e6def3..9a662fe7 100644 --- a/src/lib/sos/plugins/kernel.py +++ b/src/lib/sos/plugins/kernel.py @@ -64,9 +64,7 @@ class kernel(sos.plugintools.PluginBase): self.addCopySpec("/proc/filesystems") self.addCopySpec("/proc/ksyms") self.addCopySpec("/proc/slabinfo") - # FIXME: kver should have this stuff cached somewhere - kver = commands.getoutput('/bin/uname -r') - self.addCopySpec("/lib/modules/%s/modules.dep" % kver) + self.addCopySpec("/lib/modules/%s/modules.dep" % self.cInfo["policy"].kernelVersion()) self.addCopySpec("/etc/conf.modules") self.addCopySpec("/etc/modules.conf") self.addCopySpec("/etc/modprobe.conf") diff --git a/src/lib/sos/plugins/ldap.py b/src/lib/sos/plugins/ldap.py index 47ac0612..e4779178 100644 --- a/src/lib/sos/plugins/ldap.py +++ b/src/lib/sos/plugins/ldap.py @@ -18,6 +18,11 @@ import os class ldap(sos.plugintools.PluginBase): """LDAP related information """ + def checkenabled(self): + self.packages = [ "openldap" ] + self.files = [ "/etc/openldap/ldap.conf" ] + return sos.plugintools.PluginBase.checkenabled(self) + def get_ldap_opts(self): # capture /etc/openldap/ldap.conf options in dict # FIXME: possibly not hardcode these options in? @@ -30,30 +35,16 @@ class ldap(sos.plugintools.PluginBase): results[x[0]]=x[1].rstrip("\n") return results - def get_slapd_debug(self): - """ Capture debugging information based on an existing log level - """ - loglevel=self.doRegexFindAll(r"^local4.*\s+(\/var.*)", "/etc/syslog.conf") - for i in loglevel: - return i - def diagnose(self): # Validate ldap client options ldapopts=self.get_ldap_opts() - if ldapopts.has_key("TLS_CACERTDIR"): - try: - os.stat(ldapopts["TLS_CACERTDIR"]) - except: + if ldapopts.has_key("TLS_CACERTDIR") and os.path.exists(ldapopts["TLS_CACERTDIR"]): self.addDiagnose("%s does not exist and can cause connection issues involving TLS" % ldapopts["TLS_CACERTDIR"]) def setup(self): self.addCopySpec("/etc/ldap.conf") self.addCopySpec("/etc/openldap") - slapd_debug_file = self.get_slapd_debug() - if slapd_debug_file: - self.addCopySpec(slapd_debug_file) - def postproc(self): self.doRegexSub("/etc/ldap.conf", r"(\s*bindpw\s*)\S+", r"\1***") return diff --git a/src/lib/sos/plugins/named.py b/src/lib/sos/plugins/named.py index f4d24e19..bb0d079e 100644 --- a/src/lib/sos/plugins/named.py +++ b/src/lib/sos/plugins/named.py @@ -21,20 +21,13 @@ class named(sos.plugintools.PluginBase): """ def checkenabled(self): self.files = [ "/etc/named.conf", "/etc/sysconfig/named" ] - self.packages = [ "bind" ] + self.packages = [ "bind", "bind-chroot" ] 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") - # 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') + self.addCopySpec("/var/named") + self.addForbiddenPath('/var/named/chroot/proc') + self.addForbiddenPath('/var/named/chroot/dev') diff --git a/src/lib/sos/plugins/pam.py b/src/lib/sos/plugins/pam.py index 8164bba3..1a50811b 100644 --- a/src/lib/sos/plugins/pam.py +++ b/src/lib/sos/plugins/pam.py @@ -20,6 +20,6 @@ class pam(sos.plugintools.PluginBase): def setup(self): self.addCopySpec("/etc/pam.d") self.addCopySpec("/etc/security") - self.collectExtOutput("/bin/ls -laF /lib/security/pam_*so") + self.collectExtOutput("/bin/ls -laF /lib/security") return diff --git a/src/lib/sos/plugins/rpm.py b/src/lib/sos/plugins/rpm.py index 279dde4c..f1c09e33 100644 --- a/src/lib/sos/plugins/rpm.py +++ b/src/lib/sos/plugins/rpm.py @@ -27,7 +27,7 @@ class rpm(sos.plugintools.PluginBase): self.collectExtOutput("/bin/rpm -qa --qf \"%{NAME}-%{VERSION}-%{RELEASE}-%{ARCH}\n\"", root_symlink = "installed-rpms") if self.getOption("rpmva"): - self.eta_weight += 800 # this plugins takes 200x longer (for ETA) - self.collectExtOutput("/bin/rpm -Va", root_symlink = "rpm-Va") + self.eta_weight += 1500 # this plugins takes 200x longer (for ETA) + self.collectExtOutput("/bin/rpm -Va", root_symlink = "rpm-Va", timeout = 3600) return diff --git a/src/lib/sos/plugintools.py b/src/lib/sos/plugintools.py index 303e4fc5..2501c450 100644 --- a/src/lib/sos/plugintools.py +++ b/src/lib/sos/plugintools.py @@ -30,11 +30,25 @@ This is the base class for sosreport plugins """ from sos.helpers import * from threading import Thread, activeCount -import os, os.path, sys, string, itertools, glob, re, traceback -import logging, shutil +import os, os.path, sys, string, glob, re, traceback +import shutil from stat import * from time import time +# RHEL3 doesn't have a logging module +try: + import logging +except ImportError: + import sos.rhel3_logging + logging = sos.rhel3_logging + +# RHEL3 doesn't have format_exc +if sys.version_info[0] <= 2 and sys.version_info[1] <= 2: + def format_exc(): + return "ciao" + + traceback.format_exc = format_exc + class PluginBase: """ Base class for plugins @@ -177,6 +191,7 @@ class PluginBase: pass else: self.doCopyFileOrDir(srcpath+'/'+afile) + return # if we get here, it's definitely a regular file (not a symlink or dir) @@ -291,11 +306,11 @@ class PluginBase: status, shout, runtime = sosGetCommandOutput(prog) return status - def collectExtOutput(self, exe, suggest_filename = None, root_symlink = None): + def collectExtOutput(self, exe, suggest_filename = None, root_symlink = None, timeout = 300): """ Run a program and collect the output """ - self.collectProgs.append( (exe,suggest_filename,root_symlink) ) + self.collectProgs.append( (exe, suggest_filename, root_symlink, timeout) ) def fileGrep(self, regexp, fname): results = [] @@ -331,14 +346,13 @@ class PluginBase: return outfn - def collectOutputNow(self, exe, suggest_filename = None, root_symlink = False): + def collectOutputNow(self, exe, suggest_filename = None, root_symlink = False, timeout = 300): """ Execute a command and save the output to a file for inclusion in the report """ - # FIXME: we should have a timeout or we may end waiting forever # pylint: disable-msg = W0612 - status, shout, runtime = sosGetCommandOutput(exe) + status, shout, runtime = sosGetCommandOutput(exe, timeout = timeout) if suggest_filename: outfn = self.makeCommandFilename(suggest_filename) @@ -356,7 +370,8 @@ class PluginBase: if root_symlink: curdir = os.getcwd() os.chdir(self.cInfo['dstroot']) - os.symlink(outfn[len(self.cInfo['dstroot'])+1:], root_symlink.strip("/.")) + try: os.symlink(outfn[len(self.cInfo['dstroot'])+1:], root_symlink.strip("/.")) + except: pass os.chdir(curdir) outfn_strip = outfn[len(self.cInfo['cmddir'])+1:] @@ -469,10 +484,10 @@ class PluginBase: except Exception, e: self.soslog.log(logging.VERBOSE2, "error copying from pathspec %s (%s), traceback follows:" % (path,e)) self.soslog.log(logging.VERBOSE2, traceback.format_exc()) - for (prog,suggest_filename,root_symlink) in self.collectProgs: + for (prog, suggest_filename, root_symlink, timeout) in self.collectProgs: self.soslog.debug("collecting output of '%s'" % prog) try: - self.collectOutputNow(prog, suggest_filename, root_symlink) + self.collectOutputNow(prog, suggest_filename, root_symlink, timeout) except SystemExit: if semaphore: semaphore.release() if threaded: return SystemExit diff --git a/src/lib/sos/policyredhat.py b/src/lib/sos/policyredhat.py index 38ded430..2f65dd39 100755 --- a/src/lib/sos/policyredhat.py +++ b/src/lib/sos/policyredhat.py @@ -61,7 +61,10 @@ def memoized(function): class SosPolicy: "This class implements various policies for sos" def __init__(self): - self.report_file = None + self.report_file = "" + self.report_md5 = "" + self.reportName = "" + self.ticketNumber = "" return def setCommons(self, commons): @@ -177,6 +180,9 @@ class SosPolicy: else: return False + def getArch(self): + return commands.getoutput("/bin/uname -m").strip() + def pkgNVRA(self, pkg): fields = pkg.split("-") version, release, arch = fields[-3:] @@ -200,22 +206,33 @@ class SosPolicy: 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) - self.reportName = re.sub(r"[^a-zA-Z.0-9]", "", self.reportName) - if len(self.reportName) == 0: - self.reportName = localname + if not self.cInfo['cmdlineopts'].batch: + try: + self.reportName = raw_input(_("Please enter your first initial and last name [%s]: ") % localname) + self.reportName = re.sub(r"[^a-zA-Z.0-9]", "", self.reportName) - self.ticketNumber = raw_input(_("Please enter the case number that you are generating this report for: ")) - self.ticketNumber = re.sub(r"[^0-9]", "", self.ticketNumber) - print - except: - print - sys.exit(0) + self.ticketNumber = raw_input(_("Please enter the case number that you are generating this report for: ")) + self.ticketNumber = re.sub(r"[^0-9]", "", self.ticketNumber) + print + except: + print + sys.exit(0) + + if len(self.reportName) == 0: + self.reportName = localname + + return + + def renameResults(self, newName): + newName = os.path.join(gettempdir(), newName) + if len(self.report_file) and os.path.isfile(self.report_file): + try: os.rename(self.report_file, newName) + except: return False + self.report_file = newName def packageResults(self): - self.report_file = os.path.join(gettempdir(), "sosreport-%s-%s.tar.bz2" % (self.reportName,time.strftime("%Y%m%d%H%M%S"))) + self.renameResults("sosreport-%s-%s.tar.bz2" % (self.reportName, time.strftime("%Y%m%d%H%M%S"))) tarcmd = "/bin/tar -jcf %s %s" % (self.report_file, os.path.basename(self.cInfo['dstroot'])) @@ -224,7 +241,7 @@ class SosPolicy: curwd = os.getcwd() os.chdir(os.path.dirname(self.cInfo['dstroot'])) oldmask = os.umask(077) - status, shout, runtime = sosGetCommandOutput(tarcmd) + status, shout = commands.getstatusoutput(tarcmd) os.umask(oldmask) os.chdir(curwd) @@ -258,19 +275,21 @@ class SosPolicy: # calculate md5 fp = open(self.report_file, "r") - md5out = md5.new(fp.read()).hexdigest() + self.report_md5 = md5.new(fp.read()).hexdigest() fp.close() - # store md5 to a file + self.renameResults("sosreport-%s-%s-%s.tar.bz2" % (self.reportName, time.strftime("%Y%m%d%H%M%S"), self.report_md5[-4:])) + + # store md5 into file fp = open(self.report_file + ".md5", "w") - fp.write(md5out + "\n") + fp.write(self.report_md5 + "\n") fp.close() print print _("Your sosreport has been generated and saved in:\n %s") % self.report_file print - if md5out: - print _("The md5sum is: ") + md5out + if len(self.report_md5): + print _("The md5sum is: ") + self.report_md5 print print _("Please send this file to your support representative.") print diff --git a/src/sos.spec b/src/sos.spec index 973be121..5a5e7212 100644 --- a/src/sos.spec +++ b/src/sos.spec @@ -1,8 +1,8 @@ %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} %define name sos -%define version 1.7 -%define release 10pre1 +%define version 1.8 +%define release 0pre0 %define _localedir %_datadir/locale @@ -23,6 +23,7 @@ BuildArch: noarch Url: http://sos.108.redhat.com/ BuildRequires: python-devel Requires: libxml2-python +Provides: sysreport = 1.3.15-8 Obsoletes: sysreport %description diff --git a/src/sosreport b/src/sosreport index 88e50a97..d8b631ae 100755 --- a/src/sosreport +++ b/src/sosreport @@ -33,14 +33,20 @@ from sos.helpers import * from snack import * from threading import Thread, activeCount import signal -import logging from stat import * from time import strftime, localtime, time from pwd import getpwuid import gettext from threading import Semaphore -__version__ = 1.7 +# RHEL3 doesn't have a logging module +try: + import logging +except ImportError: + import sos.rhel3_logging + logging = sos.rhel3_logging + +__version__ = 1.8 __breakHits__ = 0 # Use this to track how many times we enter the exit routine @@ -73,7 +79,7 @@ def doExitCode(): doExit(1) if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ): - print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately" + print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately." ## FIXME: Add thread-kill code (see FIXME below) return elif ( ( activeCount() > 1 ) and ( __breakHits__ > 2 ) ): @@ -83,7 +89,6 @@ def doExitCode(): print "Multiple SIGTERMs, single thread, exiting without cleaning up." doExit(3) - # FIXME: Add code here to clean up /tmp doExit("Abnormal exit") def doExit(error=0): @@ -163,6 +168,12 @@ __cmdParser__.add_option("-u", "--upload", action="store_true", \ __cmdParser__.add_option("--encrypt", action="store_true", \ dest="encrypt", default=False, \ help="encrypt with GPG using Red Hat support's public key") +__cmdParser__.add_option("--batch", action="store_true", \ + dest="batch", default=False, \ + help="do not ask any question (batch mode)") +__cmdParser__.add_option("--no-colors", action="store_true", \ + dest="nocolors", default=False, \ + help="do not use terminal colors for text") __cmdParser__.add_option("-v", "--verbose", action="count", \ dest="verbosity", \ help="increase verbosity") @@ -175,9 +186,21 @@ __cmdParser__.add_option("--no-progressbar", action="store_false", \ __cmdParser__.add_option("--no-multithread", action="store_true", \ dest="nomultithread", \ help="disable multi-threaded gathering mode (slower)", default=False) + +if sys.argv[0].endswith("sysreport"): + print + print "WARNING: sysreport is deprecated, please use sosreport instead." + if not sys.stdin.isatty(): + print + os.execl("/bin/sh", "/bin/sh", "-c", "/usr/sbin/sysreport.legacy") + os.exit(-1) + (__cmdLineOpts__, __cmdLineArgs__)=__cmdParser__.parse_args() def textcolor(text, fg, raw=0): + global __cmdLineOpts__ + if __cmdLineOpts__.nocolors: + return text colors = { "black":"30", "red":"31", "green":"32", "brown":"33", "blue":"34", "purple":"35", "cyan":"36", "lgray":"37", "gray":"1;30", "lred":"1;31", "lgreen":"1;32", "yellow":"1;33", "lblue":"1;34", "pink":"1;35", @@ -200,11 +223,11 @@ class progressBar: self.last_amount_update = time() self.update() - def updateAmount(self, newAmount = 0): + def updateAmount(self, newAmount = 0, finished = False): if newAmount < self.min: newAmount = self.min if newAmount > self.max: - newAmount = self.max + newAmount = self.max - 1 if self.amount != newAmount: self.last_amount_update = time() self.amount = newAmount @@ -219,6 +242,8 @@ class progressBar: percentDone = round(timeElapsed * 100 / self.eta) except: percentDone = 0 + if percentDone >= 100 and not finished: + percentDone = 99 if percentDone > 100: percentDone = 100 ETA = timeElapsed @@ -253,7 +278,7 @@ class progressBar: self.updateAmount(self.amount+toInc) def finished(self): - self.updateAmount(self.max) + self.updateAmount(self.max, finished = True) sys.stdout.write(self.progBar + '\n') sys.stdout.flush() @@ -386,7 +411,10 @@ def sosreport(): logging.addLevelName(logging.VERBOSE2,"verbose2") logging.addLevelName(logging.VERBOSE3,"verbose3") - # FIXME: strip colours if terminal doesn't allow it + # if stdin is not a tty, disable colors and don't ask questions + if not sys.stdin.isatty(): + __cmdLineOpts__.nocolors = True + __cmdLineOpts__.batch = True # log to a file flog = logging.FileHandler(logdir + "/sos.log") @@ -409,7 +437,7 @@ def sosreport(): # set up dict so everyone can share the following commons = {'dstroot': dstroot, 'cmddir': cmddir, 'logdir': logdir, 'rptdir': rptdir, 'soslog': soslog, 'policy': policy, 'verbosity' : __cmdLineOpts__.verbosity, - 'xmlreport' : xmlrep } + 'xmlreport' : xmlrep, 'cmdlineopts':__cmdLineOpts__ } # Make policy aware of the commons policy.setCommons(commons) @@ -588,8 +616,7 @@ def sosreport(): soslog.error(_("no valid plugins were enabled")) doExit(1) - try: - raw_input(_("""This utility will collect some detailed information about the + msg = _("""This utility will collect some detailed information about the hardware and setup of your Red Hat Enterprise Linux system. The information is collected and an archive is packaged under /tmp, which you can send to a support representative. @@ -600,10 +627,13 @@ This process may take a while to complete. No changes will be made to your system. Press ENTER to continue, or CTRL-C to quit. -""")) - except: - print - doExit() +""") + if __cmdLineOpts__.batch: + print msg + else: + try: raw_input(msg) + except: print ; doExit() + del msg # Call the diagnose() method for each plugin tmpcount = 0 @@ -630,18 +660,19 @@ Press ENTER to continue, or CTRL-C to quit. fp.close() print - try: - while True: - yorno = raw_input( _("Are you sure you would like to continue (y/n) ? ") ) - if yorno == _("y") or yorno == _("Y"): - print - break - elif yorno == _("n") or yorno == _("N"): - doExit(0) - del yorno - except KeyboardInterrupt: - print - doExit(0) + if not __cmdLineOpts__.batch: + try: + while True: + yorno = raw_input( _("Are you sure you would like to continue (y/n) ? ") ) + if yorno == _("y") or yorno == _("Y"): + print + break + elif yorno == _("n") or yorno == _("N"): + doExit(0) + del yorno + except KeyboardInterrupt: + print + doExit(0) policy.preWork() @@ -818,7 +849,6 @@ Press ENTER to continue, or CTRL-C to quit. # Close all log files and perform any cleanup logging.shutdown() - if __name__ == '__main__': try: sosreport() |