aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake Hunsaker <jhunsake@redhat.com>2019-04-10 11:55:53 -0400
committerBryn M. Reeves <bmr@redhat.com>2019-05-14 11:25:01 +0100
commit762765cfabb1ac62864f6a0552f7eda46112f9e1 (patch)
tree9dfb76f8e8165e1c9f5b01c3012ea799e796abc0
parent877014bbfd85c02083a716212a5cbbe715f4b96a (diff)
downloadsos-762765cfabb1ac62864f6a0552f7eda46112f9e1.tar.gz
[Plugin] Allow plugins to capture environment variables
Adds a new 'add_env_var()' method to the Plugin class, which allows plugins to specify which environment variables should be recorded in the sos archive. This functions as a whitelist, as only environment variables requested by plugins will be captured. The new method accepts either a single string, or a list of strings. Collection of environment variables is done _after_ we have run collect() for each plugin, and will be written to the 'environment' file in the archive root. Only environment variables that exist will be written, so if a plugin requests an environment variable be captured and it does not appear in the file the chances are good that the variable is not set on the system. Each environment variable will only be captured once - so multiple plugins may specify the same environment variable without an issue. Additionally, when a plugin uses add_env_var(), the value passed as well as an upper- and lower- cased variant of the value will be added to the list of variables to be collected as well. This is because it is a frequent support issue where end users set an incorrectly-cased variable, and support representatives will want to know when this is the case. Because this functionality works off of a whitelist, environment variable values are not sanitized. Note also that due to the variable name casing functionality mentioned above, this means there is a small chance where sensitive data stored in differently-cased variables of the same name as common variables could be unintentionally captured. Use the --no-env-vars option to prevent capturing any environment variables wholesale. Fixes: #1396 Resolves: #1643 Signed-off-by: Jake Hunsaker <jhunsake@redhat.com> Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
-rw-r--r--sos/__init__.py9
-rw-r--r--sos/plugins/__init__.py16
-rw-r--r--sos/sosreport.py17
3 files changed, 38 insertions, 4 deletions
diff --git a/sos/__init__.py b/sos/__init__.py
index ed59025a..9cd71728 100644
--- a/sos/__init__.py
+++ b/sos/__init__.py
@@ -54,9 +54,9 @@ _arg_names = [
'chroot', 'compression_type', 'config_file', 'desc', 'debug', 'del_preset',
'dry_run', 'enableplugins', 'encrypt_key', 'encrypt_pass', 'experimental',
'label', 'list_plugins', 'list_presets', 'list_profiles', 'log_size',
- 'noplugins', 'noreport', 'note', 'onlyplugins', 'plugin_timeout',
- 'plugopts', 'preset', 'profiles', 'quiet', 'sysroot', 'threads', 'tmp_dir',
- 'verbosity', 'verify'
+ 'noplugins', 'noreport', 'no_env_vars', 'note', 'onlyplugins',
+ 'plugin_timeout', 'plugopts', 'preset', 'profiles', 'quiet', 'sysroot',
+ 'threads', 'tmp_dir', 'verbosity', 'verify'
]
#: Arguments with non-zero default values
@@ -179,6 +179,7 @@ class SoSOptions(object):
self.log_size = _arg_defaults["log_size"]
self.noplugins = []
self.noreport = False
+ self.no_env_vars = False
self.note = ""
self.onlyplugins = []
self.plugin_timeout = None
@@ -220,7 +221,7 @@ class SoSOptions(object):
no_value = (
"alloptions", "all-logs", "batch", "build", "debug",
"experimental", "list-plugins", "list-presets", "list-profiles",
- "noreport", "quiet", "verify"
+ "noreport", "no-env-vars", "quiet", "verify"
)
count = ("verbose",)
if opt in no_value:
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
index 09a90c7f..8fbceeb3 100644
--- a/sos/plugins/__init__.py
+++ b/sos/plugins/__init__.py
@@ -242,6 +242,7 @@ class Plugin(object):
self.copied_files = []
self.executed_commands = []
+ self._env_vars = set()
self.alerts = []
self.custom_text = ""
self.opt_names = []
@@ -969,6 +970,21 @@ class Plugin(object):
return outfn
+ def add_env_var(self, name):
+ """Add an environment variable to the list of to-be-collected env vars.
+
+ Accepts either a single variable name or a list of names. Any value
+ given will be added as provided to the method, as well as an upper-
+ and lower- cased version.
+ """
+ if not isinstance(name, list):
+ name = [name]
+ for env in name:
+ # get both upper and lower cased vars since a common support issue
+ # is setting the env vars to the wrong case, and if the plugin
+ # adds a mixed case variable name, still get that as well
+ self._env_vars.update([env, env.upper(), env.lower()])
+
def add_string_as_file(self, content, filename, pred=None):
"""Add a string to the archive as a file named `filename`"""
diff --git a/sos/sosreport.py b/sos/sosreport.py
index c13142c7..058868c7 100644
--- a/sos/sosreport.py
+++ b/sos/sosreport.py
@@ -180,6 +180,9 @@ def _get_parser():
parser.add_argument("--no-report", action="store_true",
dest="noreport",
help="disable plaintext/HTML reporting", default=False)
+ parser.add_argument("--no-env-vars", action="store_true", default=False,
+ dest="no_env_vars",
+ help="Do not collect environment variables")
parser.add_argument("--note", type=str, action="store", default="",
help="Behaviour notes for new preset")
parser.add_argument("-o", "--only-plugins", action="extend",
@@ -245,6 +248,7 @@ class SoSReport(object):
self.loaded_plugins = []
self.skipped_plugins = []
self.all_options = []
+ self.env_vars = set()
self.archive = None
self.tempfile_util = None
self._args = args
@@ -931,6 +935,7 @@ class SoSReport(object):
try:
plug.archive = self.archive
plug.setup()
+ self.env_vars.update(plug._env_vars)
if self.opts.verify:
plug.setup_verify()
except KeyboardInterrupt:
@@ -1062,6 +1067,16 @@ class SoSReport(object):
sys.stdout.write(status_line)
sys.stdout.flush()
+ def collect_env_vars(self):
+ if not self.env_vars:
+ return
+ env = '\n'.join([
+ "%s=%s" % (name, val) for (name, val) in
+ [(name, '%s' % os.environ.get(name)) for name in self.env_vars if
+ os.environ.get(name) is not None]
+ ]) + '\n'
+ self.archive.add_string(env, 'environment')
+
def plain_report(self):
report = Report()
@@ -1356,6 +1371,8 @@ class SoSReport(object):
self.prework()
self.setup()
self.collect()
+ if not self.opts.no_env_vars:
+ self.collect_env_vars()
if not self.opts.noreport:
self.html_report()
self.plain_report()