diff options
-rw-r--r-- | src/Makefile | 34 | ||||
-rw-r--r-- | src/README | 23 | ||||
-rw-r--r-- | src/setup.py | 78 | ||||
-rw-r--r-- | src/sos.spec | 86 | ||||
-rwxr-xr-x | src/sosreport | 347 | ||||
-rw-r--r-- | src/sosreport.1 | 16 |
6 files changed, 431 insertions, 153 deletions
diff --git a/src/Makefile b/src/Makefile index 942e4776..37c384bc 100644 --- a/src/Makefile +++ b/src/Makefile @@ -59,7 +59,7 @@ release: clean @echo " " @echo "The final archive is ./$(NAME)-$(VERSION).tar.bz2." -install:mo +install:mo gpgkey python setup.py install @rm -rf build/lib @@ -67,18 +67,40 @@ version: @echo "The version is $(NAME)-$(VERSION)" clean: - @rm -fv *~ .*~ changenew ChangeLog.old $(NAME)-$(VERSION).tar.bz2 sosreport.1.gz + @rm -fv *~ .*~ changenew ChangeLog.old $(NAME)-$(VERSION).tar.bz2 sosreport.1.gz gpgkeys/rhsupport.* @rm -rfv build/* -rpm: mo - @test -f sos.spec +internal-rpm: gpgkey + @test -f sos-internal.spec + @mkdir -p $(TOPDIR)/SOURCES $(TOPDIR)/SRPMS $(TOPDIR)/RPMS $(TOPDIR)/BUILD $(SRCDIR)/dist + cp gpgkeys/rhsupport.pub gpgkeys/rhsupport.key $(TOPDIR)/SOURCES + +# this builds an RPM from the current working copy + @cd $(TOPDIR)/BUILD ; \ + rm -rf $(NAME)-$(VERSION) ; \ + ln -s $(SRCDIR) $(NAME)-$(VERSION) ; \ + tar --gzip --exclude=.svn --exclude=svn-commit.tmp --exclude=$(NAME)-$(VERSION)/build --exclude=$(NAME)-$(VERSION)/dist \ + --exclude gpgkeys/rhsupport.pub --exclude gpgkeys/rhsupport.key \ + -chSpf $(TOPDIR)/SOURCES/$(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION) ; \ + rm -f $(NAME)-$(VERSION) + + rpmbuild -ba --define="_topdir $(TOPDIR)" sos-internal.spec + @mv $(TOPDIR)/RPMS/noarch/$(NAME)-internal-*.rpm $(TOPDIR)/SRPMS/$(NAME)-internal-*.rpm dist/ + cp gpgkeys/rhsupport.key dist/ + +rpm: mo gpgkey @mkdir -p $(TOPDIR)/SOURCES $(TOPDIR)/SRPMS $(TOPDIR)/RPMS $(TOPDIR)/BUILD $(SRCDIR)/dist + cp gpgkeys/rhsupport.pub $(TOPDIR)/SOURCES + + @test -f sos.spec + # this builds an RPM from the current working copy @cd $(TOPDIR)/BUILD ; \ rm -rf $(NAME)-$(VERSION) ; \ ln -s $(SRCDIR) $(NAME)-$(VERSION) ; \ tar --gzip --exclude=.svn --exclude=svn-commit.tmp --exclude=$(NAME)-$(VERSION)/build --exclude=$(NAME)-$(VERSION)/dist \ + --exclude gpgkeys/rhsupport.pub --exclude gpgkeys/rhsupport.key \ -chSpf $(TOPDIR)/SOURCES/$(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION) ; \ rm -f $(NAME)-$(VERSION) @@ -95,3 +117,7 @@ pot: mo: find locale/*/LC_MESSAGES -name sos.po -exec python tools/msgfmt.py {} \; + +gpgkey: + @test -f gpgkeys/rhsupport.pub && echo "GPG key already exists." || \ + gpg --batch --gen-key gpgkeys/gpg.template @@ -4,8 +4,8 @@ package maintainers, and anyone else to provide plugins that will collect, analyze, and report information that is useful for supporting software packages. -This project is hosted at http://sos.108.redhat.com. For the latest version, -to contribute, and for more information, please visit there. +This project is hosted at http://hosted.fedoraproject.org/projects/sos +For the latest version, to contribute, and for more information, please visit there. To access to the public source code repository for this project run: @@ -20,9 +20,20 @@ Maintainer: Navid Sheikhol-Eslami <navid@redhat.com> -Contributors: +Developers and Contributors: - Steve Conklin <sconklin@redhat.com> - Pierre Amadio <pamadio@redhat.com> + Adam Stokes <astokes@redhat.com> + Cris Lalancette <clalance@redhat.com> + Eugene Teo <eteo@redhat.com> John Berninger <jwb@redhat.com> - Navid Sheikhol-Eslami <navid@redhat.com> + Justin Payne <jpayne@redhat.com> + Pierre Amadio <pamadio@redhat.com> + Qian Shen <qshen@redhat.com> + Steve Conklin <sconklin@redhat.com> + +Thanks to: + + 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 diff --git a/src/setup.py b/src/setup.py index b64c3593..d34ae6c8 100644 --- a/src/setup.py +++ b/src/setup.py @@ -9,6 +9,82 @@ 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 = [ ('/etc', [ 'sos.conf']), ('/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/af/LC_MESSAGES', ['locale/af/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/am/LC_MESSAGES', ['locale/am/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ar/LC_MESSAGES', ['locale/ar/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/as/LC_MESSAGES', ['locale/as/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/be/LC_MESSAGES', ['locale/be/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/bg/LC_MESSAGES', ['locale/bg/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/bn/LC_MESSAGES', ['locale/bn/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/bn_IN/LC_MESSAGES', ['locale/bn_IN/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/bs/LC_MESSAGES', ['locale/bs/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ca/LC_MESSAGES', ['locale/ca/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/cs/LC_MESSAGES', ['locale/cs/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/cy/LC_MESSAGES', ['locale/cy/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/da/LC_MESSAGES', ['locale/da/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/de/LC_MESSAGES', ['locale/de/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/el/LC_MESSAGES', ['locale/el/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/en/LC_MESSAGES', ['locale/en/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/en_GB/LC_MESSAGES', ['locale/en_GB/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/es/LC_MESSAGES', ['locale/es/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/et/LC_MESSAGES', ['locale/et/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/eu_ES/LC_MESSAGES', ['locale/eu_ES/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/fa/LC_MESSAGES', ['locale/fa/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/fi/LC_MESSAGES', ['locale/fi/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/fr/LC_MESSAGES', ['locale/fr/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/gl/LC_MESSAGES', ['locale/gl/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/gu/LC_MESSAGES', ['locale/gu/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/he/LC_MESSAGES', ['locale/he/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/hi/LC_MESSAGES', ['locale/hi/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/hr/LC_MESSAGES', ['locale/hr/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/hu/LC_MESSAGES', ['locale/hu/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/hy/LC_MESSAGES', ['locale/hy/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/id/LC_MESSAGES', ['locale/id/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ilo/LC_MESSAGES', ['locale/ilo/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/is/LC_MESSAGES', ['locale/is/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/it/LC_MESSAGES', ['locale/it/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ja/LC_MESSAGES', ['locale/ja/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ka/LC_MESSAGES', ['locale/ka/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/kn/LC_MESSAGES', ['locale/kn/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ko/LC_MESSAGES', ['locale/ko/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ku/LC_MESSAGES', ['locale/ku/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/lo/LC_MESSAGES', ['locale/lo/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/lt/LC_MESSAGES', ['locale/lt/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/lv/LC_MESSAGES', ['locale/lv/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/mk/LC_MESSAGES', ['locale/mk/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ml/LC_MESSAGES', ['locale/ml/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/mr/LC_MESSAGES', ['locale/mr/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ms/LC_MESSAGES', ['locale/ms/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/my/LC_MESSAGES', ['locale/my/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/nb/LC_MESSAGES', ['locale/nb/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/nl/LC_MESSAGES', ['locale/nl/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/nn/LC_MESSAGES', ['locale/nn/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/no/LC_MESSAGES', ['locale/no/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/nso/LC_MESSAGES', ['locale/nso/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/or/LC_MESSAGES', ['locale/or/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/pa/LC_MESSAGES', ['locale/pa/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/pl/LC_MESSAGES', ['locale/pl/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/pt/LC_MESSAGES', ['locale/pt/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/pt_BR/LC_MESSAGES', ['locale/pt_BR/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ro/LC_MESSAGES', ['locale/ro/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ru/LC_MESSAGES', ['locale/ru/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/si/LC_MESSAGES', ['locale/si/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sk/LC_MESSAGES', ['locale/sk/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sl/LC_MESSAGES', ['locale/sl/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sq/LC_MESSAGES', ['locale/sq/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sr/LC_MESSAGES', ['locale/sr/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sr@latin/LC_MESSAGES', ['locale/sr@latin/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/sv/LC_MESSAGES', ['locale/sv/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ta/LC_MESSAGES', ['locale/ta/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/te/LC_MESSAGES', ['locale/te/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/th/LC_MESSAGES', ['locale/th/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/tr/LC_MESSAGES', ['locale/tr/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/uk/LC_MESSAGES', ['locale/uk/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/ur/LC_MESSAGES', ['locale/ur/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/vi/LC_MESSAGES', ['locale/vi/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/zh_CN/LC_MESSAGES', ['locale/zh_CN/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/zh_TW/LC_MESSAGES', ['locale/zh_TW/LC_MESSAGES/sos.mo']), + ('/usr/share/locale/zu/LC_MESSAGES', ['locale/zu/LC_MESSAGES/sos.mo']), ] ) diff --git a/src/sos.spec b/src/sos.spec index 0a0d8add..3b3f8534 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 9 +%define version 1.8 +%define release 0pre2 %define _localedir %_datadir/locale @@ -10,19 +10,23 @@ Summary: A set of tools to gather troubleshooting information from a system Name: %{name} Version: %{version} Release: %{release}%{?dist} +Group: Application/Tools # The source for this package was pulled from upstream's svn. Use the # following commands to generate the tarball: # svn --username guest export https://sos.108.redhat.com/svn/sos/tags/r1-7 sos-1.7 # tar -czvf sos-1.7.tar.gz sos-1.7 Source0: %{name}-%{version}.tar.gz +Source1: rhsupport.pub License: GPL -Group: Development/Libraries BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot BuildArch: noarch -Url: http://sos.108.redhat.com/ +Url: https://hosted.fedoraproject.org/projects/sos BuildRequires: python-devel Requires: libxml2-python +%if 0%{?rhel} +Provides: sysreport = 1.4.3-13 Obsoletes: sysreport +%endif %description Sos is a set of tools that gathers information about system @@ -38,8 +42,18 @@ python setup.py build %install rm -rf ${RPM_BUILD_ROOT} +install -D -m644 %{SOURCE1} ${RPM_BUILD_ROOT}/usr/share/sos/rhsupport.pub python setup.py install --optimize 1 --root=$RPM_BUILD_ROOT + +%if 0%{?rhel} ln -s /usr/sbin/sosreport $RPM_BUILD_ROOT/usr/sbin/sysreport +%endif +%if ! 0%{?rhel} +rm -f $RPM_BUILD_ROOT/usr/sbin/sysreport.legacy +rm -f $RPM_BUILD_ROOT/usr/share/sysreport/functions +rm -f $RPM_BUILD_ROOT/usr/share/sysreport/sysreport-fdisk +rm -f $RPM_BUILD_ROOT/usr/share/sysreport/text.xsl +%endif %clean rm -rf ${RPM_BUILD_ROOT} @@ -47,20 +61,76 @@ rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root,-) %{_sbindir}/sosreport +/usr/share/sos/rhsupport.pub /usr/bin/rh-upload-core +%if 0%{?rhel} /usr/sbin/sysreport /usr/sbin/sysreport.legacy /usr/share/sysreport +%endif %{python_sitelib}/sos/ %{_mandir}/man1/sosreport.1* %{_localedir}/*/LC_MESSAGES/sos.mo %doc README README.rh-upload-core TODO LICENSE ChangeLog +%config /etc/sos.conf %changelog -* Thu Aug 16 2007 Navid Sheikhol-Eslami <navid at redhat dot com> - 1.7-9 -- corrected a problem causing sometimes exceptions not to be catched when triggered within a thread - -* Mon Aug 13 2007 Navid Sheikhol-Eslami <navid at redhat dot com> - 1.7-8 +* Wed Nov 21 2007 Navid Sheikhol-Eslami <navid at redhat dot com> - 1.8-0 +- Resolves: bz368261 sosGetCommandOutput() does not block on hung processes +- Resolves: bz361861 work-around missing traceback.format_exc() in RHEL4 +- Resolves: bz394781 device-mapper: use /sbin/lvm_dump to collect dm related info +- Resolves: bz386691 unattended --batch option +- Resolves: bz371251 sos could hang when accessing /sys/hypervisor/uuid +- selinux: always collect sestatus +- added many languages +- added --debug option which causes exceptions not to be trapped +- updated to sysreport-1.4.3-13.el5 +- ftp upload to dropbox with --upload +- cluster: major rewrite to support different versions of RHEL +- cluster: check rg_test for errors +- minor changes in various plug-ins (yum, networking, process, kernel) +- fixed some exceptions in threads which were not properly trapped +- veritas: don't run rpm -qa every time +- using rpm's python bindings instead of external binary +- corrected autofs and ldap plugin that were failing when debug option was not found in config file. +- implemented built-in checkdebug() that uses self.files and self.packages to make the decision +- missing binaries are properly detected now. +- better doExitCode handling +- fixed problem with rpm module intercepting SIGINT +- error when user specifies an invalid plugin or plugin option +- named: fixed indentation +- replaced isOptionEnabled() with getOption() +- tune2fs and fdisk were not always run against the correct devices/mountpoint +- added gpg key to package +- updated README with new svn repo and contributors +- updated manpage +- better signal handling +- caching of rpm -q outputs +- report filename includes rhnUsername if available +- report encryption via gpg and support pubkey +- autofs: removed redundant files +- filesys: better handling of removable devices +- added sosReadFile() returns a file's contents +- return after looping inside a directory +- collect udevinfo for each block device +- simply collect output of fdisk -l in one go +- handle sysreport invocation properly (warn if shell is interactive, otherwise spawn sysreport.legacy) +- progress bar don't show 100% until finished() is called +- Resolves: bz238778 added lspci -t +- now runs on RHEL3 as well (python 2.2) +- replaced commonPrefix() with faster code +- filesys: one fdisk -l for all +- selinux: collect fixfilex check output +- devicemapper: collect udevinfo for all block devices +- cluster: validate node names according to RFC 2181 +- systemtap: cleaned up and added checkenabled() method +- added kdump plugin +- added collection of /etc/inittab +- Resolves: bz332151 apply regex to case number in sysreport for RHEL4 +- Resolves: bz332211 apply regex to case number in sysreport for RHEL5 +- Resolves: bz400111 sos incorrectly reports cluster data in SMP machine + +* Wed Aug 13 2007 Navid Sheikhol-Eslami <navid at redhat dot com> - 1.7-8 - added README.rh-upload-core * Mon Aug 13 2007 Navid Sheikhol-Eslami <navid at redhat dot com> - 1.7-7 diff --git a/src/sosreport b/src/sosreport index 888e0b54..516cda22 100755 --- a/src/sosreport +++ b/src/sosreport @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ Gather information about a system and report it using plugins supplied for application-specific information @@ -28,19 +28,26 @@ supplied for application-specific information import sys import os from optparse import OptionParser, Option +import ConfigParser import sos.policyredhat from sos.helpers import * from snack import * from threading import Thread, activeCount import signal -import logging from stat import * from time import strftime, localtime, time from pwd import getpwuid import gettext from threading import Semaphore -__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 @@ -50,10 +57,15 @@ def exittermhandler(signum, frame): def doExitCode(): from threading import enumerate - global __breakHits__ + global __breakHits__, loadedplugins, dstroot + __breakHits__ += 1 if ( ( activeCount() > 1 ) and ( __breakHits__ == 1 ) ): print "SIGTERM received, multiple threads detected, waiting for all threads to exit" + + for plugname, plug in loadedplugins: + plug.exit_please() + for thread in enumerate(): if thread.getName() == "MainThread": continue @@ -62,20 +74,41 @@ def doExitCode(): try: thread.join() except KeyboardInterrupt: - pass + doExitCode() else: print "All threads ended, cleaning up." - if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ): - print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately" + doExit(1) + + if ( ( activeCount() > 1 ) and ( __breakHits__ > 1 ) ): + print "Multiple SIGTERMs, multiple threads, attempting to signal threads to die immediately." ## FIXME: Add thread-kill code (see FIXME below) -# os.kill(os.getpid(), signal.SIGKILL) - print "Threads dead, cleaning up." - if ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ): + return + elif ( ( activeCount() > 1 ) and ( __breakHits__ > 2 ) ): + print "Multiple SIGTERMs, multiple threads, process suicides." + os.kill(os.getpid(), signal.SIGKILL) + elif ( ( activeCount() == 1 ) and ( __breakHits__ > 2 ) ): print "Multiple SIGTERMs, single thread, exiting without cleaning up." - sys.exit(3) - - # FIXME: Add code here to clean up /tmp - sys.exit("Abnormal exit") + doExit(3) + + doExit("Abnormal exit") + +def doExit(error=0): + global policy + policy.cleanDstroot() + sys.exit(error) + +def doException(type, value, tb): + if hasattr(sys, 'ps1') or not sys.stderr.isatty(): + # we are in interactive mode or we don't have a tty-like + # device, so we call the default hook + sys.__excepthook__(type, value, tb) + else: + import traceback, pdb + # we are NOT in interactive mode, print the exception... + traceback.print_exception(type, value, tb) + print + # ...then start the debugger in post-mortem mode. + pdb.pm() # Handle any sort of exit signal cleanly # Currently, we intercept only sig 15 (TERM) @@ -84,9 +117,6 @@ signal.signal(signal.SIGTERM, exittermhandler) ## FIXME: Need to figure out how to IPC with child threads in case of ## multiple SIGTERMs. -# for debugging -__raisePlugins__ = 0 - class OptionParser_extended(OptionParser): def print_help(self): OptionParser.print_help(self) @@ -95,10 +125,10 @@ class OptionParser_extended(OptionParser): print print " enable cluster plugin only and collect dlm lockdumps:" print " # sosreport -o cluster -k cluster.lockdump" - print + print print " disable memory and samba plugins, turn off rpm -Va collection:" print " # sosreport -n memory,samba -k rpm.rpmva=off" - print + print class SosOption (Option): """Allow to specify comma delimited list of plugins""" @@ -133,43 +163,55 @@ __cmdParser__.add_option("-k", action="extend", \ __cmdParser__.add_option("-a", "--alloptions", action="store_true", \ dest="usealloptions", default=False, \ help="enable all options for loaded plugins") +__cmdParser__.add_option("-u", "--upload", action="store_true", \ + dest="upload", default=False, \ + help="upload the report to Red Hat support") +#__cmdParser__.add_option("--encrypt", action="store_true", \ +# dest="encrypt", default=False, \ +# help="encrypt with GPG using Red Hat support's public key") +__cmdParser__.add_option("--batch", action="store_true", \ + dest="batch", default=False, \ + help="do not ask any question (batch mode)") +__cmdParser__.add_option("--no-colors", action="store_true", \ + dest="nocolors", default=False, \ + help="do not use terminal colors for text") __cmdParser__.add_option("-v", "--verbose", action="count", \ dest="verbosity", \ help="increase verbosity") +__cmdParser__.add_option("--debug", action="count", \ + dest="debug", \ + help="enabling debugging") __cmdParser__.add_option("--no-progressbar", action="store_false", \ dest="progressbar", default=True, \ help="do not display a progress bar.") __cmdParser__.add_option("--no-multithread", action="store_true", \ dest="nomultithread", \ help="disable multi-threaded gathering mode (slower)", default=False) -__cmdParser__.add_option("--name", action="store", \ - dest="name",type="string", \ - help="first initial and last name.", default="") -__cmdParser__.add_option("--ticket-number", action="store", \ - dest="ticketnumber", type="string", \ - help="ticket number.", default="") if sys.argv[0].endswith("sysreport"): - try: - ppid = os.getppid() - fp = open("/proc/%d/cmdline" % ppid, "r") - cmd = fp.read() - fp.close() - except: - cmd = "" - if not sys.stdin.isatty() or cmd.find("bash") < 0: - os.execl("/bin/sh", "/bin/sh", "-c", "/usr/sbin/sysreport.legacy") - os.exit(-1) 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") + sys.exit(-1) + +if "-norpm" in sys.argv: + print + print """WARNING: sysreport's "-norpm" option is deprecated, please use "-k rpm.rpmva=off" instead.""" + print + sys.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", - "lcyan":"1;36", "white":"1;37" } + "purple":"35", "cyan":"36", "lgray":"37", "gray":"1;30", "lred":"1;31", + "lgreen":"1;32", "yellow":"1;33", "lblue":"1;34", "pink":"1;35", + "lcyan":"1;36", "white":"1;37" } opencol = "\033[" closecol = "m" clear = opencol + "0" + closecol @@ -188,11 +230,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 @@ -207,6 +249,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 @@ -241,7 +285,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() @@ -315,6 +359,14 @@ class XmlReport: outfn.write(self.doc.serialize(None,1)) outfn.close() +# if debugging is enabled, allow plugins to raise exceptions + +if __cmdLineOpts__.debug: + sys.excepthook = doException + __raisePlugins__ = 1 +else: + __raisePlugins__ = 0 + def sosreport(): # pylint: disable-msg = R0912 # pylint: disable-msg = R0914 @@ -322,6 +374,13 @@ def sosreport(): """ This is the top-level function that gathers and processes all sosreport information """ + + global loadedplugins, dstroot, policy + + config = ConfigParser.ConfigParser() + try: config.readfp(open('/etc/sos.conf')) + except IOError: pass + loadedplugins = [] skippedplugins = [] alloptions = [] @@ -336,8 +395,12 @@ def sosreport(): pluginpath = path + "/sos/plugins" # Set up common info and create destinations + + dstroot = policy.getDstroot() + if not dstroot: + print _("Could not create temporary directory.") + doExit() - dstroot = sosFindTmpDir() cmddir = os.path.join(dstroot, "sos_commands") logdir = os.path.join(dstroot, "sos_logs") rptdir = os.path.join(dstroot, "sos_reports") @@ -346,7 +409,7 @@ def sosreport(): os.mkdir(rptdir, 0755) # initialize i18n language localization - gettext.install('sos', '/usr/share/locale', unicode=False) + gettext.install('sos', '/usr/share/locale', unicode=False) # initialize logging soslog = logging.getLogger('sos') @@ -354,12 +417,15 @@ def sosreport(): logging.VERBOSE = logging.INFO - 1 logging.VERBOSE2 = logging.INFO - 2 - logging.VERBOSE3 = logging.INFO - 3 + logging.VERBOSE3 = logging.INFO - 3 logging.addLevelName(logging.VERBOSE, "verbose") logging.addLevelName(logging.VERBOSE2,"verbose2") logging.addLevelName(logging.VERBOSE3,"verbose3") - # 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") @@ -382,7 +448,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__, 'config':config } # Make policy aware of the commons policy.setCommons(commons) @@ -390,12 +456,11 @@ def sosreport(): print soslog.info ( _("sosreport (version %s)") % __version__) print - + # 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: @@ -403,36 +468,33 @@ def sosreport(): if not plug[-3:] == '.py' or plugbase == "__init__": continue try: - #print "importing plugin: %s" % plugbase - try: - if policy.validatePlugin(pluginpath + plug): - pluginClass = importPlugin("sos.plugins." + plugbase, plugbase) - else: - soslog.warning(_("plugin %s does not validate, skipping") % plug) - skippedplugins.append((plugbase, pluginClass(plugbase, commons))) - continue - if plugbase in __cmdLineOpts__.noplugins: - soslog.log(logging.VERBOSE, _("plugin %s skipped (--skip-plugins)") % plugbase) - skippedplugins.append((plugbase, pluginClass(plugbase, commons))) - continue - if not pluginClass(plugbase, commons).checkenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins: - soslog.log(logging.VERBOSE, _("plugin %s is inactive (use -e or -o to enable).") % plug) - skippedplugins.append((plugbase, pluginClass(plugbase, commons))) - continue - if not pluginClass(plugbase, commons).defaultenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins: - soslog.log(logging.VERBOSE, "plugin %s not loaded by default (use -e or -o to enable)." % plug) - skippedplugins.append((plugbase, pluginClass(plugbase, commons))) - continue - if __cmdLineOpts__.onlyplugins and not plugbase in __cmdLineOpts__.onlyplugins: - soslog.log(logging.VERBOSE, _("plugin %s not specified in --only-plugins list") % plug) - skippedplugins.append((plugbase, pluginClass(plugbase, commons))) - continue - loadedplugins.append((plugbase, pluginClass(plugbase, commons))) - except: - soslog.warning(_("plugin %s does not install, skipping") % plug) - raise + if policy.validatePlugin(pluginpath + plug): + pluginClass = importPlugin("sos.plugins." + plugbase, plugbase) + else: + soslog.warning(_("plugin %s does not validate, skipping") % plug) + skippedplugins.append((plugbase, pluginClass(plugbase, commons))) + continue + # plug-in is valid, let's decide whether run it or not + plugin_names.append(plugbase) + if plugbase in __cmdLineOpts__.noplugins: + soslog.log(logging.VERBOSE, _("plugin %s skipped (--skip-plugins)") % plugbase) + skippedplugins.append((plugbase, pluginClass(plugbase, commons))) + continue + if not pluginClass(plugbase, commons).checkenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins: + soslog.log(logging.VERBOSE, _("plugin %s is inactive (use -e or -o to enable).") % plug) + skippedplugins.append((plugbase, pluginClass(plugbase, commons))) + continue + if not pluginClass(plugbase, commons).defaultenabled() and not plugbase in __cmdLineOpts__.enableplugins and not plugbase in __cmdLineOpts__.onlyplugins: + soslog.log(logging.VERBOSE, "plugin %s not loaded by default (use -e or -o to enable)." % plug) + skippedplugins.append((plugbase, pluginClass(plugbase, commons))) + continue + if __cmdLineOpts__.onlyplugins and not plugbase in __cmdLineOpts__.onlyplugins: + soslog.log(logging.VERBOSE, _("plugin %s not specified in --only-plugins list") % plug) + skippedplugins.append((plugbase, pluginClass(plugbase, commons))) + continue + loadedplugins.append((plugbase, pluginClass(plugbase, commons))) except: - soslog.warning(_("could not load plugin %s") % plug) + soslog.warning(_("plugin %s does not install, skipping") % plug) if __raisePlugins__: raise @@ -444,6 +506,14 @@ def sosreport(): if type(parms["enabled"])==bool: parms["enabled"] = True + # read plugin tunables from configuration file + if config.has_section("tunables"): + if not __cmdLineOpts__.plugopts: + __cmdLineOpts__.plugopts = [] + + for opt, val in config.items("tunables"): + __cmdLineOpts__.plugopts.append(opt + "=" + val) + if __cmdLineOpts__.plugopts: opts = {} for opt in __cmdLineOpts__.plugopts: @@ -453,7 +523,7 @@ def sosreport(): except: val=True else: - if val == "off" or val == "disable" or val == "disabled": + if val.lower() in ["off", "disable", "disabled", "false"]: val = False else: # try to convert string "val" to int() @@ -461,7 +531,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] = [] @@ -470,10 +544,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() @@ -487,7 +577,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): @@ -530,26 +620,22 @@ 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) - isUnattended = False - if len(__cmdLineOpts__.name) > 0 and len(__cmdLineOpts__.ticketnumber) > 0: isUnattended = True - if not isUnattended: - try: - raw_input(_("""This utility will collect some detailed information about the + 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. @@ -559,11 +645,14 @@ and it will be considered confidential information. 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 KeyboardInterrupt: - print - sys.exit(0) +""") + if __cmdLineOpts__.batch: + print msg + else: + msg += _("""Press ENTER to continue, or CTRL-C to quit.\n""") + try: raw_input(msg) + except: print ; doExit() + del msg # Call the diagnose() method for each plugin tmpcount = 0 @@ -590,37 +679,32 @@ Press ENTER to continue, or CTRL-C to quit. fp.close() print - try: - while True: - if not isUnattended: + if not __cmdLineOpts__.batch: + try: + while True: yorno = raw_input( _("Are you sure you would like to continue (y/n) ? ") ) - else: - yorno = _("Y") - - if yorno == _("y") or yorno == _("Y"): - print - break - elif yorno == _("n") or yorno == _("N"): - sys.exit(0) - del yorno - except KeyboardInterrupt: - print - sys.exit(0) - - if isUnattended: - policy.preWork(__cmdLineOpts__.name, __cmdLineOpts__.ticketnumber) - else: - policy.preWork() - + 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() # Call the setup() method for each plugin for plugname, plug in loadedplugins: soslog.log(logging.VERBOSE2, "Preloading files and commands to be gathered by plugin %s" % plugname) try: - plug.setup() + plug.setup() + except KeyboardInterrupt: + raise except: - if __raisePlugins__: - raise + if __raisePlugins__: + raise # Setup the progress bar if __cmdLineOpts__.progressbar: @@ -639,15 +723,17 @@ Press ENTER to continue, or CTRL-C to quit. # Call the collect method for each plugin plugrunning = Semaphore(2) for plugname, plug in loadedplugins: - soslog.log(logging.VERBOSE, "executing plugin %s" % plugname) + soslog.log(logging.VERBOSE, "requesting plugin %s" % plugname) try: if not __cmdLineOpts__.nomultithread: plug.copyStuff(threaded = True, semaphore = plugrunning) else: - plug.copyStuff() + plug.copyStuff() if __cmdLineOpts__.progressbar: pbar.incAmount(plug.eta_weight) pbar.update() + except KeyboardInterrupt: + raise except: if __raisePlugins__: raise @@ -755,8 +841,6 @@ Press ENTER to continue, or CTRL-C to quit. rfd.close() - # Collect any needed user information (name, etc) - # Call the postproc method for each plugin for plugname, plug in loadedplugins: try: @@ -767,14 +851,23 @@ 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 not __cmdLineOpts__.upload: + policy.displayResults() + else: + policy.uploadResults() # Close all log files and perform any cleanup logging.shutdown() - - + if __name__ == '__main__': try: sosreport() 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 |