|
|
003633 |
From 5b245b1e449c6a05d09034bcb8290bffded79327 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
Date: Wed, 8 Sep 2021 17:04:58 +0200
|
|
|
003633 |
Subject: [PATCH] [report] Implement --estimate-only
|
|
|
003633 |
|
|
|
003633 |
Add report option --estimate-only to estimate disk space requirements
|
|
|
003633 |
when running a sos report.
|
|
|
003633 |
|
|
|
003633 |
Resolves: #2673
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
man/en/sos-report.1 | 13 +++++++-
|
|
|
003633 |
sos/report/__init__.py | 74 ++++++++++++++++++++++++++++++++++++++++--
|
|
|
003633 |
2 files changed, 84 insertions(+), 3 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/man/en/sos-report.1 b/man/en/sos-report.1
|
|
|
003633 |
index 36b337df..e8efc8f8 100644
|
|
|
003633 |
--- a/man/en/sos-report.1
|
|
|
003633 |
+++ b/man/en/sos-report.1
|
|
|
003633 |
@@ -14,7 +14,7 @@ sos report \- Collect and package diagnostic and support data
|
|
|
003633 |
[--preset preset] [--add-preset add_preset]\fR
|
|
|
003633 |
[--del-preset del_preset] [--desc description]\fR
|
|
|
003633 |
[--batch] [--build] [--debug] [--dry-run]\fR
|
|
|
003633 |
- [--label label] [--case-id id]\fR
|
|
|
003633 |
+ [--estimate-only] [--label label] [--case-id id]\fR
|
|
|
003633 |
[--threads threads]\fR
|
|
|
003633 |
[--plugin-timeout TIMEOUT]\fR
|
|
|
003633 |
[--cmd-timeout TIMEOUT]\fR
|
|
|
003633 |
@@ -317,6 +317,17 @@ output, or string data from the system. The resulting logs may be used
|
|
|
003633 |
to understand the actions that sos would have taken without the dry run
|
|
|
003633 |
option.
|
|
|
003633 |
.TP
|
|
|
003633 |
+.B \--estimate-only
|
|
|
003633 |
+Estimate disk space requirements when running sos report. This can be valuable
|
|
|
003633 |
+to prevent sosreport working dir to consume all free disk space. No plugin data
|
|
|
003633 |
+is available at the end.
|
|
|
003633 |
+
|
|
|
003633 |
+Plugins will be collected sequentially, size of collected files and commands outputs
|
|
|
003633 |
+will be calculated and the plugin files will be immediatelly deleted prior execution
|
|
|
003633 |
+of the next plugin. This still can consume whole free disk space, though. Please note,
|
|
|
003633 |
+size estimations may not be accurate for highly utilized systems due to changes between
|
|
|
003633 |
+an estimate and a real execution.
|
|
|
003633 |
+.TP
|
|
|
003633 |
.B \--upload
|
|
|
003633 |
If specified, attempt to upload the resulting archive to a vendor defined location.
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index 82484f1d..b033f621 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -86,6 +86,7 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
'desc': '',
|
|
|
003633 |
'domains': [],
|
|
|
003633 |
'dry_run': False,
|
|
|
003633 |
+ 'estimate_only': False,
|
|
|
003633 |
'experimental': False,
|
|
|
003633 |
'enable_plugins': [],
|
|
|
003633 |
'keywords': [],
|
|
|
003633 |
@@ -137,6 +138,7 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
self._args = args
|
|
|
003633 |
self.sysroot = "/"
|
|
|
003633 |
self.preset = None
|
|
|
003633 |
+ self.estimated_plugsizes = {}
|
|
|
003633 |
|
|
|
003633 |
self.print_header()
|
|
|
003633 |
self._set_debug()
|
|
|
003633 |
@@ -223,6 +225,11 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
help="Description for a new preset",)
|
|
|
003633 |
report_grp.add_argument("--dry-run", action="store_true",
|
|
|
003633 |
help="Run plugins but do not collect data")
|
|
|
003633 |
+ report_grp.add_argument("--estimate-only", action="store_true",
|
|
|
003633 |
+ help="Approximate disk space requirements for "
|
|
|
003633 |
+ "a real sos run; disables --clean and "
|
|
|
003633 |
+ "--collect, sets --threads=1 and "
|
|
|
003633 |
+ "--no-postproc")
|
|
|
003633 |
report_grp.add_argument("--experimental", action="store_true",
|
|
|
003633 |
dest="experimental", default=False,
|
|
|
003633 |
help="enable experimental plugins")
|
|
|
003633 |
@@ -700,6 +700,33 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
self.all_options.append((plugin, plugin_name, optname,
|
|
|
003633 |
optparm))
|
|
|
003633 |
|
|
|
003633 |
+ def _set_estimate_only(self):
|
|
|
003633 |
+ # set estimate-only mode by enforcing some options settings
|
|
|
003633 |
+ # and return a corresponding log messages string
|
|
|
003633 |
+ msg = "\nEstimate-only mode enabled"
|
|
|
003633 |
+ ext_msg = []
|
|
|
003633 |
+ if self.opts.threads > 1:
|
|
|
003633 |
+ ext_msg += ["--threads=%s overriden to 1" % self.opts.threads, ]
|
|
|
003633 |
+ self.opts.threads = 1
|
|
|
003633 |
+ if not self.opts.build:
|
|
|
003633 |
+ ext_msg += ["--build enabled", ]
|
|
|
003633 |
+ self.opts.build = True
|
|
|
003633 |
+ if not self.opts.no_postproc:
|
|
|
003633 |
+ ext_msg += ["--no-postproc enabled", ]
|
|
|
003633 |
+ self.opts.no_postproc = True
|
|
|
003633 |
+ if self.opts.clean:
|
|
|
003633 |
+ ext_msg += ["--clean disabled", ]
|
|
|
003633 |
+ self.opts.clean = False
|
|
|
003633 |
+ if self.opts.upload:
|
|
|
003633 |
+ ext_msg += ["--upload* options disabled", ]
|
|
|
003633 |
+ self.opts.upload = False
|
|
|
003633 |
+ if ext_msg:
|
|
|
003633 |
+ msg += ", which overrides some options:\n " + "\n ".join(ext_msg)
|
|
|
003633 |
+ else:
|
|
|
003633 |
+ msg += "."
|
|
|
003633 |
+ msg += "\n\n"
|
|
|
003633 |
+ return msg
|
|
|
003633 |
+
|
|
|
003633 |
def _report_profiles_and_plugins(self):
|
|
|
003633 |
self.ui_log.info("")
|
|
|
003633 |
if len(self.loaded_plugins):
|
|
|
003633 |
@@ -875,10 +909,12 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
return True
|
|
|
003633 |
|
|
|
003633 |
def batch(self):
|
|
|
003633 |
+ msg = self.policy.get_msg()
|
|
|
003633 |
+ if self.opts.estimate_only:
|
|
|
003633 |
+ msg += self._set_estimate_only()
|
|
|
003633 |
if self.opts.batch:
|
|
|
003633 |
- self.ui_log.info(self.policy.get_msg())
|
|
|
003633 |
+ self.ui_log.info(msg)
|
|
|
003633 |
else:
|
|
|
003633 |
- msg = self.policy.get_msg()
|
|
|
003633 |
msg += _("Press ENTER to continue, or CTRL-C to quit.\n")
|
|
|
003633 |
try:
|
|
|
003633 |
input(msg)
|
|
|
003633 |
@@ -1011,6 +1047,22 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
self.running_plugs.remove(plugin[1])
|
|
|
003633 |
self.loaded_plugins[plugin[0]-1][1].set_timeout_hit()
|
|
|
003633 |
pool._threads.clear()
|
|
|
003633 |
+ if self.opts.estimate_only:
|
|
|
003633 |
+ from pathlib import Path
|
|
|
003633 |
+ tmpdir_path = Path(self.archive.get_tmp_dir())
|
|
|
003633 |
+ self.estimated_plugsizes[plugin[1]] = sum(
|
|
|
003633 |
+ [f.stat().st_size for f in tmpdir_path.glob('**/*')
|
|
|
003633 |
+ if (os.path.isfile(f) and not os.path.islink(f))])
|
|
|
003633 |
+ # remove whole tmp_dir content - including "sos_commands" and
|
|
|
003633 |
+ # similar dirs that will be re-created on demand by next plugin
|
|
|
003633 |
+ # if needed; it is less error-prone approach than skipping
|
|
|
003633 |
+ # deletion of some dirs but deleting their content
|
|
|
003633 |
+ for f in os.listdir(self.archive.get_tmp_dir()):
|
|
|
003633 |
+ f = os.path.join(self.archive.get_tmp_dir(), f)
|
|
|
003633 |
+ if os.path.isdir(f):
|
|
|
003633 |
+ rmtree(f)
|
|
|
003633 |
+ else:
|
|
|
003633 |
+ os.unlink(f)
|
|
|
003633 |
return True
|
|
|
003633 |
|
|
|
003633 |
def collect_plugin(self, plugin):
|
|
|
003633 |
@@ -1330,6 +1382,24 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
self.policy.display_results(archive, directory, checksum,
|
|
|
003633 |
map_file=map_file)
|
|
|
003633 |
|
|
|
003633 |
+ if self.opts.estimate_only:
|
|
|
003633 |
+ from sos.utilities import get_human_readable
|
|
|
003633 |
+ _sum = get_human_readable(sum(self.estimated_plugsizes.values()))
|
|
|
003633 |
+ self.ui_log.info("Estimated disk space requirement for whole "
|
|
|
003633 |
+ "uncompressed sos report directory: %s" % _sum)
|
|
|
003633 |
+ bigplugins = sorted(self.estimated_plugsizes.items(),
|
|
|
003633 |
+ key=lambda x: x[1], reverse=True)[:3]
|
|
|
003633 |
+ bp_out = ", ".join("%s: %s" %
|
|
|
003633 |
+ (p, get_human_readable(v, precision=0))
|
|
|
003633 |
+ for p, v in bigplugins)
|
|
|
003633 |
+ self.ui_log.info("Three biggest plugins: %s" % bp_out)
|
|
|
003633 |
+ self.ui_log.info("")
|
|
|
003633 |
+ self.ui_log.info("Please note the estimation is relevant to the "
|
|
|
003633 |
+ "current options.")
|
|
|
003633 |
+ self.ui_log.info("Be aware that the real disk space requirements "
|
|
|
003633 |
+ "might be different.")
|
|
|
003633 |
+ self.ui_log.info("")
|
|
|
003633 |
+
|
|
|
003633 |
if self.opts.upload or self.opts.upload_url:
|
|
|
003633 |
if not self.opts.build:
|
|
|
003633 |
try:
|
|
|
003633 |
--
|
|
|
003633 |
2.31.1
|
|
|
003633 |
|
|
|
003633 |
From 7ae47e6c0717c0b56c3368008dd99a87f7f436d5 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
Date: Wed, 13 Oct 2021 20:21:16 +0200
|
|
|
003633 |
Subject: [PATCH] [report] Count with sos_logs and sos_reports in
|
|
|
003633 |
--estimate-only
|
|
|
003633 |
|
|
|
003633 |
Currently, we estimate just plugins' disk space and ignore sos_logs
|
|
|
003633 |
or sos_reports directories - although they can occupy nontrivial disk
|
|
|
003633 |
space as well.
|
|
|
003633 |
|
|
|
003633 |
Resolves: #2723
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/report/__init__.py | 8 ++++++++
|
|
|
003633 |
1 file changed, 8 insertions(+)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index e35c7e8d..7feb31ee 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -1380,6 +1380,14 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
|
|
|
003633 |
if self.opts.estimate_only:
|
|
|
003633 |
from sos.utilities import get_human_readable
|
|
|
003633 |
+ from pathlib import Path
|
|
|
003633 |
+ # add sos_logs, sos_reports dirs, etc., basically everything
|
|
|
003633 |
+ # that remained in self.tmpdir after plugins' contents removal
|
|
|
003633 |
+ # that still will be moved to the sos report final directory path
|
|
|
003633 |
+ tmpdir_path = Path(self.tmpdir)
|
|
|
003633 |
+ self.estimated_plugsizes['sos_logs_reports'] = sum(
|
|
|
003633 |
+ [f.stat().st_size for f in tmpdir_path.glob('**/*')])
|
|
|
003633 |
+
|
|
|
003633 |
_sum = get_human_readable(sum(self.estimated_plugsizes.values()))
|
|
|
003633 |
self.ui_log.info("Estimated disk space requirement for whole "
|
|
|
003633 |
"uncompressed sos report directory: %s" % _sum)
|
|
|
003633 |
--
|
|
|
003633 |
2.31.1
|
|
|
003633 |
|
|
|
003633 |
From 4293f3317505661e8f32ba94ad87310996fa1626 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Eric Desrochers <eric.desrochers@canonical.com>
|
|
|
003633 |
Date: Tue, 19 Oct 2021 12:18:40 -0400
|
|
|
003633 |
Subject: [PATCH] [report] check for symlink before rmtree when opt
|
|
|
003633 |
estimate-only is use
|
|
|
003633 |
|
|
|
003633 |
Check if the dir is also symlink before performing rmtree()
|
|
|
003633 |
method so that unlink() method can be used instead.
|
|
|
003633 |
|
|
|
003633 |
Traceback (most recent call last):
|
|
|
003633 |
File "./bin/sos", line 22, in <module>
|
|
|
003633 |
sos.execute()
|
|
|
003633 |
File "/tmp/sos/sos/__init__.py", line 186, in execute
|
|
|
003633 |
self._component.execute()
|
|
|
003633 |
OSError: Cannot call rmtree on a symbolic link
|
|
|
003633 |
|
|
|
003633 |
Closes: #2727
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Eric Desrochers <eric.desrochers@canonical.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/report/__init__.py | 2 +-
|
|
|
003633 |
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index 7feb31ee..1b5bc97d 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -1059,7 +1059,7 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
# deletion of some dirs but deleting their content
|
|
|
003633 |
for f in os.listdir(self.archive.get_tmp_dir()):
|
|
|
003633 |
f = os.path.join(self.archive.get_tmp_dir(), f)
|
|
|
003633 |
- if os.path.isdir(f):
|
|
|
003633 |
+ if os.path.isdir(f) and not os.path.islink(f):
|
|
|
003633 |
rmtree(f)
|
|
|
003633 |
else:
|
|
|
003633 |
os.unlink(f)
|
|
|
003633 |
--
|
|
|
003633 |
2.31.1
|
|
|
003633 |
|
|
|
003633 |
From 589d47c93257b55bc796ef6ac25b88c974ee3d72 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
Date: Mon, 8 Nov 2021 16:38:24 +0100
|
|
|
003633 |
Subject: [PATCH] [report] Calculate sizes of dirs, symlinks and manifest in
|
|
|
003633 |
estimate mode
|
|
|
003633 |
|
|
|
003633 |
Enhance --estimate-mode to calculate sizes of also:
|
|
|
003633 |
- symlinks
|
|
|
003633 |
- directories themselves
|
|
|
003633 |
- manifest.json file
|
|
|
003633 |
|
|
|
003633 |
Use os.lstat() method instead of os.stat() to properly calculate the
|
|
|
003633 |
sizes (and not destinations of symlinks, e.g.).
|
|
|
003633 |
|
|
|
003633 |
Print five biggest plugins instead of three as sos logs and reports do
|
|
|
003633 |
stand as one "plugin" in the list, often.
|
|
|
003633 |
|
|
|
003633 |
Resolves: #2752
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/report/__init__.py | 56 +++++++++++++++++++++---------------------
|
|
|
003633 |
1 file changed, 28 insertions(+), 28 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index 10952566..a4c92acc 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -1050,8 +1050,7 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
from pathlib import Path
|
|
|
003633 |
tmpdir_path = Path(self.archive.get_tmp_dir())
|
|
|
003633 |
self.estimated_plugsizes[plugin[1]] = sum(
|
|
|
003633 |
- [f.stat().st_size for f in tmpdir_path.glob('**/*')
|
|
|
003633 |
- if (os.path.isfile(f) and not os.path.islink(f))])
|
|
|
003633 |
+ [f.lstat().st_size for f in tmpdir_path.glob('**/*')])
|
|
|
003633 |
# remove whole tmp_dir content - including "sos_commands" and
|
|
|
003633 |
# similar dirs that will be re-created on demand by next plugin
|
|
|
003633 |
# if needed; it is less error-prone approach than skipping
|
|
|
003633 |
@@ -1273,6 +1272,33 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
short_name='manifest.json'
|
|
|
003633 |
)
|
|
|
003633 |
|
|
|
003633 |
+ # print results in estimate mode (to include also just added manifest)
|
|
|
003633 |
+ if self.opts.estimate_only:
|
|
|
003633 |
+ from sos.utilities import get_human_readable
|
|
|
003633 |
+ from pathlib import Path
|
|
|
003633 |
+ # add sos_logs, sos_reports dirs, etc., basically everything
|
|
|
003633 |
+ # that remained in self.tmpdir after plugins' contents removal
|
|
|
003633 |
+ # that still will be moved to the sos report final directory path
|
|
|
003633 |
+ tmpdir_path = Path(self.tmpdir)
|
|
|
003633 |
+ self.estimated_plugsizes['sos_logs_reports'] = sum(
|
|
|
003633 |
+ [f.lstat().st_size for f in tmpdir_path.glob('**/*')])
|
|
|
003633 |
+
|
|
|
003633 |
+ _sum = get_human_readable(sum(self.estimated_plugsizes.values()))
|
|
|
003633 |
+ self.ui_log.info("Estimated disk space requirement for whole "
|
|
|
003633 |
+ "uncompressed sos report directory: %s" % _sum)
|
|
|
003633 |
+ bigplugins = sorted(self.estimated_plugsizes.items(),
|
|
|
003633 |
+ key=lambda x: x[1], reverse=True)[:5]
|
|
|
003633 |
+ bp_out = ", ".join("%s: %s" %
|
|
|
003633 |
+ (p, get_human_readable(v, precision=0))
|
|
|
003633 |
+ for p, v in bigplugins)
|
|
|
003633 |
+ self.ui_log.info("Five biggest plugins: %s" % bp_out)
|
|
|
003633 |
+ self.ui_log.info("")
|
|
|
003633 |
+ self.ui_log.info("Please note the estimation is relevant to the "
|
|
|
003633 |
+ "current options.")
|
|
|
003633 |
+ self.ui_log.info("Be aware that the real disk space requirements "
|
|
|
003633 |
+ "might be different.")
|
|
|
003633 |
+ self.ui_log.info("")
|
|
|
003633 |
+
|
|
|
003633 |
# package up and compress the results
|
|
|
003633 |
if not self.opts.build:
|
|
|
003633 |
old_umask = os.umask(0o077)
|
|
|
003633 |
@@ -1377,32 +1403,6 @@ class SoSReport(SoSComponent):
|
|
|
003633 |
self.policy.display_results(archive, directory, checksum,
|
|
|
003633 |
map_file=map_file)
|
|
|
003633 |
|
|
|
003633 |
- if self.opts.estimate_only:
|
|
|
003633 |
- from sos.utilities import get_human_readable
|
|
|
003633 |
- from pathlib import Path
|
|
|
003633 |
- # add sos_logs, sos_reports dirs, etc., basically everything
|
|
|
003633 |
- # that remained in self.tmpdir after plugins' contents removal
|
|
|
003633 |
- # that still will be moved to the sos report final directory path
|
|
|
003633 |
- tmpdir_path = Path(self.tmpdir)
|
|
|
003633 |
- self.estimated_plugsizes['sos_logs_reports'] = sum(
|
|
|
003633 |
- [f.stat().st_size for f in tmpdir_path.glob('**/*')])
|
|
|
003633 |
-
|
|
|
003633 |
- _sum = get_human_readable(sum(self.estimated_plugsizes.values()))
|
|
|
003633 |
- self.ui_log.info("Estimated disk space requirement for whole "
|
|
|
003633 |
- "uncompressed sos report directory: %s" % _sum)
|
|
|
003633 |
- bigplugins = sorted(self.estimated_plugsizes.items(),
|
|
|
003633 |
- key=lambda x: x[1], reverse=True)[:3]
|
|
|
003633 |
- bp_out = ", ".join("%s: %s" %
|
|
|
003633 |
- (p, get_human_readable(v, precision=0))
|
|
|
003633 |
- for p, v in bigplugins)
|
|
|
003633 |
- self.ui_log.info("Three biggest plugins: %s" % bp_out)
|
|
|
003633 |
- self.ui_log.info("")
|
|
|
003633 |
- self.ui_log.info("Please note the estimation is relevant to the "
|
|
|
003633 |
- "current options.")
|
|
|
003633 |
- self.ui_log.info("Be aware that the real disk space requirements "
|
|
|
003633 |
- "might be different.")
|
|
|
003633 |
- self.ui_log.info("")
|
|
|
003633 |
-
|
|
|
003633 |
if self.opts.upload or self.opts.upload_url:
|
|
|
003633 |
if not self.opts.build:
|
|
|
003633 |
try:
|
|
|
003633 |
--
|
|
|
003633 |
2.31.1
|
|
|
003633 |
|
|
|
003633 |
From c6a5bbb8d75aadd5c7f76d3f469929aba2cf8060 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
Date: Wed, 5 Jan 2022 10:33:58 +0100
|
|
|
003633 |
Subject: [PATCH] [report] Provide better warning about estimate-mode
|
|
|
003633 |
|
|
|
003633 |
As --estimate-only calculates disk usage based on `stat` data that
|
|
|
003633 |
differs from outputs of other commands like `du`, enhance the warning
|
|
|
003633 |
about reliability of the calculated estimation.
|
|
|
003633 |
|
|
|
003633 |
Also add a rule-of-thumb recommendation of real disk space requirements.
|
|
|
003633 |
|
|
|
003633 |
Resolves: #2815
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
man/en/sos-report.1 | 10 +++++++---
|
|
|
003633 |
sos/report/__init__.py | 3 ++-
|
|
|
003633 |
2 files changed, 9 insertions(+), 4 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/man/en/sos-report.1 b/man/en/sos-report.1
|
|
|
003633 |
index 464a77e54..e34773986 100644
|
|
|
003633 |
--- a/man/en/sos-report.1
|
|
|
003633 |
+++ b/man/en/sos-report.1
|
|
|
003633 |
@@ -343,9 +343,13 @@ is available at the end.
|
|
|
003633 |
|
|
|
003633 |
Plugins will be collected sequentially, size of collected files and commands outputs
|
|
|
003633 |
will be calculated and the plugin files will be immediatelly deleted prior execution
|
|
|
003633 |
-of the next plugin. This still can consume whole free disk space, though. Please note,
|
|
|
003633 |
-size estimations may not be accurate for highly utilized systems due to changes between
|
|
|
003633 |
-an estimate and a real execution.
|
|
|
003633 |
+of the next plugin. This still can consume whole free disk space, though.
|
|
|
003633 |
+
|
|
|
003633 |
+Please note, size estimations may not be accurate for highly utilized systems due to
|
|
|
003633 |
+changes between an estimate and a real execution. Also some difference between
|
|
|
003633 |
+estimation (using `stat` command) and other commands used (i.e. `du`).
|
|
|
003633 |
+
|
|
|
003633 |
+A rule of thumb is to reserve at least double the estimation.
|
|
|
003633 |
.TP
|
|
|
003633 |
.B \--upload
|
|
|
003633 |
If specified, attempt to upload the resulting archive to a vendor defined location.
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index ef61fb344..e0617b45e 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -1330,7 +1330,8 @@ def final_work(self):
|
|
|
003633 |
self.ui_log.info("Please note the estimation is relevant to the "
|
|
|
003633 |
"current options.")
|
|
|
003633 |
self.ui_log.info("Be aware that the real disk space requirements "
|
|
|
003633 |
- "might be different.")
|
|
|
003633 |
+ "might be different. A rule of thumb is to "
|
|
|
003633 |
+ "reserve at least double the estimation.")
|
|
|
003633 |
self.ui_log.info("")
|
|
|
003633 |
|
|
|
003633 |
# package up and compress the results
|
|
|
003633 |
From f22efe044f1f0565b57d6aeca2081a5227e0312c Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
Date: Mon, 14 Feb 2022 09:37:30 -0500
|
|
|
003633 |
Subject: [PATCH] [utilities] Don't try to chroot to /
|
|
|
003633 |
|
|
|
003633 |
With the recent fix for sysroot being `None` to always being (correctly)
|
|
|
003633 |
`/`, we should guard against situations where `sos_get_command_output()`
|
|
|
003633 |
would now try to chroot to `/` before running any command. Incidentally,
|
|
|
003633 |
this would also cause our unittests to fail if they were run by a
|
|
|
003633 |
non-root user.
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/utilities.py | 2 +-
|
|
|
003633 |
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
|
003633 |
index 6b13415b..d782123a 100644
|
|
|
003633 |
--- a/sos/utilities.py
|
|
|
003633 |
+++ b/sos/utilities.py
|
|
|
003633 |
@@ -120,7 +120,7 @@ def sos_get_command_output(command, timeout=TIMEOUT_DEFAULT, stderr=False,
|
|
|
003633 |
# closure are caught in the parent (chroot and chdir are bound from
|
|
|
003633 |
# the enclosing scope).
|
|
|
003633 |
def _child_prep_fn():
|
|
|
003633 |
- if (chroot):
|
|
|
003633 |
+ if chroot and chroot != '/':
|
|
|
003633 |
os.chroot(chroot)
|
|
|
003633 |
if (chdir):
|
|
|
003633 |
os.chdir(chdir)
|
|
|
003633 |
--
|
|
|
003633 |
2.34.1
|
|
|
003633 |
From 3d064102f8ca6662fd9602512e1cb05cf8746dfd Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
Date: Mon, 27 Sep 2021 19:01:16 -0400
|
|
|
003633 |
Subject: [PATCH] [Systemd, Policy] Correct InitSystem chrooting when chroot is
|
|
|
003633 |
needed
|
|
|
003633 |
|
|
|
003633 |
This commit resolves a situation in which `sos` is being run in a
|
|
|
003633 |
container but the `SystemdInit` InitSystem would not properly load
|
|
|
003633 |
information from the host, thus causing the `Plugin.is_service*()`
|
|
|
003633 |
methods to erroneously fail or return `False`.
|
|
|
003633 |
|
|
|
003633 |
Fix this scenario by pulling the `_container_init()` and related logic
|
|
|
003633 |
to check for a containerized host sysroot out of the Red Hat specific
|
|
|
003633 |
policy and into the base `LinuxPolicy` class so that the init system can
|
|
|
003633 |
be initialized with the correct sysroot, which is now used to chroot the
|
|
|
003633 |
calls to the relevant `systemctl` commands.
|
|
|
003633 |
|
|
|
003633 |
For now, this does impose the use of looking for the `container` env var
|
|
|
003633 |
(automatically set by docker, podman, and crio regardless of
|
|
|
003633 |
distribution) and the use of the `HOST` env var to read where the host's
|
|
|
003633 |
`/` filesystem is mounted within the container. If desired in the
|
|
|
003633 |
future, this can be changed to allow policy-specific overrides. For now
|
|
|
003633 |
however, this extends host collection via an sos container for all
|
|
|
003633 |
distributions currently shipping sos.
|
|
|
003633 |
|
|
|
003633 |
Note that this issue only affected the `InitSystem` abstraction for
|
|
|
003633 |
loading information about local services, and did not affect init system
|
|
|
003633 |
related commands called by plugins as part of those collections.
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/policies/distros/__init__.py | 28 ++++++++++++++++++++++++++-
|
|
|
003633 |
sos/policies/distros/redhat.py | 27 +-------------------------
|
|
|
003633 |
sos/policies/init_systems/__init__.py | 13 +++++++++++--
|
|
|
003633 |
sos/policies/init_systems/systemd.py | 7 ++++---
|
|
|
003633 |
4 files changed, 43 insertions(+), 32 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
|
|
003633 |
index f5b9fd5b01..c33a356a75 100644
|
|
|
003633 |
--- a/sos/policies/distros/__init__.py
|
|
|
003633 |
+++ b/sos/policies/distros/__init__.py
|
|
|
003633 |
@@ -29,6 +29,10 @@
|
|
|
003633 |
except ImportError:
|
|
|
003633 |
REQUESTS_LOADED = False
|
|
|
003633 |
|
|
|
003633 |
+# Container environment variables for detecting if we're in a container
|
|
|
003633 |
+ENV_CONTAINER = 'container'
|
|
|
003633 |
+ENV_HOST_SYSROOT = 'HOST'
|
|
|
003633 |
+
|
|
|
003633 |
|
|
|
003633 |
class LinuxPolicy(Policy):
|
|
|
003633 |
"""This policy is meant to be an abc class that provides common
|
|
|
003633 |
@@ -69,10 +73,17 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
|
|
003633 |
probe_runtime=probe_runtime)
|
|
|
003633 |
self.init_kernel_modules()
|
|
|
003633 |
|
|
|
003633 |
+ # need to set _host_sysroot before PackageManager()
|
|
|
003633 |
+ if sysroot:
|
|
|
003633 |
+ self._container_init()
|
|
|
003633 |
+ self._host_sysroot = sysroot
|
|
|
003633 |
+ else:
|
|
|
003633 |
+ sysroot = self._container_init()
|
|
|
003633 |
+
|
|
|
003633 |
if init is not None:
|
|
|
003633 |
self.init_system = init
|
|
|
003633 |
elif os.path.isdir("/run/systemd/system/"):
|
|
|
003633 |
- self.init_system = SystemdInit()
|
|
|
003633 |
+ self.init_system = SystemdInit(chroot=sysroot)
|
|
|
003633 |
else:
|
|
|
003633 |
self.init_system = InitSystem()
|
|
|
003633 |
|
|
|
003633 |
@@ -130,6 +141,21 @@ def get_local_name(self):
|
|
|
003633 |
def sanitize_filename(self, name):
|
|
|
003633 |
return re.sub(r"[^-a-z,A-Z.0-9]", "", name)
|
|
|
003633 |
|
|
|
003633 |
+ def _container_init(self):
|
|
|
003633 |
+ """Check if sos is running in a container and perform container
|
|
|
003633 |
+ specific initialisation based on ENV_HOST_SYSROOT.
|
|
|
003633 |
+ """
|
|
|
003633 |
+ if ENV_CONTAINER in os.environ:
|
|
|
003633 |
+ if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
|
|
003633 |
+ self._in_container = True
|
|
|
003633 |
+ if ENV_HOST_SYSROOT in os.environ:
|
|
|
003633 |
+ self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
|
003633 |
+ use_sysroot = self._in_container and self._host_sysroot is not None
|
|
|
003633 |
+ if use_sysroot:
|
|
|
003633 |
+ host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
|
|
003633 |
+ self._tmp_dir = host_tmp_dir
|
|
|
003633 |
+ return self._host_sysroot if use_sysroot else None
|
|
|
003633 |
+
|
|
|
003633 |
def init_kernel_modules(self):
|
|
|
003633 |
"""Obtain a list of loaded kernel modules to reference later for plugin
|
|
|
003633 |
enablement and SoSPredicate checks
|
|
|
003633 |
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
|
|
003633 |
index b3a84336be..3476e21fb2 100644
|
|
|
003633 |
--- a/sos/policies/distros/redhat.py
|
|
|
003633 |
+++ b/sos/policies/distros/redhat.py
|
|
|
003633 |
@@ -17,7 +17,7 @@
|
|
|
003633 |
from sos.presets.redhat import (RHEL_PRESETS, ATOMIC_PRESETS, RHV, RHEL,
|
|
|
003633 |
CB, RHOSP, RHOCP, RH_CFME, RH_SATELLITE,
|
|
|
003633 |
ATOMIC)
|
|
|
003633 |
-from sos.policies.distros import LinuxPolicy
|
|
|
003633 |
+from sos.policies.distros import LinuxPolicy, ENV_HOST_SYSROOT
|
|
|
003633 |
from sos.policies.package_managers.rpm import RpmPackageManager
|
|
|
003633 |
from sos import _sos as _
|
|
|
003633 |
|
|
|
003633 |
@@ -56,12 +56,6 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
|
|
003633 |
super(RedHatPolicy, self).__init__(sysroot=sysroot, init=init,
|
|
|
003633 |
probe_runtime=probe_runtime)
|
|
|
003633 |
self.usrmove = False
|
|
|
003633 |
- # need to set _host_sysroot before PackageManager()
|
|
|
003633 |
- if sysroot:
|
|
|
003633 |
- self._container_init()
|
|
|
003633 |
- self._host_sysroot = sysroot
|
|
|
003633 |
- else:
|
|
|
003633 |
- sysroot = self._container_init()
|
|
|
003633 |
|
|
|
003633 |
self.package_manager = RpmPackageManager(chroot=sysroot,
|
|
|
003633 |
remote_exec=remote_exec)
|
|
|
003633 |
@@ -140,21 +134,6 @@ def transform_path(path):
|
|
|
003633 |
else:
|
|
|
003633 |
return files
|
|
|
003633 |
|
|
|
003633 |
- def _container_init(self):
|
|
|
003633 |
- """Check if sos is running in a container and perform container
|
|
|
003633 |
- specific initialisation based on ENV_HOST_SYSROOT.
|
|
|
003633 |
- """
|
|
|
003633 |
- if ENV_CONTAINER in os.environ:
|
|
|
003633 |
- if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
|
|
003633 |
- self._in_container = True
|
|
|
003633 |
- if ENV_HOST_SYSROOT in os.environ:
|
|
|
003633 |
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
|
003633 |
- use_sysroot = self._in_container and self._host_sysroot is not None
|
|
|
003633 |
- if use_sysroot:
|
|
|
003633 |
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
|
|
003633 |
- self._tmp_dir = host_tmp_dir
|
|
|
003633 |
- return self._host_sysroot if use_sysroot else None
|
|
|
003633 |
-
|
|
|
003633 |
def runlevel_by_service(self, name):
|
|
|
003633 |
from subprocess import Popen, PIPE
|
|
|
003633 |
ret = []
|
|
|
003633 |
@@ -183,10 +162,6 @@ def get_tmp_dir(self, opt_tmp_dir):
|
|
|
003633 |
return opt_tmp_dir
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
-# Container environment variables on Red Hat systems.
|
|
|
003633 |
-ENV_CONTAINER = 'container'
|
|
|
003633 |
-ENV_HOST_SYSROOT = 'HOST'
|
|
|
003633 |
-
|
|
|
003633 |
# Legal disclaimer text for Red Hat products
|
|
|
003633 |
disclaimer_text = """
|
|
|
003633 |
Any information provided to %(vendor)s will be treated in \
|
|
|
003633 |
diff --git a/sos/policies/init_systems/__init__.py b/sos/policies/init_systems/__init__.py
|
|
|
003633 |
index dd663e6522..beac44cee3 100644
|
|
|
003633 |
--- a/sos/policies/init_systems/__init__.py
|
|
|
003633 |
+++ b/sos/policies/init_systems/__init__.py
|
|
|
003633 |
@@ -29,9 +29,14 @@ class InitSystem():
|
|
|
003633 |
status of services
|
|
|
003633 |
:type query_cmd: ``str``
|
|
|
003633 |
|
|
|
003633 |
+ :param chroot: Location to chroot to for any command execution, i.e. the
|
|
|
003633 |
+ sysroot if we're running in a container
|
|
|
003633 |
+ :type chroot: ``str`` or ``None``
|
|
|
003633 |
+
|
|
|
003633 |
"""
|
|
|
003633 |
|
|
|
003633 |
- def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
|
|
003633 |
+ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None,
|
|
|
003633 |
+ chroot=None):
|
|
|
003633 |
"""Initialize a new InitSystem()"""
|
|
|
003633 |
|
|
|
003633 |
self.services = {}
|
|
|
003633 |
@@ -39,6 +44,7 @@ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
|
|
003633 |
self.init_cmd = init_cmd
|
|
|
003633 |
self.list_cmd = "%s %s" % (self.init_cmd, list_cmd) or None
|
|
|
003633 |
self.query_cmd = "%s %s" % (self.init_cmd, query_cmd) or None
|
|
|
003633 |
+ self.chroot = chroot
|
|
|
003633 |
|
|
|
003633 |
def is_enabled(self, name):
|
|
|
003633 |
"""Check if given service name is enabled
|
|
|
003633 |
@@ -108,7 +114,10 @@ def _query_service(self, name):
|
|
|
003633 |
"""Query an individual service"""
|
|
|
003633 |
if self.query_cmd:
|
|
|
003633 |
try:
|
|
|
003633 |
- return sos_get_command_output("%s %s" % (self.query_cmd, name))
|
|
|
003633 |
+ return sos_get_command_output(
|
|
|
003633 |
+ "%s %s" % (self.query_cmd, name),
|
|
|
003633 |
+ chroot=self.chroot
|
|
|
003633 |
+ )
|
|
|
003633 |
except Exception:
|
|
|
003633 |
return None
|
|
|
003633 |
return None
|
|
|
003633 |
diff --git a/sos/policies/init_systems/systemd.py b/sos/policies/init_systems/systemd.py
|
|
|
003633 |
index 1b138f97b3..76dc57e27f 100644
|
|
|
003633 |
--- a/sos/policies/init_systems/systemd.py
|
|
|
003633 |
+++ b/sos/policies/init_systems/systemd.py
|
|
|
003633 |
@@ -15,11 +15,12 @@
|
|
|
003633 |
class SystemdInit(InitSystem):
|
|
|
003633 |
"""InitSystem abstraction for SystemD systems"""
|
|
|
003633 |
|
|
|
003633 |
- def __init__(self):
|
|
|
003633 |
+ def __init__(self, chroot=None):
|
|
|
003633 |
super(SystemdInit, self).__init__(
|
|
|
003633 |
init_cmd='systemctl',
|
|
|
003633 |
list_cmd='list-unit-files --type=service',
|
|
|
003633 |
- query_cmd='status'
|
|
|
003633 |
+ query_cmd='status',
|
|
|
003633 |
+ chroot=chroot
|
|
|
003633 |
)
|
|
|
003633 |
self.load_all_services()
|
|
|
003633 |
|
|
|
003633 |
@@ -30,7 +31,7 @@ def parse_query(self, output):
|
|
|
003633 |
return 'unknown'
|
|
|
003633 |
|
|
|
003633 |
def load_all_services(self):
|
|
|
003633 |
- svcs = shell_out(self.list_cmd).splitlines()[1:]
|
|
|
003633 |
+ svcs = shell_out(self.list_cmd, chroot=self.chroot).splitlines()[1:]
|
|
|
003633 |
for line in svcs:
|
|
|
003633 |
try:
|
|
|
003633 |
name = line.split('.service')[0]
|
|
|
003633 |
From e869bc84c714bfc2249bbcb84e14908049ee42c4 Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
Date: Mon, 27 Sep 2021 12:07:08 -0400
|
|
|
003633 |
Subject: [PATCH] [Plugin,utilities] Add sysroot wrapper for os.path.join
|
|
|
003633 |
|
|
|
003633 |
Adds a wrapper for `os.path.join()` which accounts for non-/ sysroots,
|
|
|
003633 |
like we have done previously for other `os.path` methods. Further
|
|
|
003633 |
updates `Plugin()` to use this wrapper where appropriate.
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/report/plugins/__init__.py | 43 +++++++++++++++++-----------------
|
|
|
003633 |
sos/utilities.py | 6 +++++
|
|
|
003633 |
2 files changed, 28 insertions(+), 21 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
|
|
003633 |
index c635b8de9..1f84bca49 100644
|
|
|
003633 |
--- a/sos/report/plugins/__init__.py
|
|
|
003633 |
+++ b/sos/report/plugins/__init__.py
|
|
|
003633 |
@@ -13,7 +13,7 @@
|
|
|
003633 |
from sos.utilities import (sos_get_command_output, import_module, grep,
|
|
|
003633 |
fileobj, tail, is_executable, TIMEOUT_DEFAULT,
|
|
|
003633 |
path_exists, path_isdir, path_isfile, path_islink,
|
|
|
003633 |
- listdir)
|
|
|
003633 |
+ listdir, path_join)
|
|
|
003633 |
|
|
|
003633 |
import os
|
|
|
003633 |
import glob
|
|
|
003633 |
@@ -708,19 +708,6 @@ def _log_info(self, msg):
|
|
|
003633 |
def _log_debug(self, msg):
|
|
|
003633 |
self.soslog.debug(self._format_msg(msg))
|
|
|
003633 |
|
|
|
003633 |
- def join_sysroot(self, path):
|
|
|
003633 |
- """Join a given path with the configured sysroot
|
|
|
003633 |
-
|
|
|
003633 |
- :param path: The filesystem path that needs to be joined
|
|
|
003633 |
- :type path: ``str``
|
|
|
003633 |
-
|
|
|
003633 |
- :returns: The joined filesystem path
|
|
|
003633 |
- :rtype: ``str``
|
|
|
003633 |
- """
|
|
|
003633 |
- if path[0] == os.sep:
|
|
|
003633 |
- path = path[1:]
|
|
|
003633 |
- return os.path.join(self.sysroot, path)
|
|
|
003633 |
-
|
|
|
003633 |
def strip_sysroot(self, path):
|
|
|
003633 |
"""Remove the configured sysroot from a filesystem path
|
|
|
003633 |
|
|
|
003633 |
@@ -1176,7 +1163,7 @@ def _copy_dir(self, srcpath):
|
|
|
003633 |
|
|
|
003633 |
def _get_dest_for_srcpath(self, srcpath):
|
|
|
003633 |
if self.use_sysroot():
|
|
|
003633 |
- srcpath = self.join_sysroot(srcpath)
|
|
|
003633 |
+ srcpath = self.path_join(srcpath)
|
|
|
003633 |
for copied in self.copied_files:
|
|
|
003633 |
if srcpath == copied["srcpath"]:
|
|
|
003633 |
return copied["dstpath"]
|
|
|
003633 |
@@ -1284,7 +1271,7 @@ def add_forbidden_path(self, forbidden, recursive=False):
|
|
|
003633 |
forbidden = [forbidden]
|
|
|
003633 |
|
|
|
003633 |
if self.use_sysroot():
|
|
|
003633 |
- forbidden = [self.join_sysroot(f) for f in forbidden]
|
|
|
003633 |
+ forbidden = [self.path_join(f) for f in forbidden]
|
|
|
003633 |
|
|
|
003633 |
for forbid in forbidden:
|
|
|
003633 |
self._log_info("adding forbidden path '%s'" % forbid)
|
|
|
003633 |
@@ -1438,7 +1425,7 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None,
|
|
|
003633 |
since = self.get_option('since')
|
|
|
003633 |
|
|
|
003633 |
logarchive_pattern = re.compile(r'.*((\.(zip|gz|bz2|xz))|[-.][\d]+)$')
|
|
|
003633 |
- configfile_pattern = re.compile(r"^%s/*" % self.join_sysroot("etc"))
|
|
|
003633 |
+ configfile_pattern = re.compile(r"^%s/*" % self.path_join("etc"))
|
|
|
003633 |
|
|
|
003633 |
if not self.test_predicate(pred=pred):
|
|
|
003633 |
self._log_info("skipped copy spec '%s' due to predicate (%s)" %
|
|
|
003633 |
@@ -1468,7 +1455,7 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None,
|
|
|
003633 |
return False
|
|
|
003633 |
|
|
|
003633 |
if self.use_sysroot():
|
|
|
003633 |
- copyspec = self.join_sysroot(copyspec)
|
|
|
003633 |
+ copyspec = self.path_join(copyspec)
|
|
|
003633 |
|
|
|
003633 |
files = self._expand_copy_spec(copyspec)
|
|
|
003633 |
|
|
|
003633 |
@@ -1683,7 +1670,7 @@ def _add_device_cmd(self, cmds, devices, timeout=None, sizelimit=None,
|
|
|
003633 |
if not _dev_ok:
|
|
|
003633 |
continue
|
|
|
003633 |
if prepend_path:
|
|
|
003633 |
- device = os.path.join(prepend_path, device)
|
|
|
003633 |
+ device = self.path_join(prepend_path, device)
|
|
|
003633 |
_cmd = cmd % {'dev': device}
|
|
|
003633 |
self._add_cmd_output(cmd=_cmd, timeout=timeout,
|
|
|
003633 |
sizelimit=sizelimit, chroot=chroot,
|
|
|
003633 |
@@ -2592,7 +2579,7 @@ def __expand(paths):
|
|
|
003633 |
if self.path_isfile(path) or self.path_islink(path):
|
|
|
003633 |
found_paths.append(path)
|
|
|
003633 |
elif self.path_isdir(path) and self.listdir(path):
|
|
|
003633 |
- found_paths.extend(__expand(os.path.join(path, '*')))
|
|
|
003633 |
+ found_paths.extend(__expand(self.path_join(path, '*')))
|
|
|
003633 |
else:
|
|
|
003633 |
found_paths.append(path)
|
|
|
003633 |
except PermissionError:
|
|
|
003633 |
@@ -2608,7 +2595,7 @@ def __expand(paths):
|
|
|
003633 |
if (os.access(copyspec, os.R_OK) and self.path_isdir(copyspec) and
|
|
|
003633 |
self.listdir(copyspec)):
|
|
|
003633 |
# the directory exists and is non-empty, recurse through it
|
|
|
003633 |
- copyspec = os.path.join(copyspec, '*')
|
|
|
003633 |
+ copyspec = self.path_join(copyspec, '*')
|
|
|
003633 |
expanded = glob.glob(copyspec, recursive=True)
|
|
|
003633 |
recursed_files = []
|
|
|
003633 |
for _path in expanded:
|
|
|
003633 |
@@ -2877,6 +2864,20 @@ def listdir(self, path):
|
|
|
003633 |
"""
|
|
|
003633 |
return listdir(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
|
|
|
003633 |
+ def path_join(self, path, *p):
|
|
|
003633 |
+ """Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
+ corresponding `os` call to account for sysroot
|
|
|
003633 |
+
|
|
|
003633 |
+ :param path: The leading path passed to os.path.join()
|
|
|
003633 |
+ :type path: ``str``
|
|
|
003633 |
+
|
|
|
003633 |
+ :param p: Following path section(s) to be joined with ``path``,
|
|
|
003633 |
+ an empty parameter will result in a path that ends with
|
|
|
003633 |
+ a separator
|
|
|
003633 |
+ :type p: ``str``
|
|
|
003633 |
+ """
|
|
|
003633 |
+ return path_join(path, *p, sysroot=self.sysroot)
|
|
|
003633 |
+
|
|
|
003633 |
def postproc(self):
|
|
|
003633 |
"""Perform any postprocessing. To be replaced by a plugin if required.
|
|
|
003633 |
"""
|
|
|
003633 |
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
|
003633 |
index c940e066d..b75751539 100644
|
|
|
003633 |
--- a/sos/utilities.py
|
|
|
003633 |
+++ b/sos/utilities.py
|
|
|
003633 |
@@ -242,6 +242,12 @@ def listdir(path, sysroot):
|
|
|
003633 |
return _os_wrapper(path, sysroot, 'listdir', os)
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
+def path_join(path, *p, sysroot=os.sep):
|
|
|
003633 |
+ if not path.startswith(sysroot):
|
|
|
003633 |
+ path = os.path.join(sysroot, path.lstrip(os.sep))
|
|
|
003633 |
+ return os.path.join(path, *p)
|
|
|
003633 |
+
|
|
|
003633 |
+
|
|
|
003633 |
class AsyncReader(threading.Thread):
|
|
|
003633 |
"""Used to limit command output to a given size without deadlocking
|
|
|
003633 |
sos.
|
|
|
003633 |
From 9596473d1779b9c48e9923c220aaf2b8d9b3bebf Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
Date: Thu, 18 Nov 2021 13:17:14 -0500
|
|
|
003633 |
Subject: [PATCH] [global] Align sysroot determination and usage across sos
|
|
|
003633 |
|
|
|
003633 |
The determination of sysroot - being automatic, user-specified, or
|
|
|
003633 |
controlled via environment variables in a container - has gotten muddied
|
|
|
003633 |
over time. This has resulted in different parts of the project;
|
|
|
003633 |
`Policy`, `Plugin`, `SoSComponent`, etc... to not always be in sync when
|
|
|
003633 |
sysroot is not `/`, thus causing varying and unexpected/unintended
|
|
|
003633 |
behavior.
|
|
|
003633 |
|
|
|
003633 |
Fix this by only determining sysroot within `Policy()` initialization,
|
|
|
003633 |
and then using that determination across all aspects of the project that
|
|
|
003633 |
use or reference sysroot.
|
|
|
003633 |
|
|
|
003633 |
This results in several changes:
|
|
|
003633 |
|
|
|
003633 |
- `PackageManager()` will now (again) correctly reference host package
|
|
|
003633 |
lists when sos is run in a container.
|
|
|
003633 |
|
|
|
003633 |
- `ContainerRuntime()` is now able to activate when sos is running in a
|
|
|
003633 |
container.
|
|
|
003633 |
|
|
|
003633 |
- Plugins will now properly use sysroot for _all_ plugin enablement
|
|
|
003633 |
triggers.
|
|
|
003633 |
|
|
|
003633 |
- Plugins, Policy, and SoSComponents now all reference the
|
|
|
003633 |
`self.sysroot` variable, rather than changing between `sysroot`.
|
|
|
003633 |
`_host_sysroot`, and `commons['sysroot']`. `_host_sysroot` has been
|
|
|
003633 |
removed from `Policy`.
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/archive.py | 2 +-
|
|
|
003633 |
sos/component.py | 2 +-
|
|
|
003633 |
sos/policies/__init__.py | 11 +----------
|
|
|
003633 |
sos/policies/distros/__init__.py | 33 +++++++++++++++++++------------
|
|
|
003633 |
sos/policies/distros/debian.py | 2 +-
|
|
|
003633 |
sos/policies/distros/redhat.py | 3 +--
|
|
|
003633 |
sos/policies/runtimes/__init__.py | 15 +++++++++-----
|
|
|
003633 |
sos/policies/runtimes/docker.py | 4 ++--
|
|
|
003633 |
sos/report/__init__.py | 6 ++----
|
|
|
003633 |
sos/report/plugins/__init__.py | 22 +++++++++++----------
|
|
|
003633 |
sos/report/plugins/unpackaged.py | 7 ++++---
|
|
|
003633 |
sos/utilities.py | 13 ++++++++----
|
|
|
003633 |
12 files changed, 64 insertions(+), 56 deletions(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/archive.py b/sos/archive.py
|
|
|
003633 |
index b02b247595..e3c68b7789 100644
|
|
|
003633 |
--- a/sos/archive.py
|
|
|
003633 |
+++ b/sos/archive.py
|
|
|
003633 |
@@ -153,7 +153,7 @@ def dest_path(self, name):
|
|
|
003633 |
return (os.path.join(self._archive_root, name))
|
|
|
003633 |
|
|
|
003633 |
def join_sysroot(self, path):
|
|
|
003633 |
- if path.startswith(self.sysroot):
|
|
|
003633 |
+ if not self.sysroot or path.startswith(self.sysroot):
|
|
|
003633 |
return path
|
|
|
003633 |
if path[0] == os.sep:
|
|
|
003633 |
path = path[1:]
|
|
|
003633 |
diff --git a/sos/component.py b/sos/component.py
|
|
|
003633 |
index 5ac6e47f4f..dba0aabf2b 100644
|
|
|
003633 |
--- a/sos/component.py
|
|
|
003633 |
+++ b/sos/component.py
|
|
|
003633 |
@@ -109,7 +109,7 @@ def __init__(self, parser, parsed_args, cmdline_args):
|
|
|
003633 |
try:
|
|
|
003633 |
import sos.policies
|
|
|
003633 |
self.policy = sos.policies.load(sysroot=self.opts.sysroot)
|
|
|
003633 |
- self.sysroot = self.policy.host_sysroot()
|
|
|
003633 |
+ self.sysroot = self.policy.sysroot
|
|
|
003633 |
except KeyboardInterrupt:
|
|
|
003633 |
self._exit(0)
|
|
|
003633 |
self._is_root = self.policy.is_root()
|
|
|
003633 |
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
|
|
|
003633 |
index fb8db1d724..ef9188deb4 100644
|
|
|
003633 |
--- a/sos/policies/__init__.py
|
|
|
003633 |
+++ b/sos/policies/__init__.py
|
|
|
003633 |
@@ -110,7 +110,6 @@ class Policy(object):
|
|
|
003633 |
presets = {"": PresetDefaults()}
|
|
|
003633 |
presets_path = PRESETS_PATH
|
|
|
003633 |
_in_container = False
|
|
|
003633 |
- _host_sysroot = '/'
|
|
|
003633 |
|
|
|
003633 |
def __init__(self, sysroot=None, probe_runtime=True):
|
|
|
003633 |
"""Subclasses that choose to override this initializer should call
|
|
|
003633 |
@@ -124,7 +123,7 @@ def __init__(self, sysroot=None, probe_runtime=True):
|
|
|
003633 |
self.package_manager = PackageManager()
|
|
|
003633 |
self.valid_subclasses = [IndependentPlugin]
|
|
|
003633 |
self.set_exec_path()
|
|
|
003633 |
- self._host_sysroot = sysroot
|
|
|
003633 |
+ self.sysroot = sysroot
|
|
|
003633 |
self.register_presets(GENERIC_PRESETS)
|
|
|
003633 |
|
|
|
003633 |
def check(self, remote=''):
|
|
|
003633 |
@@ -177,14 +176,6 @@ def in_container(self):
|
|
|
003633 |
"""
|
|
|
003633 |
return self._in_container
|
|
|
003633 |
|
|
|
003633 |
- def host_sysroot(self):
|
|
|
003633 |
- """Get the host's default sysroot
|
|
|
003633 |
-
|
|
|
003633 |
- :returns: Host sysroot
|
|
|
003633 |
- :rtype: ``str`` or ``None``
|
|
|
003633 |
- """
|
|
|
003633 |
- return self._host_sysroot
|
|
|
003633 |
-
|
|
|
003633 |
def dist_version(self):
|
|
|
003633 |
"""
|
|
|
003633 |
Return the OS version
|
|
|
003633 |
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
|
|
003633 |
index 7bdc81b852..c69fc1e73c 100644
|
|
|
003633 |
--- a/sos/policies/distros/__init__.py
|
|
|
003633 |
+++ b/sos/policies/distros/__init__.py
|
|
|
003633 |
@@ -71,19 +71,18 @@ class LinuxPolicy(Policy):
|
|
|
003633 |
def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
|
|
003633 |
super(LinuxPolicy, self).__init__(sysroot=sysroot,
|
|
|
003633 |
probe_runtime=probe_runtime)
|
|
|
003633 |
- self.init_kernel_modules()
|
|
|
003633 |
|
|
|
003633 |
- # need to set _host_sysroot before PackageManager()
|
|
|
003633 |
if sysroot:
|
|
|
003633 |
- self._container_init()
|
|
|
003633 |
- self._host_sysroot = sysroot
|
|
|
003633 |
+ self.sysroot = sysroot
|
|
|
003633 |
else:
|
|
|
003633 |
- sysroot = self._container_init()
|
|
|
003633 |
+ self.sysroot = self._container_init()
|
|
|
003633 |
+
|
|
|
003633 |
+ self.init_kernel_modules()
|
|
|
003633 |
|
|
|
003633 |
if init is not None:
|
|
|
003633 |
self.init_system = init
|
|
|
003633 |
elif os.path.isdir("/run/systemd/system/"):
|
|
|
003633 |
- self.init_system = SystemdInit(chroot=sysroot)
|
|
|
003633 |
+ self.init_system = SystemdInit(chroot=self.sysroot)
|
|
|
003633 |
else:
|
|
|
003633 |
self.init_system = InitSystem()
|
|
|
003633 |
|
|
|
003633 |
@@ -149,27 +148,30 @@ def _container_init(self):
|
|
|
003633 |
if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
|
|
003633 |
self._in_container = True
|
|
|
003633 |
if ENV_HOST_SYSROOT in os.environ:
|
|
|
003633 |
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
|
003633 |
- use_sysroot = self._in_container and self._host_sysroot is not None
|
|
|
003633 |
+ _host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
|
|
003633 |
+ use_sysroot = self._in_container and _host_sysroot is not None
|
|
|
003633 |
if use_sysroot:
|
|
|
003633 |
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
|
|
003633 |
+ host_tmp_dir = os.path.abspath(_host_sysroot + self._tmp_dir)
|
|
|
003633 |
self._tmp_dir = host_tmp_dir
|
|
|
003633 |
- return self._host_sysroot if use_sysroot else None
|
|
|
003633 |
+ return _host_sysroot if use_sysroot else None
|
|
|
003633 |
|
|
|
003633 |
def init_kernel_modules(self):
|
|
|
003633 |
"""Obtain a list of loaded kernel modules to reference later for plugin
|
|
|
003633 |
enablement and SoSPredicate checks
|
|
|
003633 |
"""
|
|
|
003633 |
self.kernel_mods = []
|
|
|
003633 |
+ release = os.uname().release
|
|
|
003633 |
|
|
|
003633 |
# first load modules from lsmod
|
|
|
003633 |
- lines = shell_out("lsmod", timeout=0).splitlines()
|
|
|
003633 |
+ lines = shell_out("lsmod", timeout=0, chroot=self.sysroot).splitlines()
|
|
|
003633 |
self.kernel_mods.extend([
|
|
|
003633 |
line.split()[0].strip() for line in lines[1:]
|
|
|
003633 |
])
|
|
|
003633 |
|
|
|
003633 |
# next, include kernel builtins
|
|
|
003633 |
- builtins = "/usr/lib/modules/%s/modules.builtin" % os.uname().release
|
|
|
003633 |
+ builtins = self.join_sysroot(
|
|
|
003633 |
+ "/usr/lib/modules/%s/modules.builtin" % release
|
|
|
003633 |
+ )
|
|
|
003633 |
try:
|
|
|
003633 |
with open(builtins, "r") as mfile:
|
|
|
003633 |
for line in mfile:
|
|
|
003633 |
@@ -186,7 +188,7 @@ def init_kernel_modules(self):
|
|
|
003633 |
'dm_mod': 'CONFIG_BLK_DEV_DM'
|
|
|
003633 |
}
|
|
|
003633 |
|
|
|
003633 |
- booted_config = "/boot/config-%s" % os.uname().release
|
|
|
003633 |
+ booted_config = self.join_sysroot("/boot/config-%s" % release)
|
|
|
003633 |
kconfigs = []
|
|
|
003633 |
try:
|
|
|
003633 |
with open(booted_config, "r") as kfile:
|
|
|
003633 |
@@ -200,6 +202,11 @@ def init_kernel_modules(self):
|
|
|
003633 |
if config_strings[builtin] in kconfigs:
|
|
|
003633 |
self.kernel_mods.append(builtin)
|
|
|
003633 |
|
|
|
003633 |
+ def join_sysroot(self, path):
|
|
|
003633 |
+ if self.sysroot and self.sysroot != '/':
|
|
|
003633 |
+ path = os.path.join(self.sysroot, path.lstrip('/'))
|
|
|
003633 |
+ return path
|
|
|
003633 |
+
|
|
|
003633 |
def pre_work(self):
|
|
|
003633 |
# this method will be called before the gathering begins
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/policies/distros/debian.py b/sos/policies/distros/debian.py
|
|
|
003633 |
index 95b389a65e..639fd5eba3 100644
|
|
|
003633 |
--- a/sos/policies/distros/debian.py
|
|
|
003633 |
+++ b/sos/policies/distros/debian.py
|
|
|
003633 |
@@ -27,7 +27,7 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
|
|
003633 |
remote_exec=None):
|
|
|
003633 |
super(DebianPolicy, self).__init__(sysroot=sysroot, init=init,
|
|
|
003633 |
probe_runtime=probe_runtime)
|
|
|
003633 |
- self.package_manager = DpkgPackageManager(chroot=sysroot,
|
|
|
003633 |
+ self.package_manager = DpkgPackageManager(chroot=self.sysroot,
|
|
|
003633 |
remote_exec=remote_exec)
|
|
|
003633 |
self.valid_subclasses += [DebianPlugin]
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
|
|
003633 |
index eb44240736..4b14abaf3a 100644
|
|
|
003633 |
--- a/sos/policies/distros/redhat.py
|
|
|
003633 |
+++ b/sos/policies/distros/redhat.py
|
|
|
003633 |
@@ -42,7 +42,6 @@ class RedHatPolicy(LinuxPolicy):
|
|
|
003633 |
_redhat_release = '/etc/redhat-release'
|
|
|
003633 |
_tmp_dir = "/var/tmp"
|
|
|
003633 |
_in_container = False
|
|
|
003633 |
- _host_sysroot = '/'
|
|
|
003633 |
default_scl_prefix = '/opt/rh'
|
|
|
003633 |
name_pattern = 'friendly'
|
|
|
003633 |
upload_url = None
|
|
|
003633 |
@@ -57,7 +56,7 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
|
|
003633 |
probe_runtime=probe_runtime)
|
|
|
003633 |
self.usrmove = False
|
|
|
003633 |
|
|
|
003633 |
- self.package_manager = RpmPackageManager(chroot=sysroot,
|
|
|
003633 |
+ self.package_manager = RpmPackageManager(chroot=self.sysroot,
|
|
|
003633 |
remote_exec=remote_exec)
|
|
|
003633 |
|
|
|
003633 |
self.valid_subclasses += [RedHatPlugin]
|
|
|
003633 |
diff --git a/sos/policies/runtimes/__init__.py b/sos/policies/runtimes/__init__.py
|
|
|
003633 |
index f28d6a1df3..2e60ad2361 100644
|
|
|
003633 |
--- a/sos/policies/runtimes/__init__.py
|
|
|
003633 |
+++ b/sos/policies/runtimes/__init__.py
|
|
|
003633 |
@@ -64,7 +64,7 @@ def check_is_active(self):
|
|
|
003633 |
:returns: ``True`` if the runtime is active, else ``False``
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- if is_executable(self.binary):
|
|
|
003633 |
+ if is_executable(self.binary, self.policy.sysroot):
|
|
|
003633 |
self.active = True
|
|
|
003633 |
return True
|
|
|
003633 |
return False
|
|
|
003633 |
@@ -78,7 +78,7 @@ def get_containers(self, get_all=False):
|
|
|
003633 |
containers = []
|
|
|
003633 |
_cmd = "%s ps %s" % (self.binary, '-a' if get_all else '')
|
|
|
003633 |
if self.active:
|
|
|
003633 |
- out = sos_get_command_output(_cmd)
|
|
|
003633 |
+ out = sos_get_command_output(_cmd, chroot=self.policy.sysroot)
|
|
|
003633 |
if out['status'] == 0:
|
|
|
003633 |
for ent in out['output'].splitlines()[1:]:
|
|
|
003633 |
ent = ent.split()
|
|
|
003633 |
@@ -112,8 +112,10 @@ def get_images(self):
|
|
|
003633 |
images = []
|
|
|
003633 |
fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}'
|
|
|
003633 |
if self.active:
|
|
|
003633 |
- out = sos_get_command_output("%s images --format '%s'"
|
|
|
003633 |
- % (self.binary, fmt))
|
|
|
003633 |
+ out = sos_get_command_output(
|
|
|
003633 |
+ "%s images --format '%s'" % (self.binary, fmt),
|
|
|
003633 |
+ chroot=self.policy.sysroot
|
|
|
003633 |
+ )
|
|
|
003633 |
if out['status'] == 0:
|
|
|
003633 |
for ent in out['output'].splitlines():
|
|
|
003633 |
ent = ent.split()
|
|
|
003633 |
@@ -129,7 +131,10 @@ def get_volumes(self):
|
|
|
003633 |
"""
|
|
|
003633 |
vols = []
|
|
|
003633 |
if self.active:
|
|
|
003633 |
- out = sos_get_command_output("%s volume ls" % self.binary)
|
|
|
003633 |
+ out = sos_get_command_output(
|
|
|
003633 |
+ "%s volume ls" % self.binary,
|
|
|
003633 |
+ chroot=self.policy.sysroot
|
|
|
003633 |
+ )
|
|
|
003633 |
if out['status'] == 0:
|
|
|
003633 |
for ent in out['output'].splitlines()[1:]:
|
|
|
003633 |
ent = ent.split()
|
|
|
003633 |
diff --git a/sos/policies/runtimes/docker.py b/sos/policies/runtimes/docker.py
|
|
|
003633 |
index 759dfaf6a0..e81f580ec3 100644
|
|
|
003633 |
--- a/sos/policies/runtimes/docker.py
|
|
|
003633 |
+++ b/sos/policies/runtimes/docker.py
|
|
|
003633 |
@@ -18,9 +18,9 @@ class DockerContainerRuntime(ContainerRuntime):
|
|
|
003633 |
name = 'docker'
|
|
|
003633 |
binary = 'docker'
|
|
|
003633 |
|
|
|
003633 |
- def check_is_active(self):
|
|
|
003633 |
+ def check_is_active(self, sysroot=None):
|
|
|
003633 |
# the daemon must be running
|
|
|
003633 |
- if (is_executable('docker') and
|
|
|
003633 |
+ if (is_executable('docker', sysroot) and
|
|
|
003633 |
(self.policy.init_system.is_running('docker') or
|
|
|
003633 |
self.policy.init_system.is_running('snap.docker.dockerd'))):
|
|
|
003633 |
self.active = True
|
|
|
003633 |
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
|
|
003633 |
index a4c92accd3..a6c72778fc 100644
|
|
|
003633 |
--- a/sos/report/__init__.py
|
|
|
003633 |
+++ b/sos/report/__init__.py
|
|
|
003633 |
@@ -173,14 +173,12 @@ def __init__(self, parser, args, cmdline):
|
|
|
003633 |
self._set_directories()
|
|
|
003633 |
|
|
|
003633 |
msg = "default"
|
|
|
003633 |
- host_sysroot = self.policy.host_sysroot()
|
|
|
003633 |
+ self.sysroot = self.policy.sysroot
|
|
|
003633 |
# set alternate system root directory
|
|
|
003633 |
if self.opts.sysroot:
|
|
|
003633 |
msg = "cmdline"
|
|
|
003633 |
- self.sysroot = self.opts.sysroot
|
|
|
003633 |
- elif self.policy.in_container() and host_sysroot != os.sep:
|
|
|
003633 |
+ elif self.policy.in_container() and self.sysroot != os.sep:
|
|
|
003633 |
msg = "policy"
|
|
|
003633 |
- self.sysroot = host_sysroot
|
|
|
003633 |
self.soslog.debug("set sysroot to '%s' (%s)" % (self.sysroot, msg))
|
|
|
003633 |
|
|
|
003633 |
if self.opts.chroot not in chroot_modes:
|
|
|
003633 |
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
|
|
003633 |
index 46028bb124..e180ae1727 100644
|
|
|
003633 |
--- a/sos/report/plugins/__init__.py
|
|
|
003633 |
+++ b/sos/report/plugins/__init__.py
|
|
|
003633 |
@@ -724,7 +724,7 @@ def strip_sysroot(self, path):
|
|
|
003633 |
"""
|
|
|
003633 |
if not self.use_sysroot():
|
|
|
003633 |
return path
|
|
|
003633 |
- if path.startswith(self.sysroot):
|
|
|
003633 |
+ if self.sysroot and path.startswith(self.sysroot):
|
|
|
003633 |
return path[len(self.sysroot):]
|
|
|
003633 |
return path
|
|
|
003633 |
|
|
|
003633 |
@@ -743,8 +743,10 @@ def tmp_in_sysroot(self):
|
|
|
003633 |
``False``
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- paths = [self.sysroot, self.archive.get_tmp_dir()]
|
|
|
003633 |
- return os.path.commonprefix(paths) == self.sysroot
|
|
|
003633 |
+ # if sysroot is still None, that implies '/'
|
|
|
003633 |
+ _sysroot = self.sysroot or '/'
|
|
|
003633 |
+ paths = [_sysroot, self.archive.get_tmp_dir()]
|
|
|
003633 |
+ return os.path.commonprefix(paths) == _sysroot
|
|
|
003633 |
|
|
|
003633 |
def is_installed(self, package_name):
|
|
|
003633 |
"""Is the package $package_name installed?
|
|
|
003633 |
@@ -2621,7 +2623,7 @@ def __expand(paths):
|
|
|
003633 |
return list(set(expanded))
|
|
|
003633 |
|
|
|
003633 |
def _collect_copy_specs(self):
|
|
|
003633 |
- for path in self.copy_paths:
|
|
|
003633 |
+ for path in sorted(self.copy_paths, reverse=True):
|
|
|
003633 |
self._log_info("collecting path '%s'" % path)
|
|
|
003633 |
self._do_copy_path(path)
|
|
|
003633 |
self.generate_copyspec_tags()
|
|
|
003633 |
@@ -2749,7 +2751,7 @@ def _check_plugin_triggers(self, files, packages, commands, services,
|
|
|
003633 |
|
|
|
003633 |
return ((any(self.path_exists(fname) for fname in files) or
|
|
|
003633 |
any(self.is_installed(pkg) for pkg in packages) or
|
|
|
003633 |
- any(is_executable(cmd) for cmd in commands) or
|
|
|
003633 |
+ any(is_executable(cmd, self.sysroot) for cmd in commands) or
|
|
|
003633 |
any(self.is_module_loaded(mod) for mod in self.kernel_mods) or
|
|
|
003633 |
any(self.is_service(svc) for svc in services) or
|
|
|
003633 |
any(self.container_exists(cntr) for cntr in containers)) and
|
|
|
003633 |
@@ -2817,7 +2819,7 @@ def path_exists(self, path):
|
|
|
003633 |
:returns: True if the path exists in sysroot, else False
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- return path_exists(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
+ return path_exists(path, self.sysroot)
|
|
|
003633 |
|
|
|
003633 |
def path_isdir(self, path):
|
|
|
003633 |
"""Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
@@ -2830,7 +2832,7 @@ def path_isdir(self, path):
|
|
|
003633 |
:returns: True if the path is a dir, else False
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- return path_isdir(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
+ return path_isdir(path, self.sysroot)
|
|
|
003633 |
|
|
|
003633 |
def path_isfile(self, path):
|
|
|
003633 |
"""Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
@@ -2843,7 +2845,7 @@ def path_isfile(self, path):
|
|
|
003633 |
:returns: True if the path is a file, else False
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- return path_isfile(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
+ return path_isfile(path, self.sysroot)
|
|
|
003633 |
|
|
|
003633 |
def path_islink(self, path):
|
|
|
003633 |
"""Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
@@ -2856,7 +2858,7 @@ def path_islink(self, path):
|
|
|
003633 |
:returns: True if the path is a link, else False
|
|
|
003633 |
:rtype: ``bool``
|
|
|
003633 |
"""
|
|
|
003633 |
- return path_islink(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
+ return path_islink(path, self.sysroot)
|
|
|
003633 |
|
|
|
003633 |
def listdir(self, path):
|
|
|
003633 |
"""Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
@@ -2869,7 +2871,7 @@ def listdir(self, path):
|
|
|
003633 |
:returns: Contents of path, if it is a directory
|
|
|
003633 |
:rtype: ``list``
|
|
|
003633 |
"""
|
|
|
003633 |
- return listdir(path, self.commons['cmdlineopts'].sysroot)
|
|
|
003633 |
+ return listdir(path, self.sysroot)
|
|
|
003633 |
|
|
|
003633 |
def path_join(self, path, *p):
|
|
|
003633 |
"""Helper to call the sos.utilities wrapper that allows the
|
|
|
003633 |
diff --git a/sos/report/plugins/unpackaged.py b/sos/report/plugins/unpackaged.py
|
|
|
003633 |
index 772b1d1fbb..24203c4b13 100644
|
|
|
003633 |
--- a/sos/report/plugins/unpackaged.py
|
|
|
003633 |
+++ b/sos/report/plugins/unpackaged.py
|
|
|
003633 |
@@ -58,10 +58,11 @@ def format_output(files):
|
|
|
003633 |
"""
|
|
|
003633 |
expanded = []
|
|
|
003633 |
for f in files:
|
|
|
003633 |
- if self.path_islink(f):
|
|
|
003633 |
- expanded.append("{} -> {}".format(f, os.readlink(f)))
|
|
|
003633 |
+ fp = self.path_join(f)
|
|
|
003633 |
+ if self.path_islink(fp):
|
|
|
003633 |
+ expanded.append("{} -> {}".format(fp, os.readlink(fp)))
|
|
|
003633 |
else:
|
|
|
003633 |
- expanded.append(f)
|
|
|
003633 |
+ expanded.append(fp)
|
|
|
003633 |
return expanded
|
|
|
003633 |
|
|
|
003633 |
# Check command predicate to avoid costly processing
|
|
|
003633 |
diff --git a/sos/utilities.py b/sos/utilities.py
|
|
|
003633 |
index b757515397..d66309334b 100644
|
|
|
003633 |
--- a/sos/utilities.py
|
|
|
003633 |
+++ b/sos/utilities.py
|
|
|
003633 |
@@ -96,11 +96,15 @@ def grep(pattern, *files_or_paths):
|
|
|
003633 |
return matches
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
-def is_executable(command):
|
|
|
003633 |
+def is_executable(command, sysroot=None):
|
|
|
003633 |
"""Returns if a command matches an executable on the PATH"""
|
|
|
003633 |
|
|
|
003633 |
paths = os.environ.get("PATH", "").split(os.path.pathsep)
|
|
|
003633 |
candidates = [command] + [os.path.join(p, command) for p in paths]
|
|
|
003633 |
+ if sysroot:
|
|
|
003633 |
+ candidates += [
|
|
|
003633 |
+ os.path.join(sysroot, c.lstrip('/')) for c in candidates
|
|
|
003633 |
+ ]
|
|
|
003633 |
return any(os.access(path, os.X_OK) for path in candidates)
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
@@ -216,8 +220,9 @@ def get_human_readable(size, precision=2):
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
def _os_wrapper(path, sysroot, method, module=os.path):
|
|
|
003633 |
- if sysroot not in [None, '/']:
|
|
|
003633 |
- path = os.path.join(sysroot, path.lstrip('/'))
|
|
|
003633 |
+ if sysroot and sysroot != os.sep:
|
|
|
003633 |
+ if not path.startswith(sysroot):
|
|
|
003633 |
+ path = os.path.join(sysroot, path.lstrip('/'))
|
|
|
003633 |
_meth = getattr(module, method)
|
|
|
003633 |
return _meth(path)
|
|
|
003633 |
|
|
|
003633 |
@@ -243,7 +248,7 @@ def listdir(path, sysroot):
|
|
|
003633 |
|
|
|
003633 |
|
|
|
003633 |
def path_join(path, *p, sysroot=os.sep):
|
|
|
003633 |
- if not path.startswith(sysroot):
|
|
|
003633 |
+ if sysroot and not path.startswith(sysroot):
|
|
|
003633 |
path = os.path.join(sysroot, path.lstrip(os.sep))
|
|
|
003633 |
return os.path.join(path, *p)
|
|
|
003633 |
|
|
|
003633 |
From a43124e1f6217107838eed4d70339d100cbbc77a Mon Sep 17 00:00:00 2001
|
|
|
003633 |
From: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
Date: Wed, 9 Feb 2022 19:45:27 +0100
|
|
|
003633 |
Subject: [PATCH] [policies] Set fallback to None sysroot
|
|
|
003633 |
|
|
|
003633 |
9596473 commit added a regression allowing to set sysroot to None
|
|
|
003633 |
when running sos report on a regular system (outside a container). In
|
|
|
003633 |
such a case, we need to fallback to '/' sysroot.
|
|
|
003633 |
|
|
|
003633 |
Resolves: #2846
|
|
|
003633 |
|
|
|
003633 |
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
|
|
003633 |
---
|
|
|
003633 |
sos/policies/distros/__init__.py | 2 +-
|
|
|
003633 |
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
|
003633 |
|
|
|
003633 |
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
|
|
003633 |
index f3c1de11..9048f1c4 100644
|
|
|
003633 |
--- a/sos/policies/distros/__init__.py
|
|
|
003633 |
+++ b/sos/policies/distros/__init__.py
|
|
|
003633 |
@@ -78,7 +78,7 @@ class LinuxPolicy(Policy):
|
|
|
003633 |
if sysroot:
|
|
|
003633 |
self.sysroot = sysroot
|
|
|
003633 |
else:
|
|
|
003633 |
- self.sysroot = self._container_init()
|
|
|
003633 |
+ self.sysroot = self._container_init() or '/'
|
|
|
003633 |
|
|
|
003633 |
self.init_kernel_modules()
|
|
|
003633 |
|
|
|
003633 |
--
|
|
|
003633 |
2.34.1
|
|
|
003633 |
|