aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJake Hunsaker <jhunsake@redhat.com>2020-10-12 12:33:30 -0400
committerJake Hunsaker <jhunsake@redhat.com>2020-11-03 13:40:18 -0500
commit55ca9a849121b9058f8e0768eb4d4bef84db49ab (patch)
tree5951b559a6bc3acf88edd860bb9d32bd1740e52b
parenta5162c73ddd948085ca99fba81353104c54623de (diff)
downloadsos-55ca9a849121b9058f8e0768eb4d4bef84db49ab.tar.gz
[report] Allow users to specify commands and files to skip
Adds two new options, `--skip-commands` and `--skip-files`, that allow users to selectively skip specific command or file collection instead of having to disable whole plugins to skip those collections. These options are also exposed via `sos collect`, being gated by a version of 4.1 since that is the next scheduled release where we can guarantee this functionality will be present. Closes: #2203 Resolves: #2271 Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r--man/en/sos-collect.114
-rw-r--r--man/en/sos-report.114
-rw-r--r--sos/collector/__init__.py8
-rw-r--r--sos/collector/sosnode.py10
-rw-r--r--sos/report/__init__.py8
-rw-r--r--sos/report/plugins/__init__.py27
-rw-r--r--tests/option_tests.py2
-rw-r--r--tests/plugin_tests.py2
8 files changed, 85 insertions, 0 deletions
diff --git a/man/en/sos-collect.1 b/man/en/sos-collect.1
index 7d6f8b87..d4e5e648 100644
--- a/man/en/sos-collect.1
+++ b/man/en/sos-collect.1
@@ -30,6 +30,8 @@ sos collect \- Collect sosreports from multiple (cluster) nodes
[\-\-password]
[\-\-password\-per\-node]
[\-\-preset PRESET]
+ [\-\-skip-commands COMMANDS]
+ [\-\-skip-files FILES]
[\-s|\-\-sysroot SYSROOT]
[\-\-ssh\-user SSH_USER]
[\-\-sos-cmd SOS_CMD]
@@ -261,6 +263,18 @@ defined, or has a version of sos prior to 3.6, this option is ignored for that n
\fB\-p\fR SSH_PORT, \fB\-\-ssh\-port\fR SSH_PORT
Specify SSH port for all nodes. Use this if SSH runs on any port other than 22.
.TP
+\fB\-\-skip-commands\fR COMMANDS
+A comma delimited list of commands to skip execution of, but still allowing the
+rest of the plugin that calls the command to run. This will generally need to
+be some form of UNIX shell-style wildcard matching. For example, using a value
+of \fBhostname\fR will skip only that single command, while using \fBhostname*\fR
+will skip all commands with names that begin with the string "hostname".
+.TP
+\fB\-\-skip-files\fR FILES
+A comma delimited list of files or filepath wildcard matches to skip collection
+of. Values may either be exact filepaths or paths using UNIX shell-style wildcards,
+for example \fB/etc/sos/*\fR.
+.TP
\fB\-\-ssh\-user\fR SSH_USER
Specify an SSH user for sos collect to connect to nodes with. Default is root.
diff --git a/man/en/sos-report.1 b/man/en/sos-report.1
index 0a571d18..19fb6aae 100644
--- a/man/en/sos-report.1
+++ b/man/en/sos-report.1
@@ -26,6 +26,8 @@ sosreport \- Collect and package diagnostic and support data
[--log-size]\fR
[--all-logs]\fR
[--since YYYYMMDD[HHMMSS]]\fR
+ [--skip-commands commands]\fR
+ [--skip-files files]\fR
[--allow-system-changes]\fR
[-z|--compression-type method]\fR
[--encrypt-key KEY]\fR
@@ -180,6 +182,18 @@ compression-type file extension for example ".zip". ".1", ".gz" etc.).
This also affects \--all-logs. The date string will be padded with zeros
if HHMMSS is not specified.
.TP
+.B \--skip-commands COMMANDS
+A comma delimited list of commands to skip execution of, but still allowing the
+rest of the plugin that calls the command to run. This will generally need to
+be some form of UNIX shell-style wildcard matching. For example, using a value
+of \fBhostname\fR will skip only that single command, while using \fBhostname*\fR
+will skip all commands with names that begin with the string "hostname".
+.TP
+.B \--skip-files FILES
+A comma delimited list of files or filepath wildcard matches to skip collection
+of. Values may either be exact filepaths or paths using UNIX shell-style wildcards,
+for example \fB/etc/sos/*\fR.
+.TP
.B \--allow-system-changes
Run commands even if they can change the system (e.g. load kernel modules).
.TP
diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py
index 3390e0b0..1abb08ae 100644
--- a/sos/collector/__init__.py
+++ b/sos/collector/__init__.py
@@ -84,6 +84,8 @@ class SoSCollector(SoSComponent):
'preset': '',
'save_group': '',
'since': '',
+ 'skip_cmds': [],
+ 'skip_files': [],
'skip_plugins': [],
'sos_opt_line': '',
'ssh_key': '',
@@ -277,6 +279,12 @@ class SoSCollector(SoSComponent):
help=('Escapes archived files older than date. '
'This will also affect --all-logs. '
'Format: YYYYMMDD[HHMMSS]'))
+ sos_grp.add_argument('--skip-commands', default=[], action='extend',
+ dest='skip_cmds',
+ help="do not execute these commands")
+ sos_grp.add_argument('--skip-files', default=[], action='extend',
+ dest='skip_files',
+ help="do not collect these files")
sos_grp.add_argument('--verify', action="store_true",
help='perform pkg verification during collection')
diff --git a/sos/collector/sosnode.py b/sos/collector/sosnode.py
index d0e836a8..75daef22 100644
--- a/sos/collector/sosnode.py
+++ b/sos/collector/sosnode.py
@@ -651,6 +651,16 @@ class SosNode():
if self.check_sos_version('4.0'):
self.sos_bin = 'sos report'
+ if self.check_sos_version('4.1'):
+ if self.opts.skip_cmds:
+ sos_opts.append(
+ '--skip-commands=%s' % (quote(self.opts.skip_cmds))
+ )
+ if self.opts.skip_files:
+ sos_opts.append(
+ '--skip-files=%s' % (quote(self.opts.skip_files))
+ )
+
sos_cmd = sos_cmd.replace(
'sosreport',
os.path.join(self.host.sos_bin_path, self.sos_bin)
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
index a938f706..7838d60a 100644
--- a/sos/report/__init__.py
+++ b/sos/report/__init__.py
@@ -94,6 +94,8 @@ class SoSReport(SoSComponent):
'list_profiles': False,
'log_size': 25,
'map_file': '/etc/sos/cleaner/default_mapping',
+ 'skip_cmds': [],
+ 'skip_files': [],
'skip_plugins': [],
'noreport': False,
'no_env_vars': False,
@@ -258,6 +260,12 @@ class SoSReport(SoSComponent):
dest="profiles", type=str, default=[],
help="enable plugins used by the given "
"profiles")
+ report_grp.add_argument('--skip-commands', default=[], action='extend',
+ dest='skip_cmds',
+ help="do not execute these commands")
+ report_grp.add_argument('--skip-files', default=[], action='extend',
+ dest='skip_files',
+ help="do not collect these files")
report_grp.add_argument("--verify", action="store_true",
dest="verify", default=False,
help="perform data verification during "
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
index 4e1a263d..ed0a07ef 100644
--- a/sos/report/plugins/__init__.py
+++ b/sos/report/plugins/__init__.py
@@ -495,6 +495,8 @@ class Plugin(object):
self.policy = commons['policy']
self.devices = commons['devices']
self.manifest = None
+ self.skip_files = commons['cmdlineopts'].skip_files
+ self.skip_cmds = commons['cmdlineopts'].skip_cmds
self.soslog = self.commons['soslog'] if 'soslog' in self.commons \
else logging.getLogger('sos')
@@ -1080,6 +1082,20 @@ class Plugin(object):
def _is_forbidden_path(self, path):
return _path_in_path_list(path, self.forbidden_paths)
+ def _is_skipped_path(self, path):
+ """Check if the given path matches a user-provided specification to
+ ignore collection of via the ``--skip-files`` option
+
+ :param path: The filepath being collected
+ :type path: ``str``
+
+ :returns: ``True`` if file should be skipped, else ``False``
+ """
+ for _skip_path in self.skip_files:
+ if fnmatch.fnmatch(path, _skip_path):
+ return True
+ return False
+
def _copy_node(self, path, st):
dev_maj = os.major(st.st_rdev)
dev_min = os.minor(st.st_rdev)
@@ -1425,6 +1441,9 @@ class Plugin(object):
if self._is_forbidden_path(_file):
self._log_debug("skipping forbidden path '%s'" % _file)
continue
+ if self._is_skipped_path(_file):
+ self._log_debug("skipping excluded path '%s'" % _file)
+ continue
if limit_reached:
self._log_info("skipping '%s' over size limit" % _file)
continue
@@ -1577,6 +1596,14 @@ class Plugin(object):
pred = kwargs.pop('pred') if 'pred' in kwargs else None
soscmd = SoSCommand(**kwargs)
self._log_debug("packed command: " + soscmd.__str__())
+ for _skip_cmd in self.skip_cmds:
+ # This probably seems weird to be doing filename matching on the
+ # commands, however we want to remain consistent with our regex
+ # matching with file paths, which sysadmins are almost guaranteed
+ # to assume will use shell-style unix matching
+ if fnmatch.fnmatch(soscmd.cmd, _skip_cmd):
+ self._log_debug("skipping excluded command '%s'" % soscmd.cmd)
+ return
if self.test_predicate(cmd=True, pred=pred):
self.collect_cmds.append(soscmd)
self._log_info("added cmd output '%s'" % soscmd.cmd)
diff --git a/tests/option_tests.py b/tests/option_tests.py
index 56480a58..44e2079f 100644
--- a/tests/option_tests.py
+++ b/tests/option_tests.py
@@ -16,6 +16,8 @@ class MockOptions(object):
dry_run = False
log_size = 25
allow_system_changes = False
+ skip_cmds = []
+ skip_files = []
class GlobalOptionTest(unittest.TestCase):
diff --git a/tests/plugin_tests.py b/tests/plugin_tests.py
index 9290003a..0acf07f4 100644
--- a/tests/plugin_tests.py
+++ b/tests/plugin_tests.py
@@ -114,6 +114,8 @@ class MockOptions(object):
log_size = 25
allow_system_changes = False
no_postproc = False
+ skip_files = []
+ skip_cmds = []
class PluginToolTests(unittest.TestCase):