From 9d19e66db03c34ec640ec4c6456c4120eb6d761c Mon Sep 17 00:00:00 2001 From: Gorka Eguileor Date: Fri, 21 Jun 2024 11:03:02 +0200 Subject: [PATCH] [plugins] maxhours and all_logs on all plugins This patch makes 2 options settable globally and per-plugin: `maxhours` and `all-logs`. The `maxhours` option maps to what the code used to call `maxage`, which has also been renamed to `maxhours` to be consistent. Examples: ``` sos report --all-logs --maxhours=1 sos report -k container_log.all-logs=on,container_log.maxhours=1 sos report --all-logs --maxhours=1 \ -k container_log.all-logs=off,container_log.maxhours=2 ``` This adds flexibility to what users want to retrieve. Signed-off-by: Gorka Eguileor --- sos/report/__init__.py | 18 +++++++++++++-- sos/report/plugins/__init__.py | 42 +++++++++++++++++++++++----------- sos/report/plugins/kdump.py | 4 ++-- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/sos/report/__init__.py b/sos/report/__init__.py index d6d40f399c..f2e701c963 100644 --- a/sos/report/__init__.py +++ b/sos/report/__init__.py @@ -122,6 +122,7 @@ class SoSReport(SoSComponent): 'cmd_timeout': TIMEOUT_DEFAULT, 'profiles': [], 'since': None, + 'maxhours': None, 'verify': False, 'allow_system_changes': False, 'usernames': [], @@ -200,6 +201,12 @@ def add_parser_options(cls, parser): help="Escapes archived files older than date. " "This will also affect --all-logs. " "Format: YYYYMMDD[HHMMSS]") + report_grp.add_argument("--maxhours", action="store", + dest="maxhours", default=None, type=int, + help="Escapes archived files older (according " + "to `mktime`) than this many hours. This will " + "also affect --all-logs (sets the default for " + "all plugins)") report_grp.add_argument("--build", action="store_true", dest="build", default=False, help="preserve the temporary directory and do " @@ -904,6 +911,12 @@ def _set_all_options(self): opt.value = True def _set_tunables(self): + # Set plugin option's defaults to the global argument values + for pluginname, plugin in self.loaded_plugins: + for optname in plugin.options: + if hasattr(self.opts, optname): + plugin.options[optname].value = getattr(self.opts, optname) + if self.opts.plugopts: opts = {} for opt in self.opts.plugopts: @@ -1063,12 +1076,13 @@ def list_plugins(self): val = TIMEOUT_DEFAULT if opt.name == 'postproc': val = not self.opts.no_postproc - self.ui_log.info(f"{opt.param_name:<25} {val:<15} {opt.desc}") + self.ui_log.info( + f"{opt.param_name:<25} {val!s:<15} {opt.desc}") self.ui_log.info("") self.ui_log.info(_("The following plugin options are available:")) for opt in self.all_options: - if opt.name in ('timeout', 'postproc', 'cmd-timeout'): + if opt.name in _defaults: if opt.value == opt.default: continue # format option value based on its type (int or bool) diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py index be34cf7add..37d7f876e8 100644 --- a/sos/report/plugins/__init__.py +++ b/sos/report/plugins/__init__.py @@ -594,7 +594,19 @@ def __init__(self, commons): self.set_predicate(SoSPredicate(self)) def get_default_plugin_opts(self): + # The default of options that have a global argument counterpart with + # the same name must use the same default in both places. return { + 'maxhours': PluginOpt( + 'maxhours', default=None, val_type=int, + desc='Escapes archived files older (according to `mktime`) ' + 'than this many hours' + ), + 'all_logs': PluginOpt( + 'all_logs', default=False, val_type=bool, + param_name='all-logs', + desc='collect all available logs regardless of size', + ), 'timeout': PluginOpt( 'timeout', default=-1, val_type=int, desc='Timeout in seconds for plugin to finish all collections' @@ -1567,9 +1579,12 @@ def get_option(self, optionname, default=0): :returns: The value of `optionname` if found, else `default` """ + # These are Global options that can only be set globally. Options that + # can be set globally and per-plugin (those also returned by + # get_default_plugin_opts) are handled by the `_set_tunables` method. global_options = ( - 'all_logs', 'allow_system_changes', 'cmd_timeout', 'journal_size', - 'log_size', 'plugin_timeout', 'since', 'verify' + 'allow_system_changes', 'cmd_timeout', 'journal_size', 'log_size', + 'plugin_timeout', 'since', 'verify' ) if optionname in global_options: @@ -1636,7 +1651,7 @@ def generate_copyspec_tags(self): manifest_data['files_copied'] = matched_files self.manifest.files.append(manifest_data) - def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None, + def add_copy_spec(self, copyspecs, sizelimit=None, maxhours=None, tailit=True, pred=None, tags=[], container=None): """Add a file, directory, or globs matching filepaths to the archive @@ -1647,9 +1662,9 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None, to this size in MB :type sizelimit: ``int`` - :param maxage: Collect files with `mtime` not older than this many - hours - :type maxage: ``int`` + :param maxhours: Collect files with `mtime` not older than this many + hours + :type maxhours: ``int`` :param tailit: Should a file that exceeds `sizelimit` be tail'ed to fit the remaining space to meet `sizelimit` @@ -1679,9 +1694,10 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None, sos will collect up to 25MB worth of files within `/etc/foo`, and will collect the last 25MB of `/etc/bar.conf`. """ - since = None - if self.get_option('since'): - since = self.get_option('since') + since = self.get_option('since') or None + + # User's plugin option argument takes precedence over plugin passed arg + maxhours = self.get_option('maxhours') or maxhours logarchive_pattern = re.compile(r'.*((\.(zip|gz|bz2|xz))|[-.][\d]+)$') configfile_pattern = re.compile(fr"^{self.path_join('etc')}/*") @@ -1798,8 +1814,8 @@ def getmtime(path): return 0 def time_filter(path): - """ When --since is passed, or maxage is coming from the - plugin, we need to filter out older files """ + """ When --since is passed, or maxhours is coming from the + plugin or its options, we need to filter out older files """ # skip config files or not-logarchive files from the filter if ((logarchive_pattern.search(path) is None) or @@ -1808,11 +1824,11 @@ def time_filter(path): filetime = getmtime(path) filedatetime = datetime.fromtimestamp(filetime) if ((since and filedatetime < since) or - (maxage and (time()-filetime < maxage*3600))): + (maxhours and (time()-filetime < maxhours*3600))): return False return True - if since or maxage: + if since or maxhours: files = list(filter(lambda f: time_filter(f), files)) files.sort(key=getmtime, reverse=True) diff --git a/sos/report/plugins/kdump.py b/sos/report/plugins/kdump.py index a1be9ea462..21205cd939 100644 --- a/sos/report/plugins/kdump.py +++ b/sos/report/plugins/kdump.py @@ -100,7 +100,7 @@ def setup(self): # collect the latest vmcore created in the last 24hrs <= 2GB if self.get_option("get-vm-core"): - self.add_copy_spec(f"{path}/*/vmcore", sizelimit=2048, maxage=24) + self.add_copy_spec(f"{path}/*/vmcore", sizelimit=2048, maxhours=24) class DebianKDump(KDump, DebianPlugin, UbuntuPlugin): @@ -178,6 +178,6 @@ def setup(self): # collect the latest vmcore created in the last 24hrs <= 2GB if self.get_option("get-vm-core"): - self.add_copy_spec(f"{path}/*/vmcore", sizelimit=2048, maxage=24) + self.add_copy_spec(f"{path}/*/vmcore", sizelimit=2048, maxhours=24) # vim: set et ts=4 sw=4 :