aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Moravec <pmoravec@redhat.com>2017-12-20 11:47:33 +0100
committerBryn M. Reeves <bmr@redhat.com>2018-04-16 16:27:05 +0100
commit8d830501000f382a48a762ecfbe0426f9345d90b (patch)
tree9801d3074ff6a03e99087e26e91372a7154df0e9
parent15d7237527fe26da95070b48e7aafd0597dc245f (diff)
downloadsos-8d830501000f382a48a762ecfbe0426f9345d90b.tar.gz
[plugins] allow add_cmd_output to collect binary output
If a command output is a true binary data, allow add_cmd_output to collect the raw content and dont try to decode it as UTF-8. Resolves: #1169 Closes: #1170 Signed-off-by: Pavel Moravec <pmoravec@redhat.com> Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
-rw-r--r--sos/archive.py11
-rw-r--r--sos/plugins/__init__.py49
-rw-r--r--sos/plugins/postgresql.py4
-rw-r--r--sos/utilities.py5
4 files changed, 49 insertions, 20 deletions
diff --git a/sos/archive.py b/sos/archive.py
index 607312a7..80e27b84 100644
--- a/sos/archive.py
+++ b/sos/archive.py
@@ -85,6 +85,9 @@ class Archive(object):
def add_string(self, content, dest):
raise NotImplementedError
+ def add_binary(self, content, dest):
+ raise NotImplementedError
+
def add_link(self, source, link_name):
raise NotImplementedError
@@ -215,6 +218,14 @@ class FileCacheArchive(Archive):
self.log_debug("added string at '%s' to FileCacheArchive '%s'"
% (src, self._archive_root))
+ def add_binary(self, content, dest):
+ dest = self.dest_path(dest)
+ self._check_path(dest)
+ f = codecs.open(dest, 'wb', encoding=None)
+ f.write(content)
+ self.log_debug("added binary content at '%s' to FileCacheArchive '%s'"
+ % (dest, self._archive_root))
+
def add_link(self, source, link_name):
dest = self.dest_path(link_name)
self._check_path(dest)
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
index 44502d05..98364da1 100644
--- a/sos/plugins/__init__.py
+++ b/sos/plugins/__init__.py
@@ -228,6 +228,10 @@ class Plugin(object):
for called in self.executed_commands:
if called['file'] is None:
continue
+ if called['binary'] == 'yes':
+ self._log_warn("Cannot apply regex substitution to binary"
+ " output: '%s'" % called['exe'])
+ continue
if fnmatch.fnmatch(called['exe'], globstr):
path = os.path.join(self.commons['cmddir'], called['file'])
readable = self.archive.open_file(path)
@@ -266,6 +270,10 @@ class Plugin(object):
# was anything collected?
if called['file'] is None:
continue
+ if called['binary'] == 'yes':
+ self._log_warn("Cannot apply regex substitution to binary"
+ " output: '%s'" % called['exe'])
+ continue
if fnmatch.fnmatch(called['exe'], globstr):
path = os.path.join(self.commons['cmddir'], called['file'])
self._log_debug("applying substitution to '%s'" % path)
@@ -593,7 +601,8 @@ class Plugin(object):
self.archive.add_link(link_path, _file)
def get_command_output(self, prog, timeout=300, stderr=True,
- chroot=True, runat=None, env=None):
+ chroot=True, runat=None, env=None,
+ binary=False):
if chroot or self.commons['cmdlineopts'].chroot == 'always':
root = self.sysroot
else:
@@ -601,7 +610,7 @@ class Plugin(object):
result = sos_get_command_output(prog, timeout=timeout, stderr=stderr,
chroot=root, chdir=runat,
- env=env)
+ env=env, binary=binary)
if result['status'] == 124:
self._log_warn("command '%s' timed out after %ds"
@@ -617,7 +626,8 @@ class Plugin(object):
% (prog.split()[0], root))
return self.get_command_output(prog, timeout=timeout,
chroot=False, runat=runat,
- env=env)
+ env=env,
+ binary=binary)
self._log_debug("could not run '%s': command not found" % prog)
return result
@@ -638,14 +648,14 @@ class Plugin(object):
def _add_cmd_output(self, cmd, suggest_filename=None,
root_symlink=None, timeout=300, stderr=True,
- chroot=True, runat=None, env=None):
+ chroot=True, runat=None, env=None, binary=False):
"""Internal helper to add a single command to the collection list."""
cmdt = (
cmd, suggest_filename,
root_symlink, timeout, stderr,
- chroot, runat, env
+ chroot, runat, env, binary
)
- _tuplefmt = "('%s', '%s', '%s', %s, '%s', '%s', '%s', '%s')"
+ _tuplefmt = "('%s', '%s', '%s', %s, '%s', '%s', '%s', '%s', '%s')"
_logstr = "packed command tuple: " + _tuplefmt
self._log_debug(_logstr % cmdt)
self.collect_cmds.append(cmdt)
@@ -653,7 +663,7 @@ class Plugin(object):
def add_cmd_output(self, cmds, suggest_filename=None,
root_symlink=None, timeout=300, stderr=True,
- chroot=True, runat=None, env=None):
+ chroot=True, runat=None, env=None, binary=False):
"""Run a program or a list of programs and collect the output"""
if isinstance(cmds, six.string_types):
cmds = [cmds]
@@ -662,7 +672,7 @@ class Plugin(object):
for cmd in cmds:
self._add_cmd_output(cmd, suggest_filename,
root_symlink, timeout, stderr,
- chroot, runat, env)
+ chroot, runat, env, binary)
def get_cmd_output_path(self, name=None, make=True):
"""Return a path into which this module should store collected
@@ -718,14 +728,15 @@ class Plugin(object):
def get_cmd_output_now(self, exe, suggest_filename=None,
root_symlink=False, timeout=300, stderr=True,
- chroot=True, runat=None, env=None):
+ chroot=True, runat=None, env=None,
+ binary=False):
"""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, stderr=stderr,
chroot=chroot, runat=runat,
- env=env)
+ env=env, binary=binary)
self._log_debug("collected output of '%s' in %s"
% (exe.split()[0], time() - start))
@@ -735,13 +746,17 @@ class Plugin(object):
outfn = self._make_command_filename(exe)
outfn_strip = outfn[len(self.commons['cmddir'])+1:]
- self.archive.add_string(result['output'], outfn)
+ if binary:
+ self.archive.add_binary(result['output'], outfn)
+ else:
+ self.archive.add_string(result['output'], outfn)
if root_symlink:
self.archive.add_link(outfn, root_symlink)
# save info for later
# save in our list
- self.executed_commands.append({'exe': exe, 'file': outfn_strip})
+ self.executed_commands.append({'exe': exe, 'file': outfn_strip,
+ 'binary': 'yes' if binary else 'no'})
self.commons['xmlreport'].add_command(cmdline=exe,
exitcode=result['status'],
f_stdout=outfn_strip)
@@ -850,16 +865,16 @@ class Plugin(object):
timeout,
stderr,
chroot, runat,
- env
+ env, binary
) = progs[0]
- self._log_debug("unpacked command tuple: " +
- "('%s', '%s', '%s', %s, '%s', '%s', '%s', '%s')" %
- progs[0])
+ self._log_debug(("unpacked command tuple: " +
+ "('%s', '%s', '%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,
stderr=stderr, chroot=chroot, runat=runat,
- env=env)
+ env=env, binary=binary)
def _collect_strings(self):
for string, file_name in self.copy_strings:
diff --git a/sos/plugins/postgresql.py b/sos/plugins/postgresql.py
index 3ddd46fc..d5d8e925 100644
--- a/sos/plugins/postgresql.py
+++ b/sos/plugins/postgresql.py
@@ -69,7 +69,9 @@ class PostgreSQL(Plugin):
if scl is not None:
cmd = self.convert_cmd_scl(scl, cmd)
- self.add_cmd_output(cmd, suggest_filename=filename)
+ self.add_cmd_output(cmd, suggest_filename=filename,
+ binary=True)
+
else: # no password in env or options
self.soslog.warning(
"password must be supplied to dump a database."
diff --git a/sos/utilities.py b/sos/utilities.py
index 55bb1dc9..b5aa571b 100644
--- a/sos/utilities.py
+++ b/sos/utilities.py
@@ -110,7 +110,8 @@ def is_executable(command):
def sos_get_command_output(command, timeout=300, stderr=False,
- chroot=None, chdir=None, env=None):
+ chroot=None, chdir=None, env=None,
+ binary=False):
"""Execute a command and return a dictionary of status and output,
optionally changing root or current working directory before
executing command.
@@ -164,7 +165,7 @@ def sos_get_command_output(command, timeout=300, stderr=False,
return {
'status': p.returncode,
- 'output': stdout.decode('utf-8', 'ignore')
+ 'output': stdout if binary else stdout.decode('utf-8', 'ignore')
}