89b86368f8
Update sos in rawhide to the upstream 3.2 release and additional patches including the fix for CVE-2015-7529.
2459 lines
88 KiB
Diff
2459 lines
88 KiB
Diff
From cb3d265849771f7e53b0587196930328005414e0 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 19 Jan 2015 18:54:09 +0000
|
|
Subject: [PATCH 01/38] [sosreport] add --sysroot option
|
|
|
|
Add a --sysroot=SYSROOT option to specify that the root file system to
|
|
be inspected is mounted at SYSROOT.
|
|
|
|
This allows basic support for container environments where sos is
|
|
running in a container and inspecting the containing host and its
|
|
environment ('superspection').
|
|
|
|
For this to work currently the following conditions must be met:
|
|
|
|
- sos is sufficiently privileged to read and search relevant file
|
|
system paths within SYSROOT
|
|
|
|
- sos must share the PID and network namespace of the target host
|
|
|
|
- binaries called by sos must be present and executable in the
|
|
SYSROOT inherited by sos. If PATH includes paths inside SYSROOT
|
|
appropriate values must be set for LD_LIBRARY_PATH to allow
|
|
shared executables to be linked.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 16 +++++++++++++++-
|
|
1 file changed, 15 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index 9a0cf6c..47eddc9 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -529,6 +529,17 @@ class SoSOptions(object):
|
|
self._report = value
|
|
|
|
@property
|
|
+ def sysroot(self):
|
|
+ if self._options is not None:
|
|
+ return self._options.sysroot
|
|
+ return self._sysroot
|
|
+
|
|
+ @sysroot.setter
|
|
+ def sysroot(self, value):
|
|
+ self._check_options_initialized()
|
|
+ self._sysroot = value
|
|
+
|
|
+ @property
|
|
def compression_type(self):
|
|
if self._options is not None:
|
|
return self._options.compression_type
|
|
@@ -615,6 +626,9 @@ class SoSOptions(object):
|
|
parser.add_option("--no-report", action="store_true",
|
|
dest="report",
|
|
help="Disable HTML/XML reporting", default=False)
|
|
+ parser.add_option("-s", "--sysroot", action="store", dest="sysroot",
|
|
+ help="system root directory path (default='/')",
|
|
+ default="/")
|
|
parser.add_option("-z", "--compression-type", dest="compression_type",
|
|
help="compression technology to use [auto, "
|
|
"gzip, bzip2, xz] (default=auto)",
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 3eed62e132f67930bb1cf5c9eaa5927083011043 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Fri, 23 Jan 2015 15:24:00 +0000
|
|
Subject: [PATCH 02/38] [plugins] propagate sysroot to Plugin via commons
|
|
|
|
Although plugins should generally be unaware that they are being
|
|
run with an alternate sysroot the generic plugin IO code must
|
|
peform the appropriate path prefixing when sysroot is not '/'.
|
|
|
|
Propagate sysroot to plugin classes via the commons dictionary.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 6 ++++++
|
|
1 file changed, 6 insertions(+)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index 47eddc9..580b5bd 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -651,6 +651,7 @@ class SoSReport(object):
|
|
self.archive = None
|
|
self.tempfile_util = None
|
|
self._args = args
|
|
+ self.sysroot = "/"
|
|
|
|
try:
|
|
import signal
|
|
@@ -681,6 +682,10 @@ class SoSReport(object):
|
|
self.tempfile_util = TempFileUtil(self.tmpdir)
|
|
self._set_directories()
|
|
|
|
+ # set alternate system root directory
|
|
+ if self.opts.sysroot:
|
|
+ self.sysroot = self.opts.sysroot
|
|
+
|
|
def print_header(self):
|
|
self.ui_log.info("\n%s\n" % _("sosreport (version %s)" %
|
|
(__version__,)))
|
|
@@ -693,6 +698,7 @@ class SoSReport(object):
|
|
'tmpdir': self.tmpdir,
|
|
'soslog': self.soslog,
|
|
'policy': self.policy,
|
|
+ 'sysroot': self.sysroot,
|
|
'verbosity': self.opts.verbosity,
|
|
'xmlreport': self.xml_report,
|
|
'cmdlineopts': self.opts,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From b1f3b3373e8ef3e94238760a3e7e78d95c564260 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Fri, 23 Jan 2015 23:17:34 +0000
|
|
Subject: [PATCH 03/38] [plugins] prefix target paths with self.sysroot
|
|
|
|
Prefix copyspecs with self.sysroot when using an alternate root
|
|
path. Prefixes are applied before expanding copyspecs and the
|
|
prefixed paths are stored as the 'srcpath' attribute in the
|
|
archive. Destination paths in the report archive do not include
|
|
the prefix.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 50 +++++++++++++++++++++++++++++++++++--------
|
|
tests/option_tests.py | 3 ++-
|
|
tests/plugin_tests.py | 57 ++++++++++++++++++++++++++++++++-----------------
|
|
3 files changed, 81 insertions(+), 29 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 413ee73..790338b 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -101,6 +101,7 @@ class Plugin(object):
|
|
files = ()
|
|
archive = None
|
|
profiles = ()
|
|
+ sysroot = '/'
|
|
|
|
def __init__(self, commons):
|
|
if not getattr(self, "option_list", False):
|
|
@@ -117,6 +118,7 @@ class Plugin(object):
|
|
self.copy_paths = set()
|
|
self.copy_strings = []
|
|
self.collect_cmds = []
|
|
+ self.sysroot = commons['sysroot']
|
|
|
|
self.soslog = self.commons['soslog'] if 'soslog' in self.commons \
|
|
else logging.getLogger('sos')
|
|
@@ -154,6 +156,19 @@ class Plugin(object):
|
|
def policy(self):
|
|
return self.commons["policy"]
|
|
|
|
+ def join_sysroot(self, path):
|
|
+ if path[0] == os.sep:
|
|
+ path = path[1:]
|
|
+ return os.path.join(self.sysroot, path)
|
|
+
|
|
+ def strip_sysroot(self, path):
|
|
+ if path.startswith(self.sysroot):
|
|
+ return path[len(self.sysroot):]
|
|
+ return path
|
|
+
|
|
+ def use_sysroot(self):
|
|
+ return self.sysroot != os.path.abspath(os.sep)
|
|
+
|
|
def is_installed(self, package_name):
|
|
'''Is the package $package_name installed?'''
|
|
return self.policy().pkg_by_name(package_name) is not None
|
|
@@ -207,6 +222,7 @@ class Plugin(object):
|
|
'''
|
|
try:
|
|
path = self._get_dest_for_srcpath(srcpath)
|
|
+ self._log_debug("substituting scrpath '%s'" % srcpath)
|
|
self._log_debug("substituting '%s' for '%s' in '%s'"
|
|
% (subst, regexp, path))
|
|
if not path:
|
|
@@ -257,8 +273,9 @@ class Plugin(object):
|
|
self._log_debug("copying link '%s' pointing to '%s' with isdir=%s"
|
|
% (srcpath, linkdest, os.path.isdir(absdest)))
|
|
|
|
+ dstpath = self.strip_sysroot(srcpath)
|
|
# use the relative target path in the tarball
|
|
- self.archive.add_link(reldest, srcpath)
|
|
+ self.archive.add_link(reldest, dstpath)
|
|
|
|
if os.path.isdir(absdest):
|
|
self._log_debug("link '%s' is a directory, skipping..." % linkdest)
|
|
@@ -277,7 +294,7 @@ class Plugin(object):
|
|
self._do_copy_path(absdest)
|
|
|
|
self.copied_files.append({'srcpath': srcpath,
|
|
- 'dstpath': srcpath,
|
|
+ 'dstpath': dstpath,
|
|
'symlink': "yes",
|
|
'pointsto': linkdest})
|
|
|
|
@@ -288,6 +305,8 @@ class Plugin(object):
|
|
self._do_copy_path(os.path.join(srcpath, afile), dest=None)
|
|
|
|
def _get_dest_for_srcpath(self, srcpath):
|
|
+ if self.use_sysroot():
|
|
+ srcpath = self.join_sysroot(srcpath)
|
|
for copied in self.copied_files:
|
|
if srcpath == copied["srcpath"]:
|
|
return copied["dstpath"]
|
|
@@ -315,6 +334,9 @@ class Plugin(object):
|
|
if not dest:
|
|
dest = srcpath
|
|
|
|
+ if self.use_sysroot():
|
|
+ dest = self.strip_sysroot(dest)
|
|
+
|
|
try:
|
|
st = os.lstat(srcpath)
|
|
except (OSError, IOError):
|
|
@@ -333,7 +355,7 @@ class Plugin(object):
|
|
if not (stat.S_ISREG(st.st_mode) or stat.S_ISDIR(st.st_mode)):
|
|
ntype = _node_type(st)
|
|
self._log_debug("creating %s node at archive:'%s'"
|
|
- % (ntype, srcpath))
|
|
+ % (ntype, dest))
|
|
self._copy_node(srcpath, st)
|
|
return
|
|
|
|
@@ -347,9 +369,11 @@ class Plugin(object):
|
|
else:
|
|
self.archive.add_file(srcpath, dest)
|
|
|
|
- self.copied_files.append({'srcpath': srcpath,
|
|
- 'dstpath': dest,
|
|
- 'symlink': "no"})
|
|
+ self.copied_files.append({
|
|
+ 'srcpath': srcpath,
|
|
+ 'dstpath': dest,
|
|
+ 'symlink': "no"
|
|
+ })
|
|
|
|
def add_forbidden_path(self, forbiddenPath):
|
|
"""Specify a path to not copy, even if it's part of a copy_specs[]
|
|
@@ -416,6 +440,9 @@ class Plugin(object):
|
|
except Exception:
|
|
return default
|
|
|
|
+ def _add_copy_paths(self, copy_paths):
|
|
+ self.copy_paths.update(copy_paths)
|
|
+
|
|
def add_copy_spec_limit(self, copyspec, sizelimit=None, tailit=True):
|
|
"""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
|
|
@@ -424,10 +451,13 @@ class Plugin(object):
|
|
if not (copyspec and len(copyspec)):
|
|
return False
|
|
|
|
+ if self.use_sysroot():
|
|
+ copyspec = self.join_sysroot(copyspec)
|
|
files = glob.glob(copyspec)
|
|
files.sort()
|
|
if len(files) == 0:
|
|
return
|
|
+
|
|
current_size = 0
|
|
limit_reached = False
|
|
sizelimit *= 1024 * 1024 # in MB
|
|
@@ -438,7 +468,7 @@ class Plugin(object):
|
|
if sizelimit and current_size > sizelimit:
|
|
limit_reached = True
|
|
break
|
|
- self.add_copy_spec(_file)
|
|
+ self._add_copy_paths([_file])
|
|
|
|
if limit_reached and tailit:
|
|
file_name = _file
|
|
@@ -459,12 +489,14 @@ class Plugin(object):
|
|
if isinstance(copyspecs, six.string_types):
|
|
copyspecs = [copyspecs]
|
|
for copyspec in copyspecs:
|
|
+ if self.use_sysroot():
|
|
+ copyspec = self.join_sysroot(copyspec)
|
|
if not (copyspec and len(copyspec)):
|
|
self._log_warn("added null or empty copy spec")
|
|
return False
|
|
copy_paths = self._expand_copy_spec(copyspec)
|
|
- self.copy_paths.update(copy_paths)
|
|
- self._log_info("added copyspec '%s'" % copyspec)
|
|
+ self._add_copy_paths(copy_paths)
|
|
+ self._log_info("added copyspec '%s'" % copy_paths)
|
|
|
|
def get_command_output(self, prog, timeout=300, runat=None, stderr=True):
|
|
result = sos_get_command_output(prog, timeout=timeout, runat=runat,
|
|
diff --git a/tests/option_tests.py b/tests/option_tests.py
|
|
index fe37ccf..e8a26e2 100644
|
|
--- a/tests/option_tests.py
|
|
+++ b/tests/option_tests.py
|
|
@@ -8,10 +8,11 @@ class GlobalOptionTest(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.commons = {
|
|
+ 'sysroot': '/',
|
|
'global_plugin_options': {
|
|
'test_option': 'foobar',
|
|
'baz': None,
|
|
- 'empty_global': True,
|
|
+ 'empty_global': True
|
|
},
|
|
}
|
|
self.plugin = Plugin(self.commons)
|
|
diff --git a/tests/plugin_tests.py b/tests/plugin_tests.py
|
|
index e30ded5..14d3b49 100644
|
|
--- a/tests/plugin_tests.py
|
|
+++ b/tests/plugin_tests.py
|
|
@@ -127,50 +127,53 @@ class PluginToolTests(unittest.TestCase):
|
|
|
|
class PluginTests(unittest.TestCase):
|
|
|
|
+ sysroot = os.getcwd()
|
|
+
|
|
def setUp(self):
|
|
self.mp = MockPlugin({
|
|
- 'cmdlineopts': MockOptions()
|
|
+ 'cmdlineopts': MockOptions(),
|
|
+ 'sysroot': self.sysroot
|
|
})
|
|
self.mp.archive = MockArchive()
|
|
|
|
def test_plugin_default_name(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.name(), "mockplugin")
|
|
|
|
def test_plugin_set_name(self):
|
|
- p = NamedMockPlugin({})
|
|
+ p = NamedMockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.name(), "testing")
|
|
|
|
def test_plugin_no_descrip(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_description(), "<no description available>")
|
|
|
|
def test_plugin_no_descrip(self):
|
|
- p = NamedMockPlugin({})
|
|
+ p = NamedMockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_description(), "This plugin has a description.")
|
|
|
|
def test_set_plugin_option(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
p.set_option("opt", "testing")
|
|
self.assertEquals(p.get_option("opt"), "testing")
|
|
|
|
def test_set_nonexistant_plugin_option(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertFalse(p.set_option("badopt", "testing"))
|
|
|
|
def test_get_nonexistant_plugin_option(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_option("badopt"), 0)
|
|
|
|
def test_get_unset_plugin_option(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_option("opt"), 0)
|
|
|
|
def test_get_unset_plugin_option_with_default(self):
|
|
# this shows that even when we pass in a default to get,
|
|
# we'll get the option's default as set in the plugin
|
|
# this might not be what we really want
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_option("opt", True), True)
|
|
|
|
def test_get_unset_plugin_option_with_default_not_none(self):
|
|
@@ -178,20 +181,20 @@ class PluginTests(unittest.TestCase):
|
|
# if the plugin default is not None
|
|
# we'll get the option's default as set in the plugin
|
|
# this might not be what we really want
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_option("opt2", True), False)
|
|
|
|
def test_get_option_as_list_plugin_option(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
p.set_option("opt", "one,two,three")
|
|
self.assertEquals(p.get_option_as_list("opt"), ['one', 'two', 'three'])
|
|
|
|
def test_get_option_as_list_plugin_option_default(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
self.assertEquals(p.get_option_as_list("opt", default=[]), [])
|
|
|
|
def test_get_option_as_list_plugin_option_not_list(self):
|
|
- p = MockPlugin({})
|
|
+ p = MockPlugin({'sysroot': self.sysroot})
|
|
p.set_option("opt", "testing")
|
|
self.assertEquals(p.get_option_as_list("opt"), ['testing'])
|
|
|
|
@@ -205,7 +208,8 @@ class PluginTests(unittest.TestCase):
|
|
|
|
def test_copy_dir_forbidden_path(self):
|
|
p = ForbiddenMockPlugin({
|
|
- 'cmdlineopts': MockOptions()
|
|
+ 'cmdlineopts': MockOptions(),
|
|
+ 'sysroot': self.sysroot
|
|
})
|
|
p.archive = MockArchive()
|
|
p.setup()
|
|
@@ -219,12 +223,18 @@ class AddCopySpecTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.mp = MockPlugin({
|
|
- 'cmdlineopts': MockOptions()
|
|
+ 'cmdlineopts': MockOptions(),
|
|
+ 'sysroot': os.getcwd()
|
|
})
|
|
self.mp.archive = MockArchive()
|
|
|
|
def assert_expect_paths(self):
|
|
- self.assertEquals(self.mp.copy_paths, self.expect_paths)
|
|
+ def pathmunge(path):
|
|
+ if path[0] == '/':
|
|
+ path = path[1:]
|
|
+ return os.path.join(self.mp.sysroot, path)
|
|
+ expected_paths = set(map(pathmunge, self.expect_paths))
|
|
+ self.assertEquals(self.mp.copy_paths, expected_paths)
|
|
|
|
# add_copy_spec()
|
|
|
|
@@ -242,6 +252,7 @@ class AddCopySpecTests(unittest.TestCase):
|
|
# add_copy_spec_limit()
|
|
|
|
def test_single_file_over_limit(self):
|
|
+ self.mp.sysroot = '/'
|
|
fn = create_file(2) # create 2MB file, consider a context manager
|
|
self.mp.add_copy_spec_limit(fn, 1)
|
|
content, fname = self.mp.copy_strings[0]
|
|
@@ -252,10 +263,12 @@ class AddCopySpecTests(unittest.TestCase):
|
|
os.unlink(fn)
|
|
|
|
def test_bad_filename(self):
|
|
+ self.mp.sysroot = '/'
|
|
self.assertFalse(self.mp.add_copy_spec_limit('', 1))
|
|
self.assertFalse(self.mp.add_copy_spec_limit(None, 1))
|
|
|
|
def test_glob_file_over_limit(self):
|
|
+ self.mp.sysroot = '/'
|
|
# assume these are in /tmp
|
|
fn = create_file(2)
|
|
fn2 = create_file(2)
|
|
@@ -271,7 +284,10 @@ class AddCopySpecTests(unittest.TestCase):
|
|
class CheckEnabledTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
- self.mp = EnablerPlugin({'policy': sos.policies.load()})
|
|
+ self.mp = EnablerPlugin({
|
|
+ 'policy': sos.policies.load(),
|
|
+ 'sysroot': os.getcwd()
|
|
+ })
|
|
|
|
def test_checks_for_file(self):
|
|
f = j("tail_test.txt")
|
|
@@ -296,7 +312,8 @@ class RegexSubTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.mp = MockPlugin({
|
|
- 'cmdlineopts': MockOptions()
|
|
+ 'cmdlineopts': MockOptions(),
|
|
+ 'sysroot': os.getcwd()
|
|
})
|
|
self.mp.archive = MockArchive()
|
|
|
|
@@ -310,6 +327,8 @@ class RegexSubTests(unittest.TestCase):
|
|
self.assertEquals(0, replacements)
|
|
|
|
def test_replacements(self):
|
|
+ # test uses absolute paths
|
|
+ self.mp.sysroot = '/'
|
|
self.mp.add_copy_spec(j("tail_test.txt"))
|
|
self.mp.collect()
|
|
replacements = self.mp.do_file_sub(j("tail_test.txt"), r"(tail)", "foobar")
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From c4957d8aa4ea35f879639726267043f6bb46cc7c Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sat, 24 Jan 2015 00:35:09 +0000
|
|
Subject: [PATCH 04/38] [docs] add -s/--sysroot to sosreport.1
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
man/en/sosreport.1 | 5 +++++
|
|
1 file changed, 5 insertions(+)
|
|
|
|
diff --git a/man/en/sosreport.1 b/man/en/sosreport.1
|
|
index c2b60d8..b0a86f2 100644
|
|
--- a/man/en/sosreport.1
|
|
+++ b/man/en/sosreport.1
|
|
@@ -12,6 +12,7 @@ sosreport \- Collect and package diagnostic and support data
|
|
[--no-report] [--config-file conf]\fR
|
|
[--batch] [--build] [--debug]\fR
|
|
[--name name] [--case-id id] [--ticket-number nr]
|
|
+ [-s|--sysroot]\fR
|
|
[--tmp-dir directory]\fR
|
|
[-p|--profile profile-name]\fR
|
|
[--list-profiles]\fR
|
|
@@ -72,6 +73,10 @@ Disable HTML/XML report writing.
|
|
.B \--config-file CONFIG
|
|
Specify alternate configuration file.
|
|
.TP
|
|
+.B \-s, \--sysroot SYSROOT
|
|
+Specify an alternate root file system path. Useful for collecting
|
|
+reports from containers and images.
|
|
+.TP
|
|
.B \--tmp-dir DIRECTORY
|
|
Specify alternate temporary directory to copy data as well as the
|
|
compressed report.
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 4a0a3f9607006d402713320fc31780fb54556e6a Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 14:20:10 +0000
|
|
Subject: [PATCH 05/38] [utilities] add chroot support to
|
|
sos_get_command_output()
|
|
|
|
Allow callers of sos_get_command_output() to specify a path to
|
|
chroot into before executing command.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 2 +-
|
|
sos/utilities.py | 27 ++++++++++++++++-----------
|
|
tests/utilities_tests.py | 5 +++++
|
|
3 files changed, 22 insertions(+), 12 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 790338b..137e1a1 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -499,7 +499,7 @@ class Plugin(object):
|
|
self._log_info("added copyspec '%s'" % copy_paths)
|
|
|
|
def get_command_output(self, prog, timeout=300, runat=None, stderr=True):
|
|
- result = sos_get_command_output(prog, timeout=timeout, runat=runat,
|
|
+ result = sos_get_command_output(prog, timeout=timeout, chdir=runat,
|
|
stderr=stderr)
|
|
if result['status'] == 124:
|
|
self._log_warn("command '%s' timed out after %ds"
|
|
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
index dfe6128..a82ac7c 100644
|
|
--- a/sos/utilities.py
|
|
+++ b/sos/utilities.py
|
|
@@ -120,15 +120,20 @@ def is_executable(command):
|
|
return any(os.access(path, os.X_OK) for path in candidates)
|
|
|
|
|
|
-def sos_get_command_output(command, timeout=300, runat=None, stderr=True):
|
|
- """Execute a command through the system shell. First checks to see if the
|
|
- requested command is executable. Returns (returncode, stdout, 0)"""
|
|
- def _child_chdir():
|
|
- if(runat):
|
|
- try:
|
|
- os.chdir(runat)
|
|
- except:
|
|
- self.log_error("failed to chdir to '%s'" % runat)
|
|
+def sos_get_command_output(command, timeout=300, stderr=False,
|
|
+ chroot=None, chdir=None):
|
|
+ """Execute a command and return a dictionary of status and output,
|
|
+ optionally changing root or current working directory before
|
|
+ executing command.
|
|
+ """
|
|
+ # Change root or cwd for child only. Exceptions in the prexec_fn
|
|
+ # closure are caught in the parent (chroot and chdir are bound from
|
|
+ # the enclosing scope).
|
|
+ def _child_prep_fn():
|
|
+ if (chroot):
|
|
+ os.chroot(chroot)
|
|
+ if (chdir):
|
|
+ os.chdir(chdir)
|
|
|
|
cmd_env = os.environ
|
|
# ensure consistent locale for collected command output
|
|
@@ -145,7 +150,7 @@ def sos_get_command_output(command, timeout=300, runat=None, stderr=True):
|
|
p = Popen(args, shell=False, stdout=PIPE,
|
|
stderr=STDOUT if stderr else PIPE,
|
|
bufsize=-1, env=cmd_env, close_fds=True,
|
|
- preexec_fn=_child_chdir)
|
|
+ preexec_fn=_child_prep_fn)
|
|
except OSError as e:
|
|
if e.errno == errno.ENOENT:
|
|
return {'status': 127, 'output': ""}
|
|
@@ -185,7 +190,7 @@ def shell_out(cmd, timeout=30, runat=None):
|
|
"""Shell out to an external command and return the output or the empty
|
|
string in case of error.
|
|
"""
|
|
- return sos_get_command_output(cmd, timeout=timeout, runat=runat)['output']
|
|
+ return sos_get_command_output(cmd, timeout=timeout, chdir=runat)['output']
|
|
|
|
|
|
class ImporterHelper(object):
|
|
diff --git a/tests/utilities_tests.py b/tests/utilities_tests.py
|
|
index 607056e..9327b1f 100644
|
|
--- a/tests/utilities_tests.py
|
|
+++ b/tests/utilities_tests.py
|
|
@@ -68,6 +68,11 @@ class ExecutableTest(unittest.TestCase):
|
|
self.assertEquals(result['status'], 127)
|
|
self.assertEquals(result['output'], "")
|
|
|
|
+ def test_output_chdir(self):
|
|
+ result = sos_get_command_output("/usr/bin/pwd", chdir=TEST_DIR)
|
|
+ self.assertEquals(result['status'], 0)
|
|
+ self.assertEquals(result['output'].strip(), TEST_DIR)
|
|
+
|
|
def test_shell_out(self):
|
|
path = os.path.join(TEST_DIR, 'test_exe.py')
|
|
self.assertEquals("executed\n", shell_out(path))
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 9a87cb3415a7a9587828ee40d689439949def1be Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 14:30:13 +0000
|
|
Subject: [PATCH 06/38] [sosreport] add --chroot option
|
|
|
|
Add a --chroot option to sosreport to control command chrooting.
|
|
|
|
The option takes one of three values:
|
|
|
|
* auto - Allow callers of the API to control chroot behaviour
|
|
* always - Always chroot external commands to --sysroot
|
|
* never - Never chroot external commands
|
|
|
|
This is a fairly low-level option and may not be exposed to the
|
|
user in a final release; for now it will allow tests in container
|
|
environments to control the chrooting behaviour used for a run.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 19 +++++++++++++++++++
|
|
tests/utilities_tests.py | 4 +++-
|
|
2 files changed, 22 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index 580b5bd..d9abcb8 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -540,6 +540,21 @@ class SoSOptions(object):
|
|
self._sysroot = value
|
|
|
|
@property
|
|
+ def chroot(self):
|
|
+ if self._options is not None:
|
|
+ return self._options.chroot
|
|
+ return self._chroot
|
|
+
|
|
+ @chroot.setter
|
|
+ def chroot(self, value):
|
|
+ self._check_options_initialized()
|
|
+ if value not in ["auto", "always", "never"]:
|
|
+ msg = "SoSOptions.chroot '%s' is not a valid chroot mode: "
|
|
+ msg += "('auto', 'always', 'never')"
|
|
+ raise ValueError(msg % value)
|
|
+ self._chroot = value
|
|
+
|
|
+ @property
|
|
def compression_type(self):
|
|
if self._options is not None:
|
|
return self._options.compression_type
|
|
@@ -630,6 +645,10 @@ class SoSOptions(object):
|
|
parser.add_option("-s", "--sysroot", action="store", dest="sysroot",
|
|
help="system root directory path (default='/')",
|
|
default="/")
|
|
+ parser.add_option("-c", "--chroot", action="store", dest="chroot",
|
|
+ help="chroot executed commands to SYSROOT "
|
|
+ "[auto, always, never] (default=auto)",
|
|
+ default="auto")
|
|
parser.add_option("-z", "--compression-type", dest="compression_type",
|
|
help="compression technology to use [auto, "
|
|
"gzip, bzip2, xz] (default=auto)",
|
|
diff --git a/tests/utilities_tests.py b/tests/utilities_tests.py
|
|
index 9327b1f..c464692 100644
|
|
--- a/tests/utilities_tests.py
|
|
+++ b/tests/utilities_tests.py
|
|
@@ -69,7 +69,9 @@ class ExecutableTest(unittest.TestCase):
|
|
self.assertEquals(result['output'], "")
|
|
|
|
def test_output_chdir(self):
|
|
- result = sos_get_command_output("/usr/bin/pwd", chdir=TEST_DIR)
|
|
+ cmd = "/bin/bash -c 'echo $PWD'"
|
|
+ result = sos_get_command_output(cmd, chdir=TEST_DIR)
|
|
+ print(result)
|
|
self.assertEquals(result['status'], 0)
|
|
self.assertEquals(result['output'].strip(), TEST_DIR)
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 0d060dc3aa5e90373e7bb55f9310b4cf9db0dad4 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 15:04:29 +0000
|
|
Subject: [PATCH 07/38] [plugins] implement --chroot for command callouts
|
|
|
|
When --chroot=always is given chroot all commands to SYSROOT.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 8 ++++++--
|
|
1 file changed, 6 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 137e1a1..10fdae5 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -499,8 +499,12 @@ class Plugin(object):
|
|
self._log_info("added copyspec '%s'" % copy_paths)
|
|
|
|
def get_command_output(self, prog, timeout=300, runat=None, stderr=True):
|
|
- result = sos_get_command_output(prog, timeout=timeout, chdir=runat,
|
|
- stderr=stderr)
|
|
+ if self.commons['cmdlineopts'].chroot == 'always':
|
|
+ root = self.sysroot
|
|
+ else:
|
|
+ root = None
|
|
+ result = sos_get_command_output(prog, timeout=timeout, stderr=stderr
|
|
+ chroot=root, chdir=runat)
|
|
if result['status'] == 124:
|
|
self._log_warn("command '%s' timed out after %ds"
|
|
% (prog, timeout))
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From f6f7934c7d3e7f6cb41879fc0625b06d0468af4e Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 19:32:04 +0000
|
|
Subject: [PATCH 08/38] [plugin] fix chrooted symlink handling
|
|
|
|
_copy_symlink() needs to strip_sysroot(), not join_sysroot(), on
|
|
a link target before handing it to _do_copy_path().
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 10fdae5..9d04939 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -294,7 +294,7 @@ class Plugin(object):
|
|
# to absolute paths to pass to _do_copy_path.
|
|
self._log_debug("normalized link target '%s' as '%s'"
|
|
% (linkdest, absdest))
|
|
- self._do_copy_path(absdest)
|
|
+ self._do_copy_path(self.strip_sysroot(absdest))
|
|
|
|
self.copied_files.append({'srcpath': srcpath,
|
|
'dstpath': dstpath,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From b16fbf3911c6256674e072cff6fa706050861993 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 21:54:19 +0000
|
|
Subject: [PATCH 09/38] [sosreport] check for valid CHROOT values
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 16 +++++++++++++---
|
|
1 file changed, 13 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index d9abcb8..a0b89e7 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -225,6 +225,10 @@ class XmlReport(object):
|
|
outf.close()
|
|
|
|
|
|
+# valid modes for --chroot
|
|
+chroot_modes = ["auto", "always", "never"]
|
|
+
|
|
+
|
|
class SoSOptions(object):
|
|
_list_plugins = False
|
|
_noplugins = []
|
|
@@ -548,7 +552,7 @@ class SoSOptions(object):
|
|
@chroot.setter
|
|
def chroot(self, value):
|
|
self._check_options_initialized()
|
|
- if value not in ["auto", "always", "never"]:
|
|
+ if value not in chroot_modes:
|
|
msg = "SoSOptions.chroot '%s' is not a valid chroot mode: "
|
|
msg += "('auto', 'always', 'never')"
|
|
raise ValueError(msg % value)
|
|
@@ -705,6 +709,14 @@ class SoSReport(object):
|
|
if self.opts.sysroot:
|
|
self.sysroot = self.opts.sysroot
|
|
|
|
+ self._setup_logging()
|
|
+
|
|
+ if self.opts.chroot not in chroot_modes:
|
|
+ self.soslog.error("invalid chroot mode: %s" % self.opts.chroot)
|
|
+ logging.shutdown()
|
|
+ self.tempfile_util.clean()
|
|
+ self._exit(1)
|
|
+
|
|
def print_header(self):
|
|
self.ui_log.info("\n%s\n" % _("sosreport (version %s)" %
|
|
(__version__,)))
|
|
@@ -1205,7 +1217,6 @@ class SoSReport(object):
|
|
self.ui_log.error(" %s while setting up plugins"
|
|
% e.strerror)
|
|
self.ui_log.error("")
|
|
- self._exit(1)
|
|
if self.raise_plugins:
|
|
raise
|
|
self._log_plugin_exception(plugname, "setup")
|
|
@@ -1455,7 +1466,6 @@ class SoSReport(object):
|
|
|
|
def execute(self):
|
|
try:
|
|
- self._setup_logging()
|
|
self.policy.set_commons(self.get_commons())
|
|
self.print_header()
|
|
self.load_plugins()
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From f06efd6fa7bbb0c81ce0461d4eaeed225d6f04a2 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 23:03:08 +0000
|
|
Subject: [PATCH 10/38] [plugins] add chroot parameter to callout APIs
|
|
|
|
Expose sos_get_command_output()'s chroot support to plugins via
|
|
add_cmd_output(), get_command_output(), call_ext_prog() and
|
|
related Plugin methods.
|
|
|
|
'chroot' is a boolean indicating whether the command should run
|
|
in the chroot (True) or in the host namespace (False).
|
|
|
|
Has no effect when Plugin.use_sysroot() is False.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 50 ++++++++++++++++++++++++++++---------------------
|
|
1 file changed, 29 insertions(+), 21 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 9d04939..c1b659d 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -498,12 +498,13 @@ class Plugin(object):
|
|
self._add_copy_paths(copy_paths)
|
|
self._log_info("added copyspec '%s'" % copy_paths)
|
|
|
|
- def get_command_output(self, prog, timeout=300, runat=None, stderr=True):
|
|
- if self.commons['cmdlineopts'].chroot == 'always':
|
|
+ def get_command_output(self, prog, timeout=300, stderr=True,
|
|
+ chroot=True, runat=None):
|
|
+ if chroot or self.commons['cmdlineopts'].chroot == 'always':
|
|
root = self.sysroot
|
|
else:
|
|
root = None
|
|
- result = sos_get_command_output(prog, timeout=timeout, stderr=stderr
|
|
+ result = sos_get_command_output(prog, timeout=timeout, stderr=stderr,
|
|
chroot=root, chdir=runat)
|
|
if result['status'] == 124:
|
|
self._log_warn("command '%s' timed out after %ds"
|
|
@@ -513,12 +514,13 @@ class Plugin(object):
|
|
self._log_debug("could not run '%s': command not found" % prog)
|
|
return result
|
|
|
|
- def call_ext_prog(self, prog, timeout=300, runat=None, stderr=True):
|
|
+ def call_ext_prog(self, prog, timeout=300, stderr=True,
|
|
+ chroot=True, runat=None):
|
|
"""Execute a command independantly of the output gathering part of
|
|
sosreport.
|
|
"""
|
|
- return self.get_command_output(prog, timeout=timeout, runat=runat,
|
|
- stderr=True)
|
|
+ return self.get_command_output(prog, timeout=timeout, stderr=stderr,
|
|
+ chroot=chroot, runat=runat)
|
|
|
|
def check_ext_prog(self, prog):
|
|
"""Execute a command independently of the output gathering part of
|
|
@@ -528,8 +530,8 @@ class Plugin(object):
|
|
return self.call_ext_prog(prog)['status'] == 0
|
|
|
|
def add_cmd_output(self, cmds, suggest_filename=None,
|
|
- root_symlink=None, timeout=300, runat=None,
|
|
- stderr=True):
|
|
+ root_symlink=None, timeout=300, stderr=True,
|
|
+ chroot=True, runat=None):
|
|
"""Run a program or a list of programs and collect the output"""
|
|
if isinstance(cmds, six.string_types):
|
|
cmds = [cmds]
|
|
@@ -537,9 +539,10 @@ class Plugin(object):
|
|
self._log_warn("ambiguous filename or symlink for command list")
|
|
for cmd in cmds:
|
|
cmdt = (
|
|
- cmd, suggest_filename, root_symlink, timeout, runat, stderr
|
|
+ cmd, suggest_filename, root_symlink, timeout, stderr,
|
|
+ chroot, runat
|
|
)
|
|
- _tuplefmt = "('%s', '%s', '%s', %s, '%s', '%s')"
|
|
+ _tuplefmt = "('%s', '%s', '%s', %s, '%s', '%s', '%s')"
|
|
_logstr = "packed command tuple: " + _tuplefmt
|
|
self._log_debug(_logstr % cmdt)
|
|
self.collect_cmds.append(cmdt)
|
|
@@ -594,14 +597,14 @@ class Plugin(object):
|
|
self._log_debug("added string '%s' as '%s'" % (content, filename))
|
|
|
|
def get_cmd_output_now(self, exe, suggest_filename=None,
|
|
- root_symlink=False, timeout=300,
|
|
- runat=None, stderr=True):
|
|
+ root_symlink=False, timeout=300, stderr=True,
|
|
+ chroot=True, runat=None):
|
|
"""Execute a command and save the output to a file for inclusion in the
|
|
report.
|
|
"""
|
|
start = time()
|
|
- result = self.get_command_output(exe, timeout=timeout, runat=runat,
|
|
- stderr=stderr)
|
|
+ result = self.get_command_output(exe, timeout=timeout, stderr=stderr,
|
|
+ chroot=chroot, runat=runat)
|
|
# 126 means 'found but not executable'
|
|
if result['status'] == 126 or result['status'] == 127:
|
|
return None
|
|
@@ -650,15 +653,20 @@ class Plugin(object):
|
|
|
|
def _collect_cmd_output(self):
|
|
for progs in zip(self.collect_cmds):
|
|
- (prog, suggest_filename, root_symlink, timeout, runat, stderr
|
|
- ) = progs[0]
|
|
- self._log_debug("unpacked command tuple: "
|
|
- + "('%s', '%s', '%s', %s, '%s', %s)" % progs[0])
|
|
+ (
|
|
+ prog,
|
|
+ suggest_filename, root_symlink,
|
|
+ timeout,
|
|
+ stderr,
|
|
+ chroot, runat
|
|
+ ) = progs[0]
|
|
+ self._log_debug("unpacked command tuple: " +
|
|
+ "('%s', '%s', '%s', %s, '%s', '%s', '%s')" %
|
|
+ progs[0])
|
|
self._log_info("collecting output of '%s'" % prog)
|
|
self.get_cmd_output_now(prog, suggest_filename=suggest_filename,
|
|
- root_symlink=root_symlink,
|
|
- timeout=timeout, runat=runat,
|
|
- stderr=stderr)
|
|
+ root_symlink=root_symlink, timeout=timeout,
|
|
+ chroot=chroot, runat=runat)
|
|
|
|
def _collect_strings(self):
|
|
for string, file_name in self.copy_strings:
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 3390d070b2945715a15f74462c511df2b2941ef5 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 23:08:37 +0000
|
|
Subject: [PATCH 11/38] [plugin] add tmp_in_sysroot() method
|
|
|
|
Add a method that plugins can test to determine whether the
|
|
archive's temporary directory is inside sysroot. This is always
|
|
true when sysroot is '/'. When sysroot is a subdirectory of root
|
|
the temporary directory may be inaccessible from the chroot
|
|
namespace. Plugins can test this method to determine where to
|
|
write output.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 4 ++++
|
|
1 file changed, 4 insertions(+)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index c1b659d..49f62bf 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -169,6 +169,10 @@ class Plugin(object):
|
|
def use_sysroot(self):
|
|
return self.sysroot != os.path.abspath(os.sep)
|
|
|
|
+ def tmp_in_sysroot(self):
|
|
+ paths = [self.sysroot, self.archive.get_tmp_dir()]
|
|
+ return os.path.commonprefix(paths) == self.sysroot
|
|
+
|
|
def is_installed(self, package_name):
|
|
'''Is the package $package_name installed?'''
|
|
return self.policy().pkg_by_name(package_name) is not None
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 5ae1b392d1f081bcb43e91a572342d6f02e4728d Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Sun, 25 Jan 2015 23:27:51 +0000
|
|
Subject: [PATCH 12/38] [plugin] enforce forbidden paths when --sysroot is set
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 10 +++++++---
|
|
1 file changed, 7 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 49f62bf..fd1acb5 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -317,6 +317,8 @@ class Plugin(object):
|
|
return None
|
|
|
|
def _is_forbidden_path(self, path):
|
|
+ if self.use_sysroot():
|
|
+ path = self.join_sysroot(path)
|
|
return _path_in_path_list(path, self.forbidden_paths)
|
|
|
|
def _copy_node(self, path, st):
|
|
@@ -379,13 +381,15 @@ class Plugin(object):
|
|
'symlink': "no"
|
|
})
|
|
|
|
- def add_forbidden_path(self, forbiddenPath):
|
|
+ def add_forbidden_path(self, forbidden):
|
|
"""Specify a path to not copy, even if it's part of a copy_specs[]
|
|
entry.
|
|
"""
|
|
+ if self.use_sysroot():
|
|
+ forbidden = self.join_sysroot(forbidden)
|
|
# Glob case handling is such that a valid non-glob is a reduced glob
|
|
- for filespec in glob.glob(forbiddenPath):
|
|
- self.forbidden_paths.append(filespec)
|
|
+ for path in glob.glob(forbidden):
|
|
+ self.forbidden_paths.append(path)
|
|
|
|
def get_all_options(self):
|
|
"""return a list of all options selected"""
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From e18d25a0e0c10a2702893f7bae2530dc2a41a394 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:00:08 +0000
|
|
Subject: [PATCH 13/38] [cluster] handle crm_report with --sysroot
|
|
|
|
Don't attempt to run crm_report in the chroot if tmp is not a
|
|
subdirectory of sysroot.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/cluster.py | 5 +++--
|
|
1 file changed, 3 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/plugins/cluster.py b/sos/plugins/cluster.py
|
|
index ea5dbae..f52f154 100644
|
|
--- a/sos/plugins/cluster.py
|
|
+++ b/sos/plugins/cluster.py
|
|
@@ -120,8 +120,9 @@ class Cluster(Plugin, RedHatPlugin):
|
|
self._log_warn("scrubbing of crm passwords has been disabled:")
|
|
self._log_warn("data collected by crm_report may contain"
|
|
" sensitive values.")
|
|
- self.add_cmd_output('crm_report %s -S -d --dest %s --from "%s"'
|
|
- % (crm_scrub, crm_dest, crm_from))
|
|
+ self.add_cmd_output('crm_report %s -S -d --dest %s --from "%s"' %
|
|
+ (crm_scrub, crm_dest, crm_from),
|
|
+ chroot=self.tmp_in_sysroot())
|
|
|
|
def do_lockdump(self):
|
|
if self._mount_debug():
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 2ca9c74454699ba6ecad21d6b0c0809333d729aa Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:02:35 +0000
|
|
Subject: [PATCH 14/38] [dmraid] don't chroot if tmp is not inside sysroot
|
|
|
|
To dump metadata dmraid needs to chdir to the temporary archive
|
|
directory. Don't attempt to chroot into sysroot if the temporary
|
|
directory is not a subdirectory of it.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/dmraid.py | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/dmraid.py b/sos/plugins/dmraid.py
|
|
index b7c0b42..87381a0 100644
|
|
--- a/sos/plugins/dmraid.py
|
|
+++ b/sos/plugins/dmraid.py
|
|
@@ -39,6 +39,7 @@ class Dmraid(Plugin, RedHatPlugin, DebianPlugin, UbuntuPlugin):
|
|
self.add_cmd_output("dmraid -%s" % (opt,))
|
|
if self.get_option("metadata"):
|
|
metadata_path = self.get_cmd_output_path("metadata")
|
|
- self.add_cmd_output("dmraid -rD", runat=metadata_path)
|
|
+ self.add_cmd_output("dmraid -rD", runat=metadata_path,
|
|
+ chroot=self.tmp_in_sysroot())
|
|
|
|
# vim: et ts=4 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 4ae09ee0ed25d771cc6cc8a013837ed4c647b3ed Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:04:15 +0000
|
|
Subject: [PATCH 15/38] [foreman] don't chroot if tmp is not inside sysroot
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/foreman.py | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/foreman.py b/sos/plugins/foreman.py
|
|
index 9d1cbad..363b9d6 100644
|
|
--- a/sos/plugins/foreman.py
|
|
+++ b/sos/plugins/foreman.py
|
|
@@ -27,7 +27,9 @@ class Foreman(Plugin, RedHatPlugin):
|
|
|
|
def setup(self):
|
|
cmd = "foreman-debug"
|
|
+
|
|
path = self.get_cmd_output_path(name="foreman-debug")
|
|
- self.add_cmd_output("%s -g -q -a -d %s" % (cmd, path))
|
|
+ self.add_cmd_output("%s -g -q -a -d %s" % (cmd, path),
|
|
+ chroot=self.tmp_in_sysroot())
|
|
|
|
# vim: et ts=4 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 78761114ea9cc1b33233db2186a5ff762e1ac2f2 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:07:12 +0000
|
|
Subject: [PATCH 16/38] [libvirt] use join_sysroot() before calling
|
|
os.path.exists
|
|
|
|
The libvirt plugin tests for the presence of files. Use
|
|
join_sysroot() to ensure the correct path is tested.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/libvirt.py | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/libvirt.py b/sos/plugins/libvirt.py
|
|
index aaf862b..295c8eb 100644
|
|
--- a/sos/plugins/libvirt.py
|
|
+++ b/sos/plugins/libvirt.py
|
|
@@ -56,7 +56,7 @@ class Libvirt(Plugin, RedHatPlugin, UbuntuPlugin, DebianPlugin):
|
|
else:
|
|
self.add_copy_spec("/var/log/libvirt")
|
|
|
|
- if os.path.exists(libvirt_keytab):
|
|
+ if os.path.exists(self.join_sysroot(libvirt_keytab)):
|
|
self.add_cmd_output("klist -ket %s" % libvirt_keytab)
|
|
|
|
self.add_cmd_output("ls -lR /var/lib/libvirt/qemu")
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From b34ea0c6ea5449bbd2f4f9624e1644dc01b07e9d Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:09:11 +0000
|
|
Subject: [PATCH 17/38] [logs] fix do_regex_find_all() use for --sysroot
|
|
|
|
The logs plugin searches syslog configuration files. When using
|
|
--sysroot the plugin needs to use join_sysroot() to open the
|
|
correct path.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/logs.py | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/sos/plugins/logs.py b/sos/plugins/logs.py
|
|
index 2f86acc..7957898 100644
|
|
--- a/sos/plugins/logs.py
|
|
+++ b/sos/plugins/logs.py
|
|
@@ -38,12 +38,12 @@ class Logs(Plugin):
|
|
])
|
|
|
|
if self.get_option('all_logs'):
|
|
- logs = self.do_regex_find_all("^\S+\s+(-?\/.*$)\s+",
|
|
- "/etc/syslog.conf")
|
|
+ syslog_conf = self.join_sysroot("/etc/syslog.conf")
|
|
+ logs = self.do_regex_find_all("^\S+\s+(-?\/.*$)\s+", syslog_conf)
|
|
if self.is_installed("rsyslog") \
|
|
or os.path.exists("/etc/rsyslog.conf"):
|
|
logs += self.do_regex_find_all("^\S+\s+(-?\/.*$)\s+",
|
|
- "/etc/rsyslog.conf")
|
|
+ rsyslog_conf)
|
|
for i in logs:
|
|
if i.startswith("-"):
|
|
i = i[1:]
|
|
@@ -74,7 +74,7 @@ class RedHatLogs(Logs, RedHatPlugin):
|
|
messages = "/var/log/messages"
|
|
self.add_copy_spec_limit("/var/log/secure*", sizelimit=self.limit)
|
|
self.add_copy_spec_limit(messages + "*", sizelimit=self.limit)
|
|
- # collect five days worth of logs by default if the system is
|
|
+ # collect three days worth of logs by default if the system is
|
|
# configured to use the journal and not /var/log/messages
|
|
if not os.path.exists(messages) and self.is_installed("systemd"):
|
|
try:
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 534eb7fe732ec366292ec582ec2891ef0648ffcb Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:11:15 +0000
|
|
Subject: [PATCH 18/38] [lvm2] don't chroot if tmp is not inside sysroot
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/lvm2.py | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/lvm2.py b/sos/plugins/lvm2.py
|
|
index dd10fa7..c626231 100644
|
|
--- a/sos/plugins/lvm2.py
|
|
+++ b/sos/plugins/lvm2.py
|
|
@@ -37,7 +37,7 @@ class Lvm2(Plugin, RedHatPlugin, DebianPlugin, UbuntuPlugin):
|
|
lvmdump_opts = "-a -m"
|
|
cmd = lvmdump_cmd % (lvmdump_opts,
|
|
self.get_cmd_output_path(name="lvmdump"))
|
|
- self.add_cmd_output(cmd)
|
|
+ self.add_cmd_output(cmd, chroot=self.tmp_in_sysroot())
|
|
|
|
def setup(self):
|
|
# use locking_type 0 (no locks) when running LVM2 commands,
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From f4218ff5bab93908ca3d0804c9d837bdfa57f654 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 00:37:32 +0000
|
|
Subject: [PATCH 19/38] [docs] add --chroot to sosreport.1
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
man/en/sosreport.1 | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/man/en/sosreport.1 b/man/en/sosreport.1
|
|
index b0a86f2..f36f845 100644
|
|
--- a/man/en/sosreport.1
|
|
+++ b/man/en/sosreport.1
|
|
@@ -13,6 +13,7 @@ sosreport \- Collect and package diagnostic and support data
|
|
[--batch] [--build] [--debug]\fR
|
|
[--name name] [--case-id id] [--ticket-number nr]
|
|
[-s|--sysroot]\fR
|
|
+ [-c|--chroot {auto|always|never}\fR
|
|
[--tmp-dir directory]\fR
|
|
[-p|--profile profile-name]\fR
|
|
[--list-profiles]\fR
|
|
@@ -77,6 +78,13 @@ Specify alternate configuration file.
|
|
Specify an alternate root file system path. Useful for collecting
|
|
reports from containers and images.
|
|
.TP
|
|
+.B \-c, \--chroot {auto|always|never}
|
|
+Set the chroot mode. When \--sysroot is used commands default to
|
|
+executing with SYSROOT as the root directory (unless disabled by
|
|
+a specific plugin). This can be overriden by setting \--chroot to
|
|
+"always" (alwyas chroot) or "never" (always run in the host
|
|
+namespace).
|
|
+.TP
|
|
.B \--tmp-dir DIRECTORY
|
|
Specify alternate temporary directory to copy data as well as the
|
|
compressed report.
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From fb1b4a8b6793611ed91f43f6d3553351c704f50f Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 14:57:01 +0000
|
|
Subject: [PATCH 20/38] [plugin] handle ELOOP in _copy_dir()
|
|
|
|
A problem with systemd's management of the binfmt_misc automount
|
|
point in Atomic environments causes attempts to access this path to
|
|
fail with ELOOP:
|
|
|
|
>>> import os
|
|
>>> os.listdir("/host/proc/sys/fs/binfmt_misc/")
|
|
Traceback (most recent call last):
|
|
File "<stdin>", line 1, in <module>
|
|
OSError: [Errno 2] No such file or directory: '/host/proc/sys/fs/binfmt_misc/'
|
|
|
|
For reasons that are not yet clear this causes the entire sos
|
|
process to immediately terminate.
|
|
|
|
For now avoid the problem by enclosing the problem os.listdir in
|
|
a try/except block that explicitly handles the one errno value
|
|
implicated here.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 16 ++++++++++++----
|
|
1 file changed, 12 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index fd1acb5..b206470 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -27,6 +27,7 @@ import stat
|
|
from time import time
|
|
import logging
|
|
import fnmatch
|
|
+import errno
|
|
|
|
# PYCOMPAT
|
|
import six
|
|
@@ -303,10 +304,17 @@ class Plugin(object):
|
|
'pointsto': linkdest})
|
|
|
|
def _copy_dir(self, srcpath):
|
|
- for afile in os.listdir(srcpath):
|
|
- self._log_debug("recursively adding '%s' from '%s'"
|
|
- % (afile, srcpath))
|
|
- self._do_copy_path(os.path.join(srcpath, afile), dest=None)
|
|
+ try:
|
|
+ for afile in os.listdir(srcpath):
|
|
+ self._log_debug("recursively adding '%s' from '%s'"
|
|
+ % (afile, srcpath))
|
|
+ self._do_copy_path(os.path.join(srcpath, afile), dest=None)
|
|
+ except OSError as e:
|
|
+ if e.errno == errno.ELOOP:
|
|
+ msg = "Too many levels of symbolic links copying"
|
|
+ self._log_error("_copy_dir: %s '%s'" % (msg, srcpath))
|
|
+ return
|
|
+ raise e
|
|
|
|
def _get_dest_for_srcpath(self, srcpath):
|
|
if self.use_sysroot():
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 2c1af0457b668acb99129ed1f6dedcf7cdaa0eea Mon Sep 17 00:00:00 2001
|
|
From: Neependra Khare <nkhare@redhat.com>
|
|
Date: Mon, 26 Jan 2015 15:04:07 +0000
|
|
Subject: [PATCH 21/38] [kubernetes] new plugin
|
|
|
|
Add a plugin for Kubernetes support.
|
|
|
|
Signed-off-by: Neependra Khare <nkhare@redhat.com>
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/kubernetes.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++
|
|
1 file changed, 46 insertions(+)
|
|
create mode 100644 sos/plugins/kubernetes.py
|
|
|
|
diff --git a/sos/plugins/kubernetes.py b/sos/plugins/kubernetes.py
|
|
new file mode 100644
|
|
index 0000000..af3f3a6
|
|
--- /dev/null
|
|
+++ b/sos/plugins/kubernetes.py
|
|
@@ -0,0 +1,46 @@
|
|
+# Copyright (C) 2014 Red Hat, Inc. Neependra Khare <nkhare@redhat.com>
|
|
+# Copyright (C) 2014 Red Hat, Inc. Bryn M. Reeves <bmr@redhat.com>
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation; either version 2 of the License, or
|
|
+# (at your option) any later version.
|
|
+
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program; if not, write to the Free Software
|
|
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
+
|
|
+from sos.plugins import Plugin, RedHatPlugin
|
|
+
|
|
+
|
|
+class kubernetes(Plugin, RedHatPlugin):
|
|
+
|
|
+ """Kubernetes plugin
|
|
+ """
|
|
+
|
|
+ def setup(self):
|
|
+ self.add_copy_spec("/etc/kubernetes")
|
|
+ self.add_copy_spec("/etc/etcd")
|
|
+ self.add_copy_spec("/var/run/flannel")
|
|
+
|
|
+ # Kubernetes master info
|
|
+ self.add_cmd_output("kubectl version")
|
|
+ self.add_cmd_output("kubectl get -o json pods")
|
|
+ self.add_cmd_output("kubectl get -o json minions")
|
|
+ self.add_cmd_output("kubectl get -o json replicationController")
|
|
+ self.add_cmd_output("kubectl get -o json events")
|
|
+ self.add_cmd_output("journalctl -r -u kubelet")
|
|
+
|
|
+ # etcd
|
|
+ self.add_cmd_output("curl http://127.0.0.1:4001/version")
|
|
+ self.add_cmd_output("curl http://127.0.0.1:4001/v2/members")
|
|
+ self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/leader")
|
|
+ self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/self")
|
|
+ self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/store")
|
|
+
|
|
+
|
|
+# vim: et ts=5 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 550dda69c6c5d527498ad928a29c466fad4e250e Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 17:32:35 +0000
|
|
Subject: [PATCH 22/38] [docs] fix documentation of --sysroot parameter
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
man/en/sosreport.1 | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/man/en/sosreport.1 b/man/en/sosreport.1
|
|
index f36f845..eac9047 100644
|
|
--- a/man/en/sosreport.1
|
|
+++ b/man/en/sosreport.1
|
|
@@ -12,7 +12,7 @@ sosreport \- Collect and package diagnostic and support data
|
|
[--no-report] [--config-file conf]\fR
|
|
[--batch] [--build] [--debug]\fR
|
|
[--name name] [--case-id id] [--ticket-number nr]
|
|
- [-s|--sysroot]\fR
|
|
+ [-s|--sysroot SYSROOT]\fR
|
|
[-c|--chroot {auto|always|never}\fR
|
|
[--tmp-dir directory]\fR
|
|
[-p|--profile profile-name]\fR
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From d7cf8535a3403fe6050e0905bef2b4429e595664 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 15:32:03 -0500
|
|
Subject: [PATCH 23/38] [utilities] add chroot support to shell_out()
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/utilities.py | 5 +++--
|
|
1 file changed, 3 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
index a82ac7c..6475619 100644
|
|
--- a/sos/utilities.py
|
|
+++ b/sos/utilities.py
|
|
@@ -186,11 +186,12 @@ def import_module(module_fqname, superclasses=None):
|
|
return modules
|
|
|
|
|
|
-def shell_out(cmd, timeout=30, runat=None):
|
|
+def shell_out(cmd, timeout=30, chroot=None, runat=None):
|
|
"""Shell out to an external command and return the output or the empty
|
|
string in case of error.
|
|
"""
|
|
- return sos_get_command_output(cmd, timeout=timeout, chdir=runat)['output']
|
|
+ return sos_get_command_output(cmd, timeout=timeout,
|
|
+ chroot=chroot, chdir=runat)['output']
|
|
|
|
|
|
class ImporterHelper(object):
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From a1a1fd6cfcdb62d7af7744bb5710a2c7d5b4262a Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 15:33:18 -0500
|
|
Subject: [PATCH 24/38] [policies] make PackageManager and Policy sysroot-aware
|
|
|
|
Add methods to Policy to get the host root file system path and
|
|
to test if sos is running in a container and allow Policy classes
|
|
to pass a chroot path into the PackageManager constructor in order
|
|
to obtain package data from the chroot.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/policies/__init__.py | 22 ++++++++++++++++++++--
|
|
1 file changed, 20 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
|
|
index 4657614..cea4c09 100644
|
|
--- a/sos/policies/__init__.py
|
|
+++ b/sos/policies/__init__.py
|
|
@@ -57,11 +57,14 @@ class PackageManager(object):
|
|
|
|
query_command = None
|
|
timeout = 30
|
|
+ chroot = None
|
|
|
|
- def __init__(self, query_command=None):
|
|
+ def __init__(self, query_command=None, chroot=None):
|
|
self.packages = {}
|
|
if query_command:
|
|
self.query_command = query_command
|
|
+ if chroot:
|
|
+ self.chroot = chroot
|
|
|
|
def all_pkgs_by_name(self, name):
|
|
"""
|
|
@@ -93,7 +96,11 @@ class PackageManager(object):
|
|
version': 'major.minor.version'}}
|
|
"""
|
|
if self.query_command:
|
|
- pkg_list = shell_out(self.query_command, self.timeout).splitlines()
|
|
+ cmd = self.query_command
|
|
+ pkg_list = shell_out(
|
|
+ cmd, timeout=self.timeout, chroot=self.chroot
|
|
+ ).splitlines()
|
|
+
|
|
for pkg in pkg_list:
|
|
if '|' not in pkg:
|
|
continue
|
|
@@ -145,6 +152,9 @@ No changes will be made to system configuration.
|
|
vendor_text = ""
|
|
PATH = ""
|
|
|
|
+ _in_container = False
|
|
+ _host_sysroot = '/'
|
|
+
|
|
def __init__(self):
|
|
"""Subclasses that choose to override this initializer should call
|
|
super() to ensure that they get the required platform bits attached.
|
|
@@ -180,6 +190,14 @@ No changes will be made to system configuration.
|
|
"""
|
|
return False
|
|
|
|
+ def in_container(self):
|
|
+ """ Returns True if sos is running inside a container environment.
|
|
+ """
|
|
+ return self._in_container
|
|
+
|
|
+ def host_sysroot(self):
|
|
+ return self._host_sysroot
|
|
+
|
|
def dist_version(self):
|
|
"""
|
|
Return the OS version
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 63805ed15d63ddfebb06cd03f96f310bbf60d3b2 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 15:36:40 -0500
|
|
Subject: [PATCH 25/38] [policies] add container support to Red Hat policy
|
|
|
|
Check for the presence of container-specific environment variables
|
|
and set _host_sysroot if present:
|
|
|
|
container_uuid=UUID
|
|
HOST=/path
|
|
|
|
If both a container environment variable and HOST are present run
|
|
the PackageManager query command in a chroot.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/policies/redhat.py | 23 +++++++++++++++++++++--
|
|
1 file changed, 21 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py
|
|
index d2f8db0..f1db8ac 100644
|
|
--- a/sos/policies/redhat.py
|
|
+++ b/sos/policies/redhat.py
|
|
@@ -38,13 +38,17 @@ class RedHatPolicy(LinuxPolicy):
|
|
vendor = "Red Hat"
|
|
vendor_url = "http://www.redhat.com/"
|
|
_tmp_dir = "/var/tmp"
|
|
+ _rpmq_cmd = 'rpm -qa --queryformat "%{NAME}|%{VERSION}\\n"'
|
|
+ _in_container = False
|
|
+ _host_sysroot = '/'
|
|
|
|
def __init__(self):
|
|
super(RedHatPolicy, self).__init__()
|
|
self.report_name = ""
|
|
self.ticket_number = ""
|
|
- self.package_manager = PackageManager(
|
|
- 'rpm -qa --queryformat "%{NAME}|%{VERSION}\\n"')
|
|
+ # need to set _host_sysroot before PackageManager()
|
|
+ sysroot = self._container_init()
|
|
+ self.package_manager = PackageManager(self._rpmq_cmd, chroot=sysroot)
|
|
self.valid_subclasses = [RedHatPlugin]
|
|
|
|
pkgs = self.package_manager.all_pkgs()
|
|
@@ -70,6 +74,17 @@ class RedHatPolicy(LinuxPolicy):
|
|
Fedora, RHEL or other Red Hat distribution or False otherwise."""
|
|
return False
|
|
|
|
+ def _container_init(self):
|
|
+ """Check if sos is running in a container and if a host sysroot
|
|
+ has been passed in the environment.
|
|
+ """
|
|
+ if ENV_CONTAINER_UUID in os.environ:
|
|
+ self._in_container = True
|
|
+ if ENV_HOST_SYSROOT in os.environ:
|
|
+ self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
+ use_sysroot = self._in_container and self._host_sysroot != '/'
|
|
+ return self._host_sysroot if use_sysroot else None
|
|
+
|
|
def runlevel_by_service(self, name):
|
|
from subprocess import Popen, PIPE
|
|
ret = []
|
|
@@ -100,6 +115,10 @@ class RedHatPolicy(LinuxPolicy):
|
|
def get_local_name(self):
|
|
return self.host_name()
|
|
|
|
+# Container environment variables on Red Hat systems.
|
|
+ENV_CONTAINER_UUID = 'container_uuid'
|
|
+ENV_HOST_SYSROOT = 'HOST'
|
|
+
|
|
|
|
class RHELPolicy(RedHatPolicy):
|
|
distro = "Red Hat Enterprise Linux"
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From f8a1746a871e560e548d21f1fc68067d452140a0 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 15:39:16 -0500
|
|
Subject: [PATCH 26/38] [sosreport] set SYSROOT by policy
|
|
|
|
If --sysroot is not given on the command line and
|
|
Policy.in_container() is True set sysroot automatically if
|
|
Policy.get_host_sysroot() is not '/'.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 13 ++++++++++---
|
|
1 file changed, 10 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index a0b89e7..835d828 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -648,7 +648,7 @@ class SoSOptions(object):
|
|
help="Disable HTML/XML reporting", default=False)
|
|
parser.add_option("-s", "--sysroot", action="store", dest="sysroot",
|
|
help="system root directory path (default='/')",
|
|
- default="/")
|
|
+ default=None)
|
|
parser.add_option("-c", "--chroot", action="store", dest="chroot",
|
|
help="chroot executed commands to SYSROOT "
|
|
"[auto, always, never] (default=auto)",
|
|
@@ -705,11 +705,18 @@ class SoSReport(object):
|
|
self.tempfile_util = TempFileUtil(self.tmpdir)
|
|
self._set_directories()
|
|
|
|
+ self._setup_logging()
|
|
+
|
|
+ msg = "default"
|
|
+ host_sysroot = self.policy.host_sysroot()
|
|
# set alternate system root directory
|
|
if self.opts.sysroot:
|
|
+ msg = "cmdline"
|
|
self.sysroot = self.opts.sysroot
|
|
-
|
|
- self._setup_logging()
|
|
+ elif self.policy.in_container() and host_sysroot != os.sep:
|
|
+ msg = "policy"
|
|
+ self.sysroot = host_sysroot
|
|
+ self.soslog.debug("set sysroot to '%s' (%s)" % (self.sysroot, msg))
|
|
|
|
if self.opts.chroot not in chroot_modes:
|
|
self.soslog.error("invalid chroot mode: %s" % self.opts.chroot)
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From fac57721ae10dafec909c4fac408f42ebe23d4ac Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 16:14:01 -0500
|
|
Subject: [PATCH 27/38] [firewalld] work around command hangs in container
|
|
environments
|
|
|
|
Add a 10s timeout to firewalld-cmd execution to avoid long dbus
|
|
timeouts in docker containers.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/firewalld.py | 4 +++-
|
|
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/firewalld.py b/sos/plugins/firewalld.py
|
|
index 98d011b..8eeb2b6 100644
|
|
--- a/sos/plugins/firewalld.py
|
|
+++ b/sos/plugins/firewalld.py
|
|
@@ -35,9 +35,11 @@ class FirewallD(Plugin, RedHatPlugin):
|
|
"/etc/sysconfig/firewalld"
|
|
])
|
|
|
|
+ # use a 10s timeout to workaround dbus problems in
|
|
+ # docker containers.
|
|
self.add_cmd_output([
|
|
"firewall-cmd --list-all-zones",
|
|
"firewall-cmd --permanent --list-all-zones"
|
|
- ])
|
|
+ ], timeout=10)
|
|
|
|
# vim: et ts=4 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 6a239ddeb5de9a04e7e7081ea6425d89dddda3f5 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Mon, 26 Jan 2015 17:13:24 -0500
|
|
Subject: [PATCH 28/38] [policies] pass --sysroot down to policy classes
|
|
|
|
Policies that don't auto-detect a container environment with a
|
|
host file system need to pass the value of --sysroot down to the
|
|
PackageManager class in order to obtain package details from the
|
|
chroot environment.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/policies/__init__.py | 11 ++++++-----
|
|
sos/policies/debian.py | 4 ++--
|
|
sos/policies/redhat.py | 18 +++++++++++-------
|
|
sos/policies/ubuntu.py | 4 ++--
|
|
sos/sosreport.py | 2 +-
|
|
5 files changed, 22 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
|
|
index cea4c09..a403bb9 100644
|
|
--- a/sos/policies/__init__.py
|
|
+++ b/sos/policies/__init__.py
|
|
@@ -28,7 +28,7 @@ def import_policy(name):
|
|
return None
|
|
|
|
|
|
-def load(cache={}):
|
|
+def load(cache={}, sysroot=None):
|
|
if 'policy' in cache:
|
|
return cache.get('policy')
|
|
|
|
@@ -37,7 +37,7 @@ def load(cache={}):
|
|
for module in helper.get_modules():
|
|
for policy in import_policy(module):
|
|
if policy.check():
|
|
- cache['policy'] = policy()
|
|
+ cache['policy'] = policy(sysroot=sysroot)
|
|
|
|
if 'policy' not in cache:
|
|
cache['policy'] = GenericPolicy()
|
|
@@ -155,7 +155,7 @@ No changes will be made to system configuration.
|
|
_in_container = False
|
|
_host_sysroot = '/'
|
|
|
|
- def __init__(self):
|
|
+ def __init__(self, sysroot=None):
|
|
"""Subclasses that choose to override this initializer should call
|
|
super() to ensure that they get the required platform bits attached.
|
|
super(SubClass, self).__init__(). Policies that require runtime
|
|
@@ -167,6 +167,7 @@ No changes will be made to system configuration.
|
|
self.package_manager = PackageManager()
|
|
self._valid_subclasses = []
|
|
self.set_exec_path()
|
|
+ self._host_sysroot = sysroot
|
|
|
|
def get_valid_subclasses(self):
|
|
return [IndependentPlugin] + self._valid_subclasses
|
|
@@ -372,8 +373,8 @@ class LinuxPolicy(Policy):
|
|
vendor = "None"
|
|
PATH = "/bin:/sbin:/usr/bin:/usr/sbin"
|
|
|
|
- def __init__(self):
|
|
- super(LinuxPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(LinuxPolicy, self).__init__(sysroot=sysroot)
|
|
|
|
def get_preferred_hash_algorithm(self):
|
|
checksum = "md5"
|
|
diff --git a/sos/policies/debian.py b/sos/policies/debian.py
|
|
index acb5b85..e56e546 100644
|
|
--- a/sos/policies/debian.py
|
|
+++ b/sos/policies/debian.py
|
|
@@ -16,8 +16,8 @@ class DebianPolicy(LinuxPolicy):
|
|
PATH = "/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" \
|
|
+ ":/usr/local/sbin:/usr/local/bin"
|
|
|
|
- def __init__(self):
|
|
- super(DebianPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(DebianPolicy, self).__init__(sysroot=sysroot)
|
|
self.report_name = ""
|
|
self.ticket_number = ""
|
|
self.package_manager = PackageManager(
|
|
diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py
|
|
index f1db8ac..f20359d 100644
|
|
--- a/sos/policies/redhat.py
|
|
+++ b/sos/policies/redhat.py
|
|
@@ -42,12 +42,16 @@ class RedHatPolicy(LinuxPolicy):
|
|
_in_container = False
|
|
_host_sysroot = '/'
|
|
|
|
- def __init__(self):
|
|
- super(RedHatPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(RedHatPolicy, self).__init__(sysroot=sysroot)
|
|
self.report_name = ""
|
|
self.ticket_number = ""
|
|
# need to set _host_sysroot before PackageManager()
|
|
- sysroot = self._container_init()
|
|
+ if sysroot:
|
|
+ self._container_init()
|
|
+ self._host_sysroot = sysroot
|
|
+ else:
|
|
+ sysroot = self._container_init()
|
|
self.package_manager = PackageManager(self._rpmq_cmd, chroot=sysroot)
|
|
self.valid_subclasses = [RedHatPlugin]
|
|
|
|
@@ -145,8 +149,8 @@ No changes will be made to system configuration.
|
|
%(vendor_text)s
|
|
""")
|
|
|
|
- def __init__(self):
|
|
- super(RHELPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(RHELPolicy, self).__init__(sysroot=sysroot)
|
|
|
|
@classmethod
|
|
def check(self):
|
|
@@ -192,8 +196,8 @@ class FedoraPolicy(RedHatPolicy):
|
|
vendor = "the Fedora Project"
|
|
vendor_url = "https://fedoraproject.org/"
|
|
|
|
- def __init__(self):
|
|
- super(FedoraPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(FedoraPolicy, self).__init__(sysroot=sysroot)
|
|
|
|
@classmethod
|
|
def check(self):
|
|
diff --git a/sos/policies/ubuntu.py b/sos/policies/ubuntu.py
|
|
index 0dd2ea2..f236421 100644
|
|
--- a/sos/policies/ubuntu.py
|
|
+++ b/sos/policies/ubuntu.py
|
|
@@ -9,8 +9,8 @@ class UbuntuPolicy(DebianPolicy):
|
|
vendor = "Ubuntu"
|
|
vendor_url = "http://www.ubuntu.com/"
|
|
|
|
- def __init__(self):
|
|
- super(UbuntuPolicy, self).__init__()
|
|
+ def __init__(self, sysroot=None):
|
|
+ super(UbuntuPolicy, self).__init__(sysroot=sysroot)
|
|
self.valid_subclasses = [UbuntuPlugin, DebianPlugin]
|
|
|
|
@classmethod
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index 835d828..ad13a2d 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -687,7 +687,7 @@ class SoSReport(object):
|
|
self._read_config()
|
|
|
|
try:
|
|
- self.policy = sos.policies.load()
|
|
+ self.policy = sos.policies.load(sysroot=self.opts.sysroot)
|
|
except KeyboardInterrupt:
|
|
self._exit(0)
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From d34bf4982f8a627901f6538be3b9e52cc30fe91b Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Tue, 27 Jan 2015 11:40:06 +0000
|
|
Subject: [PATCH 29/38] [sosoptions] ensure '_sysroot' and '_chroot' are
|
|
initialised
|
|
|
|
Make sure the sysroot and chroot members of the SoSOptions object
|
|
are initialised to prevent exceptions when these are not set on
|
|
the command line:
|
|
|
|
sosreport
|
|
Traceback (most recent call last):
|
|
File "/usr/sbin/sosreport", line 25, in <module>
|
|
main(sys.argv[1:])
|
|
File "/usr/lib/python2.7/site-packages/sos/sosreport.py", line 1490, in main
|
|
sos = SoSReport(args)
|
|
File "/usr/lib/python2.7/site-packages/sos/sosreport.py", line 673, in __init__
|
|
self.policy = sos.policies.load(sysroot=self.opts.sysroot)
|
|
File "/usr/lib/python2.7/site-packages/sos/policies/__init__.py", line 40, in load
|
|
cache['policy'] = policy(sysroot=sysroot)
|
|
File "/usr/lib/python2.7/site-packages/sos/policies/redhat.py", line 192, in __init__
|
|
super(FedoraPolicy, self).__init__(sysroot=sysroot)
|
|
File "/usr/lib/python2.7/site-packages/sos/policies/redhat.py", line 58, in __init__
|
|
if self.package_manager.all_pkgs()['filesystem']['version'][0] == '3':
|
|
File "/usr/lib/python2.7/site-packages/sos/policies/__init__.py", line 116, in all_pkgs
|
|
self.packages = self.get_pkg_list()
|
|
File "/usr/lib/python2.7/site-packages/sos/policies/__init__.py", line 99, in get_pkg_list
|
|
pkg_list = shell_out(cmd, chroot=self.chroot).splitlines()
|
|
File "/usr/lib/python2.7/site-packages/sos/utilities.py", line 191, in shell_out
|
|
return sos_get_command_output(cmd, chroot=chroot, chdir=runat)['output']
|
|
File "/usr/lib/python2.7/site-packages/sos/utilities.py", line 156, in sos_get_command_output
|
|
raise e
|
|
OSError: [Errno 1] Operation not permitted: '/'
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/sosreport.py | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index ad13a2d..27c756f 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -251,6 +251,8 @@ class SoSOptions(object):
|
|
_config_file = ""
|
|
_tmp_dir = ""
|
|
_report = True
|
|
+ _sysroot = None
|
|
+ _chroot = 'auto'
|
|
_compression_type = 'auto'
|
|
|
|
_options = None
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From c0858c2c87f246283f6c59b7bf7f64f7dea73a82 Mon Sep 17 00:00:00 2001
|
|
From: Neependra Khare <nkhare@redhat.com>
|
|
Date: Tue, 27 Jan 2015 15:54:23 +0000
|
|
Subject: [PATCH 30/38] [etcd] split etcd functionality from kubernetes into
|
|
new plugin
|
|
|
|
Signed-off-by: Neependra Khare <nkhare@redhat.com>
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/etcd.py | 36 ++++++++++++++++++++++++++++++++++++
|
|
sos/plugins/kubernetes.py | 8 --------
|
|
2 files changed, 36 insertions(+), 8 deletions(-)
|
|
create mode 100644 sos/plugins/etcd.py
|
|
|
|
diff --git a/sos/plugins/etcd.py b/sos/plugins/etcd.py
|
|
new file mode 100644
|
|
index 0000000..69edca0
|
|
--- /dev/null
|
|
+++ b/sos/plugins/etcd.py
|
|
@@ -0,0 +1,36 @@
|
|
+# Copyright (C) 2015 Red Hat, Inc. Neependra Khare <nkhare@redhat.com>
|
|
+# Copyright (C) 2015 Red Hat, Inc. Bryn M. Reeves <bmr@redhat.com>
|
|
+# This program is free software; you can redistribute it and/or modify
|
|
+# it under the terms of the GNU General Public License as published by
|
|
+# the Free Software Foundation; either version 2 of the License, or
|
|
+# (at your option) any later version.
|
|
+
|
|
+# This program is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU General Public License for more details.
|
|
+
|
|
+# You should have received a copy of the GNU General Public License
|
|
+# along with this program; if not, write to the Free Software
|
|
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
+
|
|
+from sos.plugins import Plugin, RedHatPlugin
|
|
+
|
|
+
|
|
+class etcd(Plugin, RedHatPlugin):
|
|
+
|
|
+ """etcd plugin
|
|
+ """
|
|
+
|
|
+ def setup(self):
|
|
+ self.add_copy_spec("/etc/etcd")
|
|
+
|
|
+ self.add_cmd_output("curl http://localhost:4001/version")
|
|
+ self.add_cmd_output("curl http://localhost:4001/v2/members")
|
|
+ self.add_cmd_output("curl http://localhost:4001/v2/stats/leader")
|
|
+ self.add_cmd_output("curl http://localhost:4001/v2/stats/self")
|
|
+ self.add_cmd_output("curl http://localhost:4001/v2/stats/store")
|
|
+ self.add_cmd_output("ls -lR /var/lib/etcd/")
|
|
+
|
|
+
|
|
+# vim: et ts=5 sw=4
|
|
diff --git a/sos/plugins/kubernetes.py b/sos/plugins/kubernetes.py
|
|
index af3f3a6..289d784 100644
|
|
--- a/sos/plugins/kubernetes.py
|
|
+++ b/sos/plugins/kubernetes.py
|
|
@@ -24,7 +24,6 @@ class kubernetes(Plugin, RedHatPlugin):
|
|
|
|
def setup(self):
|
|
self.add_copy_spec("/etc/kubernetes")
|
|
- self.add_copy_spec("/etc/etcd")
|
|
self.add_copy_spec("/var/run/flannel")
|
|
|
|
# Kubernetes master info
|
|
@@ -35,12 +34,5 @@ class kubernetes(Plugin, RedHatPlugin):
|
|
self.add_cmd_output("kubectl get -o json events")
|
|
self.add_cmd_output("journalctl -r -u kubelet")
|
|
|
|
- # etcd
|
|
- self.add_cmd_output("curl http://127.0.0.1:4001/version")
|
|
- self.add_cmd_output("curl http://127.0.0.1:4001/v2/members")
|
|
- self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/leader")
|
|
- self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/self")
|
|
- self.add_cmd_output("curl http://127.0.0.1:4001/v2/stats/store")
|
|
-
|
|
|
|
# vim: et ts=5 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 2ddc706c7219d0b891304fcb066dea865f8516b5 Mon Sep 17 00:00:00 2001
|
|
From: Neependra Khare <nkhare@redhat.com>
|
|
Date: Tue, 27 Jan 2015 15:58:32 +0000
|
|
Subject: [PATCH 31/38] [kubernetes] add services and pod logs collection
|
|
|
|
Signed-off-by: Neependra Khare <nkhare@redhat.com>
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/kubernetes.py | 12 ++++++++++++
|
|
1 file changed, 12 insertions(+)
|
|
|
|
diff --git a/sos/plugins/kubernetes.py b/sos/plugins/kubernetes.py
|
|
index 289d784..9c2df5e 100644
|
|
--- a/sos/plugins/kubernetes.py
|
|
+++ b/sos/plugins/kubernetes.py
|
|
@@ -22,6 +22,8 @@ class kubernetes(Plugin, RedHatPlugin):
|
|
"""Kubernetes plugin
|
|
"""
|
|
|
|
+ option_list = [("podslog", "capture logs for pods", 'slow', False)]
|
|
+
|
|
def setup(self):
|
|
self.add_copy_spec("/etc/kubernetes")
|
|
self.add_copy_spec("/var/run/flannel")
|
|
@@ -30,9 +32,19 @@ class kubernetes(Plugin, RedHatPlugin):
|
|
self.add_cmd_output("kubectl version")
|
|
self.add_cmd_output("kubectl get -o json pods")
|
|
self.add_cmd_output("kubectl get -o json minions")
|
|
+ self.add_cmd_output("kubectl get -o json services")
|
|
self.add_cmd_output("kubectl get -o json replicationController")
|
|
self.add_cmd_output("kubectl get -o json events")
|
|
self.add_cmd_output("journalctl -r -u kubelet")
|
|
|
|
+ if self.get_option('podslog'):
|
|
+ result = self.get_command_output("kubectl get pods")
|
|
+ if result['status'] == 0:
|
|
+ for line in result['output'].splitlines()[1:]:
|
|
+ pod_name = line.split(" ")[0]
|
|
+ self.add_cmd_output([
|
|
+ "{0} log {1}".format("kubectl", pod_name)
|
|
+ ])
|
|
+
|
|
|
|
# vim: et ts=5 sw=4
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 259897b60b0e4ee00585a8d73521fa4e291eb8da Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Tue, 27 Jan 2015 12:54:31 -0500
|
|
Subject: [PATCH 32/38] [policies/redhat] automatically set tmp_dir in
|
|
containers
|
|
|
|
Now that policies have the infrastructure to detect that they
|
|
are running in a container and to use the HOST environment
|
|
variable if present enable automatic setting of self._tmp_dir in
|
|
appriate container environments.
|
|
|
|
This causes reports to be automatically written to $HOST/var/tmp
|
|
when $HOST is set while still allowing users to override the tmp
|
|
path manually by specificying --tmp-dir=PATH.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/policies/redhat.py | 7 +++++--
|
|
1 file changed, 5 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py
|
|
index f20359d..3cf40b3 100644
|
|
--- a/sos/policies/redhat.py
|
|
+++ b/sos/policies/redhat.py
|
|
@@ -79,14 +79,17 @@ class RedHatPolicy(LinuxPolicy):
|
|
return False
|
|
|
|
def _container_init(self):
|
|
- """Check if sos is running in a container and if a host sysroot
|
|
- has been passed in the environment.
|
|
+ """Check if sos is running in a container and perform container
|
|
+ specific initialisation based on ENV_HOST_SYSROOT.
|
|
"""
|
|
if ENV_CONTAINER_UUID in os.environ:
|
|
self._in_container = True
|
|
if ENV_HOST_SYSROOT in os.environ:
|
|
self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
use_sysroot = self._in_container and self._host_sysroot != '/'
|
|
+ if use_sysroot:
|
|
+ host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
|
+ self._tmp_dir = host_tmp_dir
|
|
return self._host_sysroot if use_sysroot else None
|
|
|
|
def runlevel_by_service(self, name):
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From b880c6cb4668815b97841e6532450144a5f825f1 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Tue, 27 Jan 2015 13:53:34 -0500
|
|
Subject: [PATCH 33/38] [policies/redhat] add Red Hat Atomic Host policy
|
|
|
|
Add a new policy for the Red Hat Atomic Host.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/policies/redhat.py | 39 ++++++++++++++++++++++++++++++++++++++-
|
|
1 file changed, 38 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py
|
|
index 3cf40b3..9decd0a 100644
|
|
--- a/sos/policies/redhat.py
|
|
+++ b/sos/policies/redhat.py
|
|
@@ -37,6 +37,7 @@ class RedHatPolicy(LinuxPolicy):
|
|
distro = "Red Hat"
|
|
vendor = "Red Hat"
|
|
vendor_url = "http://www.redhat.com/"
|
|
+ _redhat_release = '/etc/redhat-release'
|
|
_tmp_dir = "/var/tmp"
|
|
_rpmq_cmd = 'rpm -qa --queryformat "%{NAME}|%{VERSION}\\n"'
|
|
_in_container = False
|
|
@@ -159,7 +160,7 @@ No changes will be made to system configuration.
|
|
def check(self):
|
|
"""This method checks to see if we are running on RHEL. It returns True
|
|
or False."""
|
|
- return (os.path.isfile('/etc/redhat-release')
|
|
+ return (os.path.isfile(self._redhat_release)
|
|
and not os.path.isfile('/etc/fedora-release'))
|
|
|
|
def dist_version(self):
|
|
@@ -193,6 +194,42 @@ No changes will be made to system configuration.
|
|
return self.rhn_username() or self.host_name()
|
|
|
|
|
|
+class RedHatAtomicPolicy(RHELPolicy):
|
|
+ distro = "Red Hat Atomic Host"
|
|
+ msg = _("""\
|
|
+This command will collect diagnostic and configuration \
|
|
+information from this %(distro)s system.
|
|
+
|
|
+An archive containing the collected information will be \
|
|
+generated in %(tmpdir)s and may be provided to a %(vendor)s \
|
|
+support representative.
|
|
+
|
|
+Any information provided to %(vendor)s will be treated in \
|
|
+accordance with the published support policies at:\n
|
|
+ %(vendor_url)s
|
|
+
|
|
+The generated archive may contain data considered sensitive \
|
|
+and its content should be reviewed by the originating \
|
|
+organization before being passed to any third party.
|
|
+%(vendor_text)s
|
|
+""")
|
|
+
|
|
+ @classmethod
|
|
+ def check(self):
|
|
+ atomic = False
|
|
+ if ENV_HOST_SYSROOT not in os.environ:
|
|
+ return atomic
|
|
+ host_release = os.environ[ENV_HOST_SYSROOT] + self._redhat_release
|
|
+ if not os.path.exists(host_release):
|
|
+ return False
|
|
+ try:
|
|
+ for line in open(host_release, "r").read().splitlines():
|
|
+ atomic |= 'Atomic' in line
|
|
+ except:
|
|
+ pass
|
|
+ return atomic
|
|
+
|
|
+
|
|
class FedoraPolicy(RedHatPolicy):
|
|
|
|
distro = "Fedora"
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From cd0d5c1f06a69c115e674f87254cc7e056c9891a Mon Sep 17 00:00:00 2001
|
|
From: Jeremy Eder <jeder@redhat.com>
|
|
Date: Wed, 28 Jan 2015 12:54:14 +0000
|
|
Subject: [PATCH 34/38] [docker] add 'docker' to the package list for Red Hat
|
|
distros
|
|
|
|
The docker package is named 'docker-io' in Fedora and 'docker'
|
|
in RHEL and other downstream products. Add the 'docker' name to
|
|
the package list in RedHatDocker to ensure the plugin runs.
|
|
|
|
Signed-off-by: Jeremy Eder <jeder@redhat.com>
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/docker.py | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/docker.py b/sos/plugins/docker.py
|
|
index 3e5bd4a..c5ea8a0 100644
|
|
--- a/sos/plugins/docker.py
|
|
+++ b/sos/plugins/docker.py
|
|
@@ -54,7 +54,7 @@ class Docker(Plugin):
|
|
|
|
class RedHatDocker(Docker, RedHatPlugin):
|
|
|
|
- packages = ('docker-io',)
|
|
+ packages = ('docker', 'docker-io')
|
|
|
|
def setup(self):
|
|
super(RedHatDocker, self).setup()
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From d4ae63afbf211a7234b7605bef037d827263bf70 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Wed, 28 Jan 2015 22:54:48 +0000
|
|
Subject: [PATCH 35/38] [plugins] automatically re-try chroot'ed commands in
|
|
the host
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 12 +++++++++++-
|
|
sos/utilities.py | 5 +----
|
|
2 files changed, 12 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index b206470..7fa7ac6 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -520,13 +520,23 @@ class Plugin(object):
|
|
root = self.sysroot
|
|
else:
|
|
root = None
|
|
+
|
|
result = sos_get_command_output(prog, timeout=timeout, stderr=stderr,
|
|
chroot=root, chdir=runat)
|
|
+
|
|
if result['status'] == 124:
|
|
self._log_warn("command '%s' timed out after %ds"
|
|
% (prog, timeout))
|
|
- # 126 means 'found but not executable'
|
|
+
|
|
+ # command not found or not runnable
|
|
if result['status'] == 126 or result['status'] == 127:
|
|
+ # automatically retry chroot'ed commands in the host namespace
|
|
+ if chroot and self.commons['cmdlineopts'].chroot != 'always':
|
|
+ self._log_info("command '%s' not found in %s - "
|
|
+ "re-trying in host root"
|
|
+ % (prog.split()[0], root))
|
|
+ return self.get_command_output(prog, timeout=timeout,
|
|
+ chroot=False, runat=runat)
|
|
self._log_debug("could not run '%s': command not found" % prog)
|
|
return result
|
|
|
|
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
index 6475619..d3a1048 100644
|
|
--- a/sos/utilities.py
|
|
+++ b/sos/utilities.py
|
|
@@ -151,16 +151,13 @@ def sos_get_command_output(command, timeout=300, stderr=False,
|
|
stderr=STDOUT if stderr else PIPE,
|
|
bufsize=-1, env=cmd_env, close_fds=True,
|
|
preexec_fn=_child_prep_fn)
|
|
+ stdout, stderr = p.communicate()
|
|
except OSError as e:
|
|
if e.errno == errno.ENOENT:
|
|
return {'status': 127, 'output': ""}
|
|
else:
|
|
raise e
|
|
|
|
- stdout, stderr = p.communicate()
|
|
-
|
|
- # Required hack while we still pass shell=True to Popen; a Popen
|
|
- # call with shell=False for a non-existant binary will raise OSError.
|
|
if p.returncode == 126 or p.returncode == 127:
|
|
stdout = six.binary_type(b"")
|
|
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 6fe240a31c01d63957ce548f4415ca55859dc071 Mon Sep 17 00:00:00 2001
|
|
From: Neependra Khare <nkhare@redhat.com>
|
|
Date: Thu, 29 Jan 2015 18:23:53 +0000
|
|
Subject: [PATCH 36/38] [kubernetes] add journal output for kube services
|
|
|
|
Add journalctl output for the following kubernetes units:
|
|
|
|
kube-apiserver
|
|
kube-controller-manager
|
|
kube-scheduler
|
|
kube-proxy
|
|
|
|
Signed-off-by: Neependra Khare <nkhare@redhat.com>
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/kubernetes.py | 4 ++++
|
|
1 file changed, 4 insertions(+)
|
|
|
|
diff --git a/sos/plugins/kubernetes.py b/sos/plugins/kubernetes.py
|
|
index 9c2df5e..38faeb2 100644
|
|
--- a/sos/plugins/kubernetes.py
|
|
+++ b/sos/plugins/kubernetes.py
|
|
@@ -36,6 +36,10 @@ class kubernetes(Plugin, RedHatPlugin):
|
|
self.add_cmd_output("kubectl get -o json replicationController")
|
|
self.add_cmd_output("kubectl get -o json events")
|
|
self.add_cmd_output("journalctl -r -u kubelet")
|
|
+ self.add_cmd_output("journalctl -r -u kube-apiserver")
|
|
+ self.add_cmd_output("journalctl -r -u kube-controller-manager")
|
|
+ self.add_cmd_output("journalctl -r -u kube-scheduler")
|
|
+ self.add_cmd_output("journalctl -r -u kube-proxy")
|
|
|
|
if self.get_option('podslog'):
|
|
result = self.get_command_output("kubectl get pods")
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 8d69d74a5be6dac29fad2ab5d7206a0485969924 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Thu, 29 Jan 2015 20:30:31 +0000
|
|
Subject: [PATCH 37/38] [plugins] do not strip SYSROOT when copying link
|
|
targets
|
|
|
|
The abspath() call in _copy_symlink returns a host-relative path
|
|
(when SYSROOT is not '/'). Pass this directly to _do_copy_path()
|
|
without stripping the SYSROOT path component.
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 3 ++-
|
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index 7fa7ac6..a7c0146 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -265,7 +265,8 @@ class Plugin(object):
|
|
# the target stored in the original symlink
|
|
linkdest = os.readlink(srcpath)
|
|
dest = os.path.join(os.path.dirname(srcpath), linkdest)
|
|
- # absolute path to the link target
|
|
+ # Absolute path to the link target. If SYSROOT != '/' this path
|
|
+ # is relative to the host root file system.
|
|
absdest = os.path.normpath(dest)
|
|
# adjust the target used inside the report to always be relative
|
|
if os.path.isabs(linkdest):
|
|
--
|
|
1.8.3.1
|
|
|
|
|
|
From 76c04a773f1927359d264f59e4fbcc9363424882 Mon Sep 17 00:00:00 2001
|
|
From: "Bryn M. Reeves" <bmr@redhat.com>
|
|
Date: Thu, 29 Jan 2015 22:00:10 +0000
|
|
Subject: [PATCH 38/38] [plugins] trim leading '../' from links when sysroot is
|
|
set
|
|
|
|
When SYSROOT is not '/' relative symlinks need to be trimmed to
|
|
remove the extra leading '../' returned by
|
|
abspath('/sysroot/...').
|
|
|
|
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 3 +++
|
|
sos/sosreport.py | 1 +
|
|
2 files changed, 4 insertions(+)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index a7c0146..a06c0b1 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -271,6 +271,9 @@ class Plugin(object):
|
|
# adjust the target used inside the report to always be relative
|
|
if os.path.isabs(linkdest):
|
|
reldest = os.path.relpath(linkdest, os.path.dirname(srcpath))
|
|
+ # trim leading /sysroot
|
|
+ if self.use_sysroot():
|
|
+ reldest = reldest[len(os.sep + os.pardir):]
|
|
self._log_debug("made link target '%s' relative as '%s'"
|
|
% (linkdest, reldest))
|
|
else:
|
|
diff --git a/sos/sosreport.py b/sos/sosreport.py
|
|
index 27c756f..567e3df 100644
|
|
--- a/sos/sosreport.py
|
|
+++ b/sos/sosreport.py
|
|
@@ -1226,6 +1226,7 @@ class SoSReport(object):
|
|
self.ui_log.error(" %s while setting up plugins"
|
|
% e.strerror)
|
|
self.ui_log.error("")
|
|
+ self._exit(1)
|
|
if self.raise_plugins:
|
|
raise
|
|
self._log_plugin_exception(plugname, "setup")
|
|
--
|
|
1.8.3.1
|
|
|
|
From bb6f546603d8e3199bda0bfe0f9b23f1da1cb8c9 Mon Sep 17 00:00:00 2001
|
|
From: Pavel Moravec <pmoravec@redhat.com>
|
|
Date: Mon, 13 Jul 2015 15:03:37 +0200
|
|
Subject: [PATCH] [plugin] pass stderr through _collect_cmd_output
|
|
|
|
Commit f06efd6 removed passing stderr in _collect_cmd_output to
|
|
get_cmd_output_now. That prevents passing stderr=False in several
|
|
scenarios.
|
|
|
|
This fix adds the argument to be passed back.
|
|
|
|
Resolves: #600
|
|
|
|
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
---
|
|
sos/plugins/__init__.py | 2 +-
|
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
|
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
|
|
index a06c0b1..aed7496 100644
|
|
--- a/sos/plugins/__init__.py
|
|
+++ b/sos/plugins/__init__.py
|
|
@@ -696,7 +696,7 @@ class Plugin(object):
|
|
self._log_info("collecting output of '%s'" % prog)
|
|
self.get_cmd_output_now(prog, suggest_filename=suggest_filename,
|
|
root_symlink=root_symlink, timeout=timeout,
|
|
- chroot=chroot, runat=runat)
|
|
+ stderr=stderr, chroot=chroot, runat=runat)
|
|
|
|
def _collect_strings(self):
|
|
for string, file_name in self.copy_strings:
|
|
--
|
|
1.8.3.1
|
|
|