aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sos.spec334
-rw-r--r--sos/archive.py301
-rw-r--r--sos/plugins/__init__.py41
-rw-r--r--sos/plugins/cloudforms.py4
-rw-r--r--sos/plugins/logs.py4
-rw-r--r--sos/plugins/lvm2.py4
-rw-r--r--sos/plugins/rhui.py2
-rw-r--r--sos/plugins/sanlock.py2
-rw-r--r--sos/plugins/satellite.py3
-rw-r--r--sos/plugins/system.py2
-rw-r--r--sos/policies/__init__.py4
-rw-r--r--sos/policies/redhat.py5
-rw-r--r--sos/sosreport.py39
13 files changed, 544 insertions, 201 deletions
diff --git a/sos.spec b/sos.spec
index 9baffb3b..96ea290b 100644
--- a/sos.spec
+++ b/sos.spec
@@ -2,10 +2,10 @@
Summary: A set of tools to gather troubleshooting information from a system
Name: sos
-Version: 2.3
+Version: 3.0
Release: 1%{?dist}
Group: Applications/System
-Source0: https://fedorahosted.org/releases/s/o/sos/%{name}-%{version}.tar.gz
+Source0: https://github.com/sosreport/sosreport
License: GPLv2+
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
BuildArch: noarch
@@ -13,6 +13,7 @@ Url: http://fedorahosted.org/sos
BuildRequires: python-devel
BuildRequires: gettext
Requires: libxml2-python
+Requires: rpm-python
Requires: tar
Requires: bzip2
Requires: xz
@@ -44,32 +45,313 @@ rm -rf ${RPM_BUILD_ROOT}
%{python_sitelib}/*
%{_mandir}/man1/*
%{_mandir}/man5/*
-%doc README.md LICENSE
+%doc AUTHORS README.md LICENSE
%config(noreplace) %{_sysconfdir}/sos.conf
%changelog
-* Wed Jul 21 2010 Adam Stokes <ajs at redhat dot com> = 2.3-1
-- Auto update version during build
-- Capture plugin tracebacks properly into a separate file
-
-* Thu May 20 2010 Adam Stokes <ajs at redhat dot com> = 2.2-0
-- Corosync plugin added
-- Cluster plugin updated
-
-* Thu Apr 22 2010 Adam Stokes <ajs at redhat dot com> = 2.1-0
-- Include --help in manpage
-- If tmp-dir is defined then put compressed archive there
-
-* Sun Apr 11 2010 Adam Stokes <ajs at redhat dot com> = 2.0-0
-- Bump release to 2
-- Fix problem where sos generates error on newline in hostname
-- Remove references to sysreport*
-
-* Tue Mar 30 2010 Adam Stokes <ajs at redhat dot com> = 1.9-5
-- Remove references to rh-upload
-
-* Fri Mar 26 2010 Adam Stokes <ajs at redhat dot com> = 1.9-4
+* Mon Jun 10 2013 Bryn M. Reeves <bmr@redhat.com> = 3.0-1
+- New upstream release
+
+* Thu May 23 2013 Bryn M. Reeves <bmr@redhat.com> = 2.2-39
+- Always invoke tar with '-f-' option
+ Resolves: bz966602
+
+* Mon Jan 21 2013 Bryn M. Reeves <bmr@redhat.com> = 2.2-38
+- Fix interactive mode regression when --ticket unspecified
+ Resolves: bz822113
+
+* Fri Jan 18 2013 Bryn M. Reeves <bmr@redhat.com> = 2.2-37
+- Fix propagation of --ticket parameter in interactive mode
+ Resolves: bz822113
+
+* Thu Jan 17 2013 Bryn M. Reeves <bmr@redhat.com> = 2.2-36
+- Revert OpenStack patch
+ Resolves: bz840057
+
+* Wed Jan 9 2013 Bryn M. Reeves <bmr@redhat.com> = 2.2-35
+- Report --name and --ticket values as defaults
+ Resolves: bz822113
+- Fix device-mapper command execution logging
+ Resolves: bz824378
+- Fix data collection and rename PostreSQL module to pgsql
+ Resolves: bz852049
+
+* Fri Oct 19 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-34
+- Add support for content delivery hosts to RHUI module
+ Resolves: bz821323
+
+* Thu Oct 18 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-33
+- Add Red Hat Update Infrastructure module
+ Resolves: bz821323
+- Collect /proc/iomem in hardware module
+ Resolves: bz840975
+- Collect subscription-manager output in general module
+ Resolves: bz825968
+- Collect rhsm log files in general module
+ Resolves: bz826312
+- Fix exception in gluster module on non-gluster systems
+ Resolves: bz849546
+- Fix exception in psql module when dbname is not given
+ Resolves: bz852049
+
+* Wed Oct 17 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-32
+- Collect /proc/pagetypeinfo in memory module
+ Resolves: bz809727
+- Strip trailing newline from command output
+ Resolves: bz850433
+- Add sanlock module
+ Resolves: bz850779
+- Do not collect archived accounting files in psacct module
+ Resolves: bz850542
+- Call spacewalk-debug from rhn module to collect satellite data
+ Resolves: bz859142
+
+* Mon Oct 15 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-31
+- Avoid calling volume status when collecting gluster statedumps
+ Resolves: bz849546
+- Use a default report name if --name is empty
+ Resolves: bz822113
+- Quote tilde characters passed to shell in RPM module
+ Resolves: bz821005
+- Collect KDC and named configuration in ipa module
+ Resolves: bz825149
+- Sanitize hostname characters before using as report path
+ Resolves: bz822174
+- Collect /etc/multipath in device-mapper module
+ Resolves: bz817093
+- New plug-in for PostgreSQL
+ Resolves: bz852049
+- Add OpenStack module
+ Resolves: bz840057
+- Avoid deprecated sysctls in /proc/sys/net
+ Resolves: bz834594
+- Fix error logging when calling external programs
+ Resolves: bz824378
+- Use ip instead of ifconfig to generate network interface lists
+ Resolves: bz833170
+
+* Wed May 23 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-29
+- Collect the swift configuration directory in gluster module
+ Resolves: bz822442
+- Update IPA module and related plug-ins
+ Resolves: bz812395
+
+* Fri May 18 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-28
+- Collect mcelog files in the hardware module
+ Resolves: bz810702
+
+* Wed May 02 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-27
+- Add nfs statedump collection to gluster module
+ Resolves: bz752549
+
+* Tue May 01 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-26
+- Use wildcard to match possible libvirt log paths
+ Resolves: bz814474
+
+* Mon Apr 23 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-25
+- Add forbidden paths for new location of gluster private keys
+ Resolves: bz752549
+
+* Fri Mar 9 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-24
+- Fix katello and aeolus command string syntax
+ Resolves: bz752666
+- Remove stray hunk from gluster module patch
+ Resolves: bz784061
+
+* Thu Mar 8 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-22
+- Correct aeolus debug invocation in CloudForms module
+ Resolves: bz752666
+- Update gluster module for gluster-3.3
+ Resolves: bz784061
+- Add additional command output to gluster module
+ Resolves: bz768641
+- Add support for collecting gluster configuration and logs
+ Resolves: bz752549
+
+* Wed Mar 7 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-19
+- Collect additional diagnostic information for realtime systems
+ Resolves: bz789096
+- Improve sanitization of RHN user and case number in report name
+ Resolves: bz771393
+- Fix verbose output and debug logging
+ Resolves: bz782339
+- Add basic support for CloudForms data collection
+ Resolves: bz752666
+- Add support for Subscription Asset Manager diagnostics
+ Resolves: bz752670
+
+* Tue Mar 6 2012 Bryn M. Reeves <bmr@redhat.com> = 2.2-18
+- Collect fence_virt.conf in cluster module
+ Resolves: bz760995
+- Fix collection of /proc/net directory tree
+ Resolves: bz730641
+- Gather output of cpufreq-info when present
+ Resolves: bz760424
+- Fix brctl showstp output when bridges contain multiple interfaces
+ Resolves: bz751273
+- Add /etc/modprobe.d to kernel module
+ Resolves: bz749919
+- Ensure relative symlink targets are correctly handled when copying
+ Resolves: bz782589
+- Fix satellite and proxy package detection in rhn plugin
+ Resolves: bz749262
+- Collect stderr output from external commands
+ Resolves: bz739080
+- Collect /proc/cgroups in the cgroups module
+ Resolve: bz784874
+- Collect /proc/irq in the kernel module
+ Resolves: bz784862
+- Fix installed-rpms formatting for long package names
+ Resolves: bz767827
+- Add symbolic links for truncated log files
+ Resolves: bz766583
+- Collect non-standard syslog and rsyslog log files
+ Resolves: bz771501
+- Use correct paths for tomcat6 in RHN module
+ Resolves: bz749279
+- Obscure root password if present in anacond-ks.cfg
+ Resolves: bz790402
+- Do not accept embedded forward slashes in RHN usernames
+ Resolves: bz771393
+- Add new sunrpc module to collect rpcinfo for gluster systems
+ Resolves: bz784061
+
+* Tue Nov 1 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-17
+- Do not collect subscription manager keys in general plugin
+ Resolves: bz750607
+
+* Fri Sep 23 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-16
+- Fix execution of RHN hardware.py from hardware plugin
+ Resolves: bz736718
+- Fix hardware plugin to support new lsusb path
+ Resolves: bz691477
+
+* Fri Sep 09 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-15
+- Fix brctl collection when a bridge contains no interfaces
+ Resolves: bz697899
+- Fix up2dateclient path in hardware plugin
+ Resolves: bz736718
+
+* Mon Aug 15 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-14
+- Collect brctl show and showstp output
+ Resolves: bz697899
+- Collect nslcd.conf in ldap plugin
+ Resolves: bz682124
+
+* Sun Aug 14 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-11
+- Truncate files that exceed specified size limit
+ Resolves: bz683219
+- Add support for collecting Red Hat Subscrition Manager configuration
+ Resolves: bz714293
+- Collect /etc/init on systems using upstart
+ Resolves: bz694813
+- Don't strip whitespace from output of external programs
+ Resolves: bz713449
+- Collect ipv6 neighbour table in network module
+ Resolves: bz721163
+- Collect basic cgroups configuration data
+ Resolves: bz729455
+
+* Sat Aug 13 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-10
+- Fix collection of data from LVM2 reporting tools in devicemapper plugin
+ Resolves: bz704383
+- Add /proc/vmmemctl collection to vmware plugin
+ Resolves: bz709491
+
+* Fri Aug 12 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-9
+- Collect yum repository list by default
+ Resolves: bz600813
+- Add basic Infiniband plugin
+ Resolves: bz673244
+- Add plugin for scsi-target-utils iSCSI target
+ Resolves: bz677124
+- Fix autofs plugin LC_ALL usage
+ Resolves: bz683404
+- Fix collection of lsusb and add collection of -t and -v outputs
+ Resolves: bz691477
+- Extend data collection by qpidd plugin
+ Resolves: bz726360
+- Add ethtool pause, coalesce and ring (-a, -c, -g) options to network plugin
+ Resolves: bz726427
+
+* Thu Apr 07 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-8
+- Use sha256 for report digest when operating in FIPS mode
+ Resolves: bz689387
+
+* Tue Apr 05 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-7
+- Fix parted and dumpe2fs output on s390
+ Resolves: bz622784
+
+* Fri Feb 25 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-6
+- Fix collection of chkconfig output in startup.py
+ Resolves: bz659467
+- Collect /etc/dhcp in dhcp.py plugin
+ Resolves: bz676522
+- Collect dmsetup ls --tree output in devicemapper.py
+ Resolves: bz675559
+- Collect lsblk output in filesys.py
+ Resolves: bz679433
+
+* Thu Feb 24 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-4
+- Fix collection of logs and config files in sssd.py
+ Resolves: bz624162
+- Add support for collecting entitlement certificates in rhn.py
+ Resolves: bz678665
+
+* Thu Feb 03 2011 Bryn M. Reeves <bmr@redhat.com> = 2.2-3
+- Fix cluster plugin dlm lockdump for el6
+ Resolves: bz622407
+- Add sssd plugin to collect configuration and logs
+ Resolves: bz624162
+- Collect /etc/anacrontab in system plugin
+ Resolves: bz622527
+- Correct handling of redhat-release for el6
+ Resolves: bz622528
+
+* Thu Jul 29 2010 Adam Stokes <ajs at redhat dot com> = 2.2-2
+- Resolves: bz582259
+- Resolves: bz585942
+- Resolves: bz584253
+- Resolves: bz581817
+
+* Thu Jun 10 2010 Adam Stokes <ajs at redhat dot com> = 2.2-0
+- Resolves: bz581921
+- Resolves: bz584253
+- Resolves: bz562651
+- Resolves: bz566170
+- Resolves: bz586450
+- Resolves: bz588223
+- Resolves: bz559737
+- Resolves: bz586405
+- Resolves: bz598978
+- Resolves: bz584763
+
+* Wed Apr 28 2010 Adam Stokes <ajs at redhat dot com> = 2.1-0
+- Resolves: bz585923
+- Resolves: bz585942
+- Resolves: bz586409
+- Resolves: bz586389
+- Resolves: bz548096
+- Resolves: bz557828
+- Resolves: bz563637
+- Resolves: bz584253
+- Resolves: bz462823
+- Resolves: bz528881
+- Resolves: bz566170
+- Resolves: bz578787
+- Resolves: bz581817
+- Resolves: bz581826
+- Resolves: bz584695
+- Resolves: bz568637
+- Resolves: bz584767
+- Resolves: bz586370
+
+* Mon Apr 12 2010 Adam Stokes <ajs at redhat dot com> = 2.0-0
+- Resolves: bz580015
+
+* Tue Mar 30 2010 Adam Stokes <ajs at redhat dot com> = 1.9-3
- fix setup.py to autocompile translations and man pages
+- rebase 1.9
* Fri Mar 19 2010 Adam Stokes <ajs at redhat dot com> = 1.9-2
- updated translations
@@ -126,10 +408,6 @@ rm -rf ${RPM_BUILD_ROOT}
* Wed Feb 25 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.8-10
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
-* Wed Jan 21 2009 Adam Stokes <ajs at redhat dot com> - 1.8-9
-- Resolves: bz436053 /usr/share/sos is not owned by any package
-- Resolves: bz434626 Wrong directory structure for translations
-
* Mon Dec 29 2008 Adam Stokes <ajs at redhat dot com> - 1.8-5
- removed source defines as python manifest handles this
diff --git a/sos/archive.py b/sos/archive.py
index f1b0b057..42916606 100644
--- a/sos/archive.py
+++ b/sos/archive.py
@@ -22,6 +22,7 @@ import tarfile
import zipfile
import shutil
import logging
+import shutil
import shlex
import re
# required for compression callout (FIXME: move to policy?)
@@ -39,51 +40,143 @@ except ImportError:
class Archive(object):
+ log = logging.getLogger("sos")
+
_name = "unset"
- def prepend(self, src):
- if src:
- name = os.path.split(self._name)[-1]
- renamed = os.path.join(name, src.lstrip(os.sep))
- return renamed
+ # this is our contract to clients of the Archive class hierarchy.
+ # All sub-classes need to implement these methods (or inherit concrete
+ # implementations from a parent class.
+ def add_file(self, src, dest=None):
+ raise NotImplementedError
+
+ def add_string(self, content, dest):
+ raise NotImplementedError
+
+ def add_link(self, source, link_name):
+ raise NotImplementedError
+
+ def add_dir(self, path):
+ raise NotImplementedError
+
+ def get_tmp_dir(self):
+ """Return a temporary directory that clients of the archive may
+ use to write content to. The content of the path is guaranteed
+ to be included in the generated archive."""
+ raise NotImplementedError
- def add_link(self, dest, link_name):
+ def cleanup(self):
+ """Clean up any temporary resources used by an Archive class."""
pass
- def compress(self, method):
- """Compress an archive object via method. ZIP archives are ignored. If
- method is automatic then the following technologies are tried in order: xz,
- bz2 and gzip"""
+ def finalize(self, method):
+ """Finalize an archive object via method. This may involve creating
+ An archive that is subsequently compressed or simply closing an
+ archive that supports in-line handling. If method is automatic then
+ the following technologies are tried in order: xz, bz2 and gzip"""
self.close()
-class TarFileArchive(Archive):
+class FileCacheArchive(Archive):
- def __init__(self, name):
+ _tmp_dir = ""
+ _archive_root = ""
+ _archive_path = ""
+
+ def __init__(self, name, tmpdir):
self._name = name
- self._suffix = "tar"
- self.tarfile = tarfile.open(self.name(),
- mode="w", format=tarfile.PAX_FORMAT)
-
- # this can be used to set permissions if using the
- # tarfile.add() interface to add directory trees.
- def copy_permissions_filter(self, tar_info):
- orig_path = tar_info.name[len(os.path.split(self._name)[-1]):]
- fstat = os.stat(orig_path)
- context = self.get_selinux_context(orig_path)
- if(context):
- tar_info.pax_headers['RHT.security.selinux'] = context
- self.set_tar_info_from_stat(tar_info,fstat)
- return tar_info
+ self._tmp_dir = tmpdir
+ self._archive_root = os.path.join(tmpdir, name)
+ os.makedirs(self._archive_root, 0700)
+ self.log.debug("initialised empty FileCacheArchive at %s"
+ % self._archive_root)
+
+ def dest_path(self, name):
+ if os.path.isabs(name):
+ name = name.lstrip(os.sep)
+ return (os.path.join(self._archive_root, name))
+
+ def _check_path(self, dest):
+ dest_dir = os.path.split(dest)[0]
+ if not dest_dir:
+ return
+ if not os.path.isdir(dest_dir):
+ self._makedirs(dest_dir)
- def get_selinux_context(self, path):
+ def add_file(self, src, dest=None):
+ if not dest:
+ dest = src
+ dest = self.dest_path(dest)
+ self._check_path(dest)
try:
- (rc, c) = selinux.getfilecon(path)
- return c
- except:
- return None
+ shutil.copy(src, dest)
+ shutil.copystat(src, dest)
+ stat = os.stat(src)
+ os.chown(dest, stat.st_uid, stat.st_gid)
+ except IOError as e:
+ self.log.info("caught IO error copying %s" % src)
+ self.log.debug("added %s to FileCacheArchive %s"
+ % (src, self._archive_root))
+
+ def add_string(self, content, dest):
+ src = dest
+ dest = self.dest_path(dest)
+ self._check_path(dest)
+ f = open(dest, 'w')
+ f.write(content)
+ if os.path.exists(src):
+ shutil.copystat(src, dest)
+ self.log.debug("added string at %s to FileCacheArchive %s"
+ % (src, self._archive_root))
+
+ def add_link(self, source, link_name):
+ dest = self.dest_path(link_name)
+ self._check_path(dest)
+ if not os.path.exists(dest):
+ os.symlink(source, dest)
+ self.log.debug("added symlink at %s to %s in FileCacheArchive %s"
+ % (dest, source, self._archive_root))
+
+ def add_dir(self, path):
+ self.makedirs(path)
+
+ def _makedirs(self, path, mode=0700):
+ os.makedirs(path, mode)
+
+ def get_tmp_dir(self):
+ return self._archive_root
+
+ def makedirs(self, path, mode=0700):
+ self._makedirs(self.dest_path(path))
+ self.log.debug("created directory at %s in FileCacheArchive %s"
+ % (path, self._archive_root))
+
+ def open_file(self, path):
+ path = self.dest_path(path)
+ return open(path, "r")
+
+ def cleanup(self):
+ shutil.rmtree(self._archive_root)
+
+ def finalize(self, method):
+ self.log.debug("finalizing archive %s" % self._archive_root)
+ self._build_archive()
+ self.cleanup()
+ self.log.debug("built archive at %s (size=%d)" % (self._archive_path,
+ os.stat(self._archive_path).st_size))
+ return self._compress()
+
+class TarFileArchive(FileCacheArchive):
+
+ method = None
+ _with_selinux_context = False
+
+ def __init__(self, name, tmpdir):
+ super(TarFileArchive, self).__init__(name, tmpdir)
+ self._suffix = "tar"
+ self._archive_path = os.path.join(tmpdir, self.name())
- def set_tar_info_from_stat(self, tar_info, fstat, mode=None):
+ def set_tarinfo_from_stat(self, tar_info, fstat, mode=None):
tar_info.mtime = fstat.st_mtime
tar_info.pax_headers['atime'] = "%.9f" % fstat.st_atime
tar_info.pax_headers['ctime'] = "%.9f" % fstat.st_ctime
@@ -94,115 +187,56 @@ class TarFileArchive(Archive):
tar_info.uid = fstat.st_uid
tar_info.gid = fstat.st_gid
- def name(self):
- return "%s.%s" % (self._name, self._suffix)
-
- def add_parent(self, path):
- path = os.path.split(path)[0]
- if path == '':
- return
- self.add_file(path)
-
- def add_file(self, src, dest=None):
- if dest:
- dest = self.prepend(dest)
- else:
- dest = self.prepend(src)
-
- if dest in self.tarfile.getnames():
- return
- if src != '/':
- self.add_parent(src)
-
- tar_info = tarfile.TarInfo(name=dest)
-
- if os.path.isdir(src):
- tar_info.type = tarfile.DIRTYPE
- fileobj = None
- else:
- try:
- fp = open(src, 'rb')
- content = fp.read()
- fp.close()
- except:
- # files with read permissions that cannot be read may exist
- # in /proc, /sys and other virtual file systems.
- content = ""
- tar_info.size = len(content)
- fileobj = StringIO(content)
-
- # FIXME: handle this at a higher level?
- if src.startswith("/sys/") or src.startswith ("/proc/"):
- context = None
- else:
- context = self.get_selinux_context(src)
- if context:
- tar_info.pax_headers['RHT.security.selinux'] = context
+ # this can be used to set permissions if using the
+ # tarfile.add() interface to add directory trees.
+ def copy_permissions_filter(self, tarinfo):
+ orig_path = tarinfo.name[len(os.path.split(self._name)[-1]):]
+ if not orig_path:
+ orig_path = self._archive_root
try:
- fstat = os.stat(src)
- if os.path.isdir(src) and not (fstat.st_mode & 000200):
- # directories not writable by their owner are a world of pain
- # in tar archives. Do not allow them (see Issue #85).
- mode = fstat.st_mode | 000200
- else:
- mode = None
- self.set_tar_info_from_stat(tar_info,fstat, mode)
- self.tarfile.addfile(tar_info, fileobj)
- except Exception as e:
- raise e
- finally:
- mode = None
-
- def add_string(self, content, dest):
- fstat = None
- if os.path.exists(dest):
- fstat = os.stat(dest)
- dest = self.prepend(dest)
- tar_info = tarfile.TarInfo(name=dest)
- tar_info.size = len(content)
- if fstat:
- context = self.get_selinux_context(dest)
- if context:
- tar_info.pax_headers['RHT.security.selinux'] = context
- self.set_tar_info_from_stat(tar_info, fstat)
- else:
- tar_info.mtime = time.time()
- self.tarfile.addfile(tar_info, StringIO(content))
-
- def add_link(self, dest, link_name):
- tar_info = tarfile.TarInfo(name=self.prepend(link_name))
- tar_info.type = tarfile.SYMTYPE
- tar_info.linkname = dest
- tar_info.mtime = time.time()
- self.tarfile.addfile(tar_info, None)
+ fstat = os.stat(orig_path)
+ except OSError:
+ return tarinfo
+ if self._with_selinux_context:
+ context = self.get_selinux_context(orig_path)
+ if(context):
+ tarinfo.pax_headers['RHT.security.selinux'] = context
+ self.set_tarinfo_from_stat(tarinfo,fstat)
+ return tarinfo
- def open_file(self, name):
+ def get_selinux_context(self, path):
try:
- self.tarfile.close()
- self.tarfile = tarfile.open(self.name(), mode="r")
- name = self.prepend(name)
- file_obj = self.tarfile.extractfile(name)
- file_obj = StringIO(file_obj.read())
- return file_obj
- finally:
- self.tarfile.close()
- self.tarfile = tarfile.open(self.name(), mode="a")
-
- def close(self):
- self.tarfile.close()
+ (rc, c) = selinux.getfilecon(path)
+ return c
+ except:
+ return None
- def compress(self, method):
- super(TarFileArchive, self).compress(method)
+ def name(self):
+ return "%s.%s" % (self._name, self._suffix)
+ def _build_archive(self):
+ old_pwd = os.getcwd()
+ old_umask = os.umask(0077)
+ os.chdir(self._tmp_dir)
+ tar = tarfile.open(self._archive_path, mode="w")
+ tar.add(os.path.split(self._name)[1], filter=self.copy_permissions_filter)
+ tar.close()
+ os.umask(old_umask)
+ os.chdir(old_pwd)
+
+ def _compress(self):
methods = ['xz', 'bzip2', 'gzip']
-
- if method in methods:
- methods = [method]
+ if self.method in methods:
+ methods = [self.method]
last_error = Exception("compression failed for an unknown reason")
log = logging.getLogger('sos')
for cmd in methods:
+ suffix = "." + cmd.replace('ip', '')
+ # use fast compression if using xz or bz2
+ if cmd != "gzip":
+ cmd = "%s -1" % cmd
try:
command = shlex.split("%s %s" % (cmd,self.name()))
p = Popen(command, stdout=PIPE, stderr=PIPE, bufsize=-1)
@@ -211,14 +245,13 @@ class TarFileArchive(Archive):
log.info(stdout)
if stderr:
log.error(stderr)
- self._suffix += "." + cmd.replace('ip', '')
+ self._suffix += suffix
return self.name()
except Exception, e:
last_error = e
else:
raise last_error
-
class ZipFileArchive(Archive):
def __init__(self, name):
@@ -234,8 +267,8 @@ class ZipFileArchive(Archive):
def name(self):
return "%s.zip" % self._name
- def compress(self, method):
- super(ZipFileArchive, self).compress(method)
+ def finalize(self, method):
+ super(ZipFileArchive, self).finalize(method)
return self.name()
def add_file(self, src, dest=None):
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
index 1a28a1e3..70711a3e 100644
--- a/sos/plugins/__init__.py
+++ b/sos/plugins/__init__.py
@@ -422,42 +422,43 @@ class Plugin(object):
except Exception:
return default
- def add_copy_spec_limit(self, fname, sizelimit=None, sub=None):
+ def add_copy_spec_limit(self, copyspec, sizelimit=None, sub=None):
"""Add a file or glob but limit it to sizelimit megabytes. If fname is
a single file the file will be tailed to meet sizelimit. If the first
file in a glob is too large it will be tailed to meet the sizelimit.
"""
- if not (fname and len(fname)):
+ if not (copyspec and len(copyspec)):
return False
- files = glob.glob(fname)
+ files = glob.glob(copyspec)
files.sort()
if len(files) == 0:
return
- cursize = 0
+ current_size = 0
limit_reached = False
sizelimit *= 1024 * 1024 # in MB
- flog = None
+ _file = None
- for flog in files:
- cursize += os.stat(flog)[ST_SIZE]
- if sizelimit and cursize > sizelimit:
+ for _file in files:
+ current_size += os.stat(_file)[ST_SIZE]
+ if sizelimit and current_size > sizelimit:
limit_reached = True
break
- self.add_copy_spec(flog, sub)
+ self.add_copy_spec(_file, sub)
- if flog == files[0] and limit_reached:
- flog_name = flog
+ if limit_reached:
+ file_name = _file
if sub:
old, new = sub
- flog_name = flog.replace(old, new)
- strfile = flog_name.replace(os.path.sep, ".") + ".tailed"
- self.add_string_as_file(tail(flog, sizelimit), strfile)
+ file_name = _file.replace(old, new)
+ if file_name[0] == os.sep:
+ file_name = file_name.lstrip(os.sep)
+ strfile = file_name.replace(os.path.sep, ".") + ".tailed"
+ self.add_string_as_file(tail(_file, sizelimit), strfile)
self.archive.add_link(os.path.join(
- os.path.relpath('/', os.path.dirname(flog)), 'sos_strings',
- self.name(), strfile), flog)
-
+ os.path.relpath('/', os.path.dirname(_file)), 'sos_strings',
+ self.name(), strfile), _file)
def add_copy_specs(self, copyspecs, sub=None):
for copyspec in copyspecs:
@@ -495,6 +496,12 @@ class Plugin(object):
"""Run a program and collect the output"""
self.collect_cmds.append( (exe, suggest_filename, root_symlink, timeout) )
+ def get_cmd_dir(self):
+ """Return a directory into which this module should store
+ collected command output"""
+ return os.path.join(self.archive.get_tmp_dir(),
+ 'sos_commands', self.name())
+
def file_grep(self, regexp, *fnames):
"""Returns lines matched in fnames, where fnames can either be
pathnames to files to grep through or open file objects to grep through
diff --git a/sos/plugins/cloudforms.py b/sos/plugins/cloudforms.py
index 1dc0eae3..d72dc42b 100644
--- a/sos/plugins/cloudforms.py
+++ b/sos/plugins/cloudforms.py
@@ -30,9 +30,9 @@ class Cloudforms(Plugin, RedHatPlugin):
katello_debug = "/usr/share/katello/script/katello-debug"
aeolus_debug = "aeolus-debug"
if os.path.isfile(katello_debug):
- katello_debug_path = os.path.join(self.commons['dstroot'],"katello-debug")
+ katello_debug_path = os.path.join(self.get_cmd_dir(), "katello-debug")
self.add_cmd_output("%s --notar -d %s" % (katello_debug, katello_debug_path))
if os.path.isfile(aeolus_debug):
- aeolus_debug_path = os.path.join(self.commons['dstroot'],"aeolus-debug")
+ aeolus_debug_path = os.path.join(self.get_cmd_dir(), "aeolus-debug")
self.add_cmd_output("%s --notar -d %s" % (aeolus_debug, aeolus_debug_path))
diff --git a/sos/plugins/logs.py b/sos/plugins/logs.py
index 28db0e47..8359e063 100644
--- a/sos/plugins/logs.py
+++ b/sos/plugins/logs.py
@@ -32,9 +32,9 @@ class Logs(Plugin):
self.add_copy_specs([
"/etc/syslog.conf",
"/etc/rsyslog.conf"
- )]
+ ])
- self.limit = self.get_option("syslogsize")
+ self.limit = self.get_option("logsize")
self.add_copy_spec_limit("/var/log/boot*", sizelimit = self.limit)
if self.get_option('all_logs'):
diff --git a/sos/plugins/lvm2.py b/sos/plugins/lvm2.py
index 8fb1843b..4e55f27f 100644
--- a/sos/plugins/lvm2.py
+++ b/sos/plugins/lvm2.py
@@ -29,8 +29,8 @@ class Lvm2(Plugin, RedHatPlugin, DebianPlugin, UbuntuPlugin):
"""Collects an lvmdump in standard format with optional metadata
archives for each physical volume present.
"""
- cmd = "lvmdump -d '%s'" % os.path.join(self.commons['dstroot'],
- "lvmdump")
+ lvmdump_cmd = "lvmdump -d '%s'"
+ cmd = lvmdump_cmd % os.path.join(self.get_cmd_dir(), "lvmdump")
if self.get_option('lvmdump-a'):
cmd += " -a"
self.add_cmd_output(cmd)
diff --git a/sos/plugins/rhui.py b/sos/plugins/rhui.py
index 69f3f22a..9bf29590 100644
--- a/sos/plugins/rhui.py
+++ b/sos/plugins/rhui.py
@@ -32,7 +32,7 @@ class Rhui(Plugin, RedHatPlugin):
else:
cds = ""
- rhui_debug_dst_path = os.path.join(self.commons['dstroot'],
+ rhui_debug_dst_path = os.path.join(self.get_cmd_dir(),
self.commons['cmddir'], self.name())
try:
os.mkdir(rhui_debug_dst_path)
diff --git a/sos/plugins/sanlock.py b/sos/plugins/sanlock.py
index 67474af8..232dd007 100644
--- a/sos/plugins/sanlock.py
+++ b/sos/plugins/sanlock.py
@@ -32,5 +32,5 @@ class RedHatSANLock(SANLock, RedHatPlugin):
files = [ "/etc/sysconfig/sanlock" ]
def setup(self):
- super(RedHatSanlock, self).setup()
+ super(RedHatSANLock, self).setup()
self.add_copy_spec("/etc/sysconfig/sanlock")
diff --git a/sos/plugins/satellite.py b/sos/plugins/satellite.py
index b2d3cde3..75c047fc 100644
--- a/sos/plugins/satellite.py
+++ b/sos/plugins/satellite.py
@@ -78,8 +78,7 @@ class Satellite(Plugin, RedHatPlugin):
"/etc/tomcat6/", "/var/log/tomcat6/"])
if os.path.exists("spacewalk-debug"):
self.add_cmd_output("spacewalk-debug --dir %s"
- % os.path.join(self.commons['dstroot'],
- "sos_commands/rhn"))
+ % os.path.join(self.get_cmd_dir()))
if self.proxy:
self.add_copy_specs(["/etc/squid", "/var/log/squid"])
diff --git a/sos/plugins/system.py b/sos/plugins/system.py
index 73c51c32..a7e3eda1 100644
--- a/sos/plugins/system.py
+++ b/sos/plugins/system.py
@@ -21,7 +21,7 @@ class System(Plugin, RedHatPlugin, DebianPlugin, UbuntuPlugin):
plugin_name = "system"
def setup(self):
- self.add_copy_specs("/proc/sys")
+ self.add_copy_spec("/proc/sys")
self.add_forbidden_path(
"/proc/sys/net/ipv6/neigh/*/retrans_time")
self.add_forbidden_path(
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
index 522aaff5..8eff9935 100644
--- a/sos/policies/__init__.py
+++ b/sos/policies/__init__.py
@@ -187,6 +187,10 @@ No changes will be made to system configuration.
self.report_name += "." + self.ticket_number
return "sosreport-%s-%s" % (self.report_name, time.strftime("%Y%m%d%H%M%S"))
+ def get_tmp_dir(self, opt_tmp_dir):
+ if not opt_tmp_dir:
+ return tempfile.gettempdir()
+
def validatePlugin(self, plugin_class):
"""
Verifies that the plugin_class should execute under this policy
diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py
index d9dc6b3e..c3740dce 100644
--- a/sos/policies/redhat.py
+++ b/sos/policies/redhat.py
@@ -35,6 +35,7 @@ class RedHatPolicy(LinuxPolicy):
distro = "Red Hat"
vendor = "Red Hat"
vendor_url = "http://www.redhat.com/"
+ _tmp_dir = "/var/tmp"
def __init__(self):
super(RedHatPolicy, self).__init__()
@@ -81,6 +82,10 @@ class RedHatPolicy(LinuxPolicy):
ret.append(int(runlevel))
return ret
+ def get_tmp_dir(self, opt_tmp_dir):
+ if not opt_tmp_dir:
+ return self._tmp_dir
+
def get_local_name(self):
return self.host_name()
diff --git a/sos/sosreport.py b/sos/sosreport.py
index df9be1ee..908cbede 100644
--- a/sos/sosreport.py
+++ b/sos/sosreport.py
@@ -495,7 +495,7 @@ class SoSOptions(object):
help="specify alternate configuration file")
parser.add_option("--tmp-dir", action="store",
dest="tmp_dir",
- help="specify alternate temporary directory", default=tempfile.gettempdir())
+ help="specify alternate temporary directory", default=None)
parser.add_option("--report", action="store_true",
dest="report",
help="Enable HTML/XML reporting", default=False)
@@ -517,6 +517,8 @@ class SoSReport(object):
self.all_options = deque()
self.xml_report = XmlReport()
self.global_plugin_options = {}
+ self.archive = None
+ self.tempfile_util = None
try:
import signal
@@ -527,11 +529,12 @@ class SoSReport(object):
#self.opts = self.parse_options(args)[0]
self.opts = SoSOptions(args)
- self.tempfile_util = TempFileUtil(tmp_dir=self.opts.tmp_dir)
self._set_debug()
self._read_config()
self.policy = sos.policies.load()
self._is_root = self.policy.is_root()
+ self.tmpdir = self.policy.get_tmp_dir(self.opts.tmp_dir)
+ self.tempfile_util = TempFileUtil(self.tmpdir)
self._set_directories()
def print_header(self):
@@ -542,7 +545,7 @@ class SoSReport(object):
'cmddir': self.cmddir,
'logdir': self.logdir,
'rptdir': self.rptdir,
- 'tmpdir': self.opts.tmp_dir,
+ 'tmpdir': self.tmpdir,
'soslog': self.soslog,
'proflog' : self.proflog,
'policy': self.policy,
@@ -558,15 +561,21 @@ class SoSReport(object):
def _set_archive(self):
if self.opts.compression_type not in ('auto', 'zip', 'bzip2', 'gzip', 'xz'):
- raise Exception("Invalid compression type specified. Options are: auto, zip, bzip2, gzip and xz")
- archive_name = os.path.join(self.opts.tmp_dir,self.policy.get_archive_name())
+ raise Exception("Invalid compression type specified. Options are:" +
+ "auto, zip, bzip2, gzip and xz")
+ archive_name = os.path.join(self.tmpdir,self.policy.get_archive_name())
if self.opts.compression_type == 'auto':
auto_archive = self.policy.preferred_archive_name()
- self.archive = auto_archive(archive_name)
+ self.archive = auto_archive(archive_name, self.tmpdir)
elif self.opts.compression_type == 'zip':
- self.archive = ZipFileArchive(archive_name)
+ self.archive = ZipFileArchive(archive_name, self.tmpdir)
else:
- self.archive = TarFileArchive(archive_name)
+ self.archive = TarFileArchive(archive_name, self.tmpdir)
+
+ def _make_archive_paths(self):
+ self.archive.makedirs(self.cmddir, 0755)
+ self.archive.makedirs(self.logdir, 0755)
+ self.archive.makedirs(self.rptdir, 0755)
def _set_directories(self):
self.cmddir = 'sos_commands'
@@ -914,6 +923,7 @@ class SoSReport(object):
try:
self.policy.pre_work()
self._set_archive()
+ self._make_archive_paths()
except Exception, e:
import traceback
traceback.print_exc(e)
@@ -1089,9 +1099,12 @@ class SoSReport(object):
# compression could fail for a number of reasons
try:
- final_filename = self.archive.compress(self.opts.compression_type)
+ final_filename = self.archive.finalize(self.opts.compression_type)
except:
- return False
+ if self.opts.debug:
+ raise
+ else:
+ return False
# automated submission will go here
if not self.opts.upload:
@@ -1145,7 +1158,11 @@ class SoSReport(object):
self.version()
return self.final_work()
- except SystemExit:
+ except (SystemExit, KeyboardInterrupt):
+ if self.archive:
+ self.archive.cleanup()
+ if self.tempfile_util:
+ self.tempfile_util.clean()
return False
def main(args):