316 lines
14 KiB
Diff
316 lines
14 KiB
Diff
|
From 90b6b709e9f4002376b656b155d00d85382f1828 Mon Sep 17 00:00:00 2001
|
||
|
From: Pavel Moravec <pmoravec@redhat.com>
|
||
|
Date: Mon, 29 Mar 2021 16:23:01 +0200
|
||
|
Subject: [PATCH] [report] add --cmd-timeout option
|
||
|
|
||
|
Add --cmd-timeout option to configure command timeout. Plugin-specific
|
||
|
option of the same name (i.e. -k logs.cmd-timeout=60) can control the
|
||
|
timeout per plugin.
|
||
|
|
||
|
Option defaults and global/plugin-specific option preference follows the
|
||
|
--plugin-timeout rules.
|
||
|
|
||
|
Resolves: #2466
|
||
|
|
||
|
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
||
|
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||
|
---
|
||
|
man/en/sos-report.1 | 18 +++++++++-
|
||
|
sos/collector/__init__.py | 3 ++
|
||
|
sos/collector/sosnode.py | 5 +++
|
||
|
sos/options.py | 3 +-
|
||
|
sos/report/__init__.py | 5 ++-
|
||
|
sos/report/plugins/__init__.py | 63 ++++++++++++++++++++++++----------
|
||
|
6 files changed, 76 insertions(+), 21 deletions(-)
|
||
|
|
||
|
diff --git a/man/en/sos-report.1 b/man/en/sos-report.1
|
||
|
index 81005959..51cf3436 100644
|
||
|
--- a/man/en/sos-report.1
|
||
|
+++ b/man/en/sos-report.1
|
||
|
@@ -17,6 +17,7 @@ sosreport \- Collect and package diagnostic and support data
|
||
|
[--label label] [--case-id id]\fR
|
||
|
[--threads threads]\fR
|
||
|
[--plugin-timeout TIMEOUT]\fR
|
||
|
+ [--cmd-timeout TIMEOUT]\fR
|
||
|
[-s|--sysroot SYSROOT]\fR
|
||
|
[-c|--chroot {auto|always|never}\fR
|
||
|
[--tmp-dir directory]\fR
|
||
|
@@ -247,7 +248,7 @@ Specify a timeout in seconds to allow each plugin to run for. A value of 0
|
||
|
means no timeout will be set. A value of -1 is used to indicate the default
|
||
|
timeout of 300 seconds.
|
||
|
|
||
|
-Note that this options sets the timeout for all plugins. If you want to set
|
||
|
+Note that this option sets the timeout for all plugins. If you want to set
|
||
|
a timeout for a specific plugin, use the 'timeout' plugin option available to
|
||
|
all plugins - e.g. '-k logs.timeout=600'.
|
||
|
|
||
|
@@ -255,6 +256,21 @@ The plugin-specific timeout option will override this option. For example, using
|
||
|
\'--plugin-timeout=60 -k logs.timeout=600\' will set a timeout of 600 seconds for
|
||
|
the logs plugin and 60 seconds for all other enabled plugins.
|
||
|
.TP
|
||
|
+.B \--cmd-timeout TIMEOUT
|
||
|
+Specify a timeout limit in seconds for a command execution. Same defaults logic
|
||
|
+from --plugin-timeout applies here.
|
||
|
+
|
||
|
+This option sets the command timeout for all plugins. If you want to set a cmd
|
||
|
+timeout for a specific plugin, use the 'cmd-timeout' plugin option available to
|
||
|
+all plugins - e.g. '-k logs.cmd-timeout=600'.
|
||
|
+
|
||
|
+Again, the same plugin/global precedence logic as for --plugin-timeout applies
|
||
|
+here.
|
||
|
+
|
||
|
+Note that setting --cmd-timeout (or -k logs.cmd-timeout) high should be followed
|
||
|
+by increasing the --plugin-timeout equivalent, otherwise the plugin can easily
|
||
|
+timeout on slow commands execution.
|
||
|
+.TP
|
||
|
.B \--case-id NUMBER
|
||
|
Specify a case identifier to associate with the archive.
|
||
|
Identifiers may include alphanumeric characters, commas and periods ('.').
|
||
|
diff --git a/sos/collector/__init__.py b/sos/collector/__init__.py
|
||
|
index 406c8f35..1ae73508 100644
|
||
|
--- a/sos/collector/__init__.py
|
||
|
+++ b/sos/collector/__init__.py
|
||
|
@@ -82,6 +82,7 @@ class SoSCollector(SoSComponent):
|
||
|
'password_per_node': False,
|
||
|
'plugin_options': [],
|
||
|
'plugin_timeout': None,
|
||
|
+ 'cmd_timeout': None,
|
||
|
'preset': '',
|
||
|
'save_group': '',
|
||
|
'since': '',
|
||
|
@@ -276,6 +277,8 @@ class SoSCollector(SoSComponent):
|
||
|
help='Do not collect env vars in sosreports')
|
||
|
sos_grp.add_argument('--plugin-timeout', type=int, default=None,
|
||
|
help='Set the global plugin timeout value')
|
||
|
+ sos_grp.add_argument('--cmd-timeout', type=int, default=None,
|
||
|
+ help='Set the global command timeout value')
|
||
|
sos_grp.add_argument('--since', default=None,
|
||
|
help=('Escapes archived files older than date. '
|
||
|
'This will also affect --all-logs. '
|
||
|
diff --git a/sos/collector/sosnode.py b/sos/collector/sosnode.py
|
||
|
index a1679655..dbbee12e 100644
|
||
|
--- a/sos/collector/sosnode.py
|
||
|
+++ b/sos/collector/sosnode.py
|
||
|
@@ -664,6 +664,11 @@ class SosNode():
|
||
|
'--skip-files=%s' % (quote(self.opts.skip_files))
|
||
|
)
|
||
|
|
||
|
+ if self.check_sos_version('4.2'):
|
||
|
+ if self.opts.cmd_timeout:
|
||
|
+ sos_opts.append('--cmd-timeout=%s'
|
||
|
+ % quote(str(self.opts.cmd_timeout)))
|
||
|
+
|
||
|
sos_cmd = sos_cmd.replace(
|
||
|
'sosreport',
|
||
|
os.path.join(self.host.sos_bin_path, self.sos_bin)
|
||
|
diff --git a/sos/options.py b/sos/options.py
|
||
|
index b82a7d36..1eda55d6 100644
|
||
|
--- a/sos/options.py
|
||
|
+++ b/sos/options.py
|
||
|
@@ -283,7 +283,8 @@ class SoSOptions():
|
||
|
if name in ("add_preset", "del_preset", "desc", "note"):
|
||
|
return False
|
||
|
# Exception list for options that still need to be reported when 0
|
||
|
- if name in ['log_size', 'plugin_timeout'] and value == 0:
|
||
|
+ if name in ['log_size', 'plugin_timeout', 'cmd_timeout'] \
|
||
|
+ and value == 0:
|
||
|
return True
|
||
|
return has_value(name, value)
|
||
|
|
||
|
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
||
|
index 25478ba7..945d0fc1 100644
|
||
|
--- a/sos/report/__init__.py
|
||
|
+++ b/sos/report/__init__.py
|
||
|
@@ -107,6 +107,7 @@ class SoSReport(SoSComponent):
|
||
|
'only_plugins': [],
|
||
|
'preset': 'auto',
|
||
|
'plugin_timeout': 300,
|
||
|
+ 'cmd_timeout': 300,
|
||
|
'profiles': [],
|
||
|
'since': None,
|
||
|
'verify': False,
|
||
|
@@ -266,6 +267,8 @@ class SoSReport(SoSComponent):
|
||
|
help="A preset identifier", default="auto")
|
||
|
report_grp.add_argument("--plugin-timeout", default=None,
|
||
|
help="set a timeout for all plugins")
|
||
|
+ report_grp.add_argument("--cmd-timeout", default=None,
|
||
|
+ help="set a command timeout for all plugins")
|
||
|
report_grp.add_argument("-p", "--profile", "--profiles",
|
||
|
action="extend", dest="profiles", type=str,
|
||
|
default=[],
|
||
|
@@ -709,7 +712,7 @@ class SoSReport(SoSComponent):
|
||
|
|
||
|
self.ui_log.info(_("The following plugin options are available:"))
|
||
|
for (plug, plugname, optname, optparm) in self.all_options:
|
||
|
- if optname in ('timeout', 'postproc'):
|
||
|
+ if optname in ('timeout', 'postproc', 'cmd-timeout'):
|
||
|
continue
|
||
|
# format option value based on its type (int or bool)
|
||
|
if type(optparm["enabled"]) == bool:
|
||
|
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||
|
index 02625eb1..779119af 100644
|
||
|
--- a/sos/report/plugins/__init__.py
|
||
|
+++ b/sos/report/plugins/__init__.py
|
||
|
@@ -472,6 +472,9 @@ class Plugin(object):
|
||
|
_default_plug_opts = [
|
||
|
('timeout', 'Timeout in seconds for plugin. The default value (-1) ' +
|
||
|
'defers to the general plugin timeout, 300 seconds', 'fast', -1),
|
||
|
+ ('cmd-timeout', 'Timeout in seconds for a command execution. The ' +
|
||
|
+ 'default value (-1) defers to the general cmd timeout, 300 ' +
|
||
|
+ 'seconds', 'fast', -1),
|
||
|
('postproc', 'Enable post-processing collected plugin data', 'fast',
|
||
|
True)
|
||
|
]
|
||
|
@@ -532,16 +535,15 @@ class Plugin(object):
|
||
|
self.manifest.add_list('commands', [])
|
||
|
self.manifest.add_list('files', [])
|
||
|
|
||
|
- @property
|
||
|
- def timeout(self):
|
||
|
- """Returns either the default plugin timeout value, the value as
|
||
|
- provided on the commandline via -k plugin.timeout=value, or the value
|
||
|
- of the global --plugin-timeout option.
|
||
|
+ def timeout_from_options(self, optname, plugoptname, default_timeout):
|
||
|
+ """Returns either the default [plugin|cmd] timeout value, the value as
|
||
|
+ provided on the commandline via -k plugin.[|cmd-]timeout=value, or the
|
||
|
+ value of the global --[plugin|cmd]-timeout option.
|
||
|
"""
|
||
|
_timeout = None
|
||
|
try:
|
||
|
- opt_timeout = self.get_option('plugin_timeout')
|
||
|
- own_timeout = int(self.get_option('timeout'))
|
||
|
+ opt_timeout = self.get_option(optname)
|
||
|
+ own_timeout = int(self.get_option(plugoptname))
|
||
|
if opt_timeout is None:
|
||
|
_timeout = own_timeout
|
||
|
elif opt_timeout is not None and own_timeout == -1:
|
||
|
@@ -551,10 +553,30 @@ class Plugin(object):
|
||
|
else:
|
||
|
return None
|
||
|
except ValueError:
|
||
|
- return self.plugin_timeout # Default to known safe value
|
||
|
+ return default_timeout # Default to known safe value
|
||
|
if _timeout is not None and _timeout > -1:
|
||
|
return _timeout
|
||
|
- return self.plugin_timeout
|
||
|
+ return default_timeout
|
||
|
+
|
||
|
+ @property
|
||
|
+ def timeout(self):
|
||
|
+ """Returns either the default plugin timeout value, the value as
|
||
|
+ provided on the commandline via -k plugin.timeout=value, or the value
|
||
|
+ of the global --plugin-timeout option.
|
||
|
+ """
|
||
|
+ _timeout = self.timeout_from_options('plugin_timeout', 'timeout',
|
||
|
+ self.plugin_timeout)
|
||
|
+ return _timeout
|
||
|
+
|
||
|
+ @property
|
||
|
+ def cmdtimeout(self):
|
||
|
+ """Returns either the default command timeout value, the value as
|
||
|
+ provided on the commandline via -k plugin.cmd-timeout=value, or the
|
||
|
+ value of the global --cmd-timeout option.
|
||
|
+ """
|
||
|
+ _cmdtimeout = self.timeout_from_options('cmd_timeout', 'cmd-timeout',
|
||
|
+ self.cmd_timeout)
|
||
|
+ return _cmdtimeout
|
||
|
|
||
|
def set_timeout_hit(self):
|
||
|
self._timeout_hit = True
|
||
|
@@ -1235,8 +1257,8 @@ class Plugin(object):
|
||
|
"""
|
||
|
|
||
|
global_options = (
|
||
|
- 'all_logs', 'allow_system_changes', 'log_size', 'plugin_timeout',
|
||
|
- 'since', 'verify'
|
||
|
+ 'all_logs', 'allow_system_changes', 'cmd_timeout', 'log_size',
|
||
|
+ 'plugin_timeout', 'since', 'verify'
|
||
|
)
|
||
|
|
||
|
if optionname in global_options:
|
||
|
@@ -1505,7 +1527,7 @@ class Plugin(object):
|
||
|
'tags': _spec_tags
|
||
|
})
|
||
|
|
||
|
- def add_blockdev_cmd(self, cmds, devices='block', timeout=300,
|
||
|
+ def add_blockdev_cmd(self, cmds, devices='block', timeout=None,
|
||
|
sizelimit=None, chroot=True, runat=None, env=None,
|
||
|
binary=False, prepend_path=None, whitelist=[],
|
||
|
blacklist=[], tags=[]):
|
||
|
@@ -1569,7 +1591,7 @@ class Plugin(object):
|
||
|
whitelist=whitelist, blacklist=blacklist,
|
||
|
tags=_dev_tags)
|
||
|
|
||
|
- def _add_device_cmd(self, cmds, devices, timeout=300, sizelimit=None,
|
||
|
+ def _add_device_cmd(self, cmds, devices, timeout=None, sizelimit=None,
|
||
|
chroot=True, runat=None, env=None, binary=False,
|
||
|
prepend_path=None, whitelist=[], blacklist=[],
|
||
|
tags=[]):
|
||
|
@@ -1627,7 +1649,7 @@ class Plugin(object):
|
||
|
changes=soscmd.changes)
|
||
|
|
||
|
def add_cmd_output(self, cmds, suggest_filename=None,
|
||
|
- root_symlink=None, timeout=cmd_timeout, stderr=True,
|
||
|
+ root_symlink=None, timeout=None, stderr=True,
|
||
|
chroot=True, runat=None, env=None, binary=False,
|
||
|
sizelimit=None, pred=None, subdir=None,
|
||
|
changes=False, foreground=False, tags=[]):
|
||
|
@@ -1849,7 +1871,7 @@ class Plugin(object):
|
||
|
self._log_debug("added string ...'%s' as '%s'" % (summary, filename))
|
||
|
|
||
|
def _collect_cmd_output(self, cmd, suggest_filename=None,
|
||
|
- root_symlink=False, timeout=cmd_timeout,
|
||
|
+ root_symlink=False, timeout=None,
|
||
|
stderr=True, chroot=True, runat=None, env=None,
|
||
|
binary=False, sizelimit=None, subdir=None,
|
||
|
changes=False, foreground=False, tags=[]):
|
||
|
@@ -1883,6 +1905,8 @@ class Plugin(object):
|
||
|
if self._timeout_hit:
|
||
|
return
|
||
|
|
||
|
+ if timeout is None:
|
||
|
+ timeout = self.cmdtimeout
|
||
|
_tags = []
|
||
|
|
||
|
if isinstance(tags, str):
|
||
|
@@ -1975,7 +1999,7 @@ class Plugin(object):
|
||
|
return result
|
||
|
|
||
|
def collect_cmd_output(self, cmd, suggest_filename=None,
|
||
|
- root_symlink=False, timeout=cmd_timeout,
|
||
|
+ root_symlink=False, timeout=None,
|
||
|
stderr=True, chroot=True, runat=None, env=None,
|
||
|
binary=False, sizelimit=None, pred=None,
|
||
|
subdir=None, tags=[]):
|
||
|
@@ -2044,7 +2068,7 @@ class Plugin(object):
|
||
|
tags=tags
|
||
|
)
|
||
|
|
||
|
- def exec_cmd(self, cmd, timeout=cmd_timeout, stderr=True, chroot=True,
|
||
|
+ def exec_cmd(self, cmd, timeout=None, stderr=True, chroot=True,
|
||
|
runat=None, env=None, binary=False, pred=None,
|
||
|
foreground=False, container=False, quotecmd=False):
|
||
|
"""Execute a command right now and return the output and status, but
|
||
|
@@ -2095,6 +2119,9 @@ class Plugin(object):
|
||
|
if not self.test_predicate(cmd=True, pred=pred):
|
||
|
return _default
|
||
|
|
||
|
+ if timeout is None:
|
||
|
+ timeout = self.cmdtimeout
|
||
|
+
|
||
|
if chroot or self.commons['cmdlineopts'].chroot == 'always':
|
||
|
root = self.sysroot
|
||
|
else:
|
||
|
@@ -2331,7 +2358,7 @@ class Plugin(object):
|
||
|
|
||
|
def add_journal(self, units=None, boot=None, since=None, until=None,
|
||
|
lines=None, allfields=False, output=None,
|
||
|
- timeout=cmd_timeout, identifier=None, catalog=None,
|
||
|
+ timeout=None, identifier=None, catalog=None,
|
||
|
sizelimit=None, pred=None, tags=[]):
|
||
|
"""Collect journald logs from one of more units.
|
||
|
|
||
|
--
|
||
|
2.26.3
|
||
|
|