aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryn M. Reeves <bmr@redhat.com>2015-01-23 23:17:34 +0000
committerBryn M. Reeves <bmr@redhat.com>2015-07-07 20:56:57 +0100
commitb1f3b3373e8ef3e94238760a3e7e78d95c564260 (patch)
tree8eb1d1ce9773f84739facf96cfbfb76bd38a2cf2
parent3eed62e132f67930bb1cf5c9eaa5927083011043 (diff)
downloadsos-b1f3b3373e8ef3e94238760a3e7e78d95c564260.tar.gz
[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>
-rw-r--r--sos/plugins/__init__.py50
-rw-r--r--tests/option_tests.py3
-rw-r--r--tests/plugin_tests.py57
3 files changed, 81 insertions, 29 deletions
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
index 413ee739..790338bc 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):
% linkdest)
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 fe37ccfe..e8a26e2d 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 e30ded5c..14d3b49c 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")