diff options
author | Pavel Moravec <pmoravec@redhat.com> | 2017-12-20 11:47:33 +0100 |
---|---|---|
committer | Bryn M. Reeves <bmr@redhat.com> | 2018-04-16 16:27:05 +0100 |
commit | 8d830501000f382a48a762ecfbe0426f9345d90b (patch) | |
tree | 9801d3074ff6a03e99087e26e91372a7154df0e9 | |
parent | 15d7237527fe26da95070b48e7aafd0597dc245f (diff) | |
download | sos-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.py | 11 | ||||
-rw-r--r-- | sos/plugins/__init__.py | 49 | ||||
-rw-r--r-- | sos/plugins/postgresql.py | 4 | ||||
-rw-r--r-- | sos/utilities.py | 5 |
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') } |