import sos-4.2-15.el8
This commit is contained in:
parent
f3fbf14566
commit
d9791f66ed
@ -417,3 +417,900 @@ index ef61fb344..e0617b45e 100644
|
||||
self.ui_log.info("")
|
||||
|
||||
# package up and compress the results
|
||||
From f22efe044f1f0565b57d6aeca2081a5227e0312c Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 14 Feb 2022 09:37:30 -0500
|
||||
Subject: [PATCH] [utilities] Don't try to chroot to /
|
||||
|
||||
With the recent fix for sysroot being `None` to always being (correctly)
|
||||
`/`, we should guard against situations where `sos_get_command_output()`
|
||||
would now try to chroot to `/` before running any command. Incidentally,
|
||||
this would also cause our unittests to fail if they were run by a
|
||||
non-root user.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/utilities.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sos/utilities.py b/sos/utilities.py
|
||||
index 6b13415b..d782123a 100644
|
||||
--- a/sos/utilities.py
|
||||
+++ b/sos/utilities.py
|
||||
@@ -120,7 +120,7 @@ def sos_get_command_output(command, timeout=TIMEOUT_DEFAULT, stderr=False,
|
||||
# closure are caught in the parent (chroot and chdir are bound from
|
||||
# the enclosing scope).
|
||||
def _child_prep_fn():
|
||||
- if (chroot):
|
||||
+ if chroot and chroot != '/':
|
||||
os.chroot(chroot)
|
||||
if (chdir):
|
||||
os.chdir(chdir)
|
||||
--
|
||||
2.34.1
|
||||
From 3d064102f8ca6662fd9602512e1cb05cf8746dfd Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 27 Sep 2021 19:01:16 -0400
|
||||
Subject: [PATCH] [Systemd, Policy] Correct InitSystem chrooting when chroot is
|
||||
needed
|
||||
|
||||
This commit resolves a situation in which `sos` is being run in a
|
||||
container but the `SystemdInit` InitSystem would not properly load
|
||||
information from the host, thus causing the `Plugin.is_service*()`
|
||||
methods to erroneously fail or return `False`.
|
||||
|
||||
Fix this scenario by pulling the `_container_init()` and related logic
|
||||
to check for a containerized host sysroot out of the Red Hat specific
|
||||
policy and into the base `LinuxPolicy` class so that the init system can
|
||||
be initialized with the correct sysroot, which is now used to chroot the
|
||||
calls to the relevant `systemctl` commands.
|
||||
|
||||
For now, this does impose the use of looking for the `container` env var
|
||||
(automatically set by docker, podman, and crio regardless of
|
||||
distribution) and the use of the `HOST` env var to read where the host's
|
||||
`/` filesystem is mounted within the container. If desired in the
|
||||
future, this can be changed to allow policy-specific overrides. For now
|
||||
however, this extends host collection via an sos container for all
|
||||
distributions currently shipping sos.
|
||||
|
||||
Note that this issue only affected the `InitSystem` abstraction for
|
||||
loading information about local services, and did not affect init system
|
||||
related commands called by plugins as part of those collections.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/policies/distros/__init__.py | 28 ++++++++++++++++++++++++++-
|
||||
sos/policies/distros/redhat.py | 27 +-------------------------
|
||||
sos/policies/init_systems/__init__.py | 13 +++++++++++--
|
||||
sos/policies/init_systems/systemd.py | 7 ++++---
|
||||
4 files changed, 43 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
||||
index f5b9fd5b01..c33a356a75 100644
|
||||
--- a/sos/policies/distros/__init__.py
|
||||
+++ b/sos/policies/distros/__init__.py
|
||||
@@ -29,6 +29,10 @@
|
||||
except ImportError:
|
||||
REQUESTS_LOADED = False
|
||||
|
||||
+# Container environment variables for detecting if we're in a container
|
||||
+ENV_CONTAINER = 'container'
|
||||
+ENV_HOST_SYSROOT = 'HOST'
|
||||
+
|
||||
|
||||
class LinuxPolicy(Policy):
|
||||
"""This policy is meant to be an abc class that provides common
|
||||
@@ -69,10 +73,17 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
||||
probe_runtime=probe_runtime)
|
||||
self.init_kernel_modules()
|
||||
|
||||
+ # need to set _host_sysroot before PackageManager()
|
||||
+ if sysroot:
|
||||
+ self._container_init()
|
||||
+ self._host_sysroot = sysroot
|
||||
+ else:
|
||||
+ sysroot = self._container_init()
|
||||
+
|
||||
if init is not None:
|
||||
self.init_system = init
|
||||
elif os.path.isdir("/run/systemd/system/"):
|
||||
- self.init_system = SystemdInit()
|
||||
+ self.init_system = SystemdInit(chroot=sysroot)
|
||||
else:
|
||||
self.init_system = InitSystem()
|
||||
|
||||
@@ -130,6 +141,21 @@ def get_local_name(self):
|
||||
def sanitize_filename(self, name):
|
||||
return re.sub(r"[^-a-z,A-Z.0-9]", "", name)
|
||||
|
||||
+ def _container_init(self):
|
||||
+ """Check if sos is running in a container and perform container
|
||||
+ specific initialisation based on ENV_HOST_SYSROOT.
|
||||
+ """
|
||||
+ if ENV_CONTAINER in os.environ:
|
||||
+ if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
+ self._in_container = True
|
||||
+ if ENV_HOST_SYSROOT in os.environ:
|
||||
+ self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
+ use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
+ if use_sysroot:
|
||||
+ host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
+ self._tmp_dir = host_tmp_dir
|
||||
+ return self._host_sysroot if use_sysroot else None
|
||||
+
|
||||
def init_kernel_modules(self):
|
||||
"""Obtain a list of loaded kernel modules to reference later for plugin
|
||||
enablement and SoSPredicate checks
|
||||
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
||||
index b3a84336be..3476e21fb2 100644
|
||||
--- a/sos/policies/distros/redhat.py
|
||||
+++ b/sos/policies/distros/redhat.py
|
||||
@@ -17,7 +17,7 @@
|
||||
from sos.presets.redhat import (RHEL_PRESETS, ATOMIC_PRESETS, RHV, RHEL,
|
||||
CB, RHOSP, RHOCP, RH_CFME, RH_SATELLITE,
|
||||
ATOMIC)
|
||||
-from sos.policies.distros import LinuxPolicy
|
||||
+from sos.policies.distros import LinuxPolicy, ENV_HOST_SYSROOT
|
||||
from sos.policies.package_managers.rpm import RpmPackageManager
|
||||
from sos import _sos as _
|
||||
|
||||
@@ -56,12 +56,6 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
||||
super(RedHatPolicy, self).__init__(sysroot=sysroot, init=init,
|
||||
probe_runtime=probe_runtime)
|
||||
self.usrmove = False
|
||||
- # need to set _host_sysroot before PackageManager()
|
||||
- if sysroot:
|
||||
- self._container_init()
|
||||
- self._host_sysroot = sysroot
|
||||
- else:
|
||||
- sysroot = self._container_init()
|
||||
|
||||
self.package_manager = RpmPackageManager(chroot=sysroot,
|
||||
remote_exec=remote_exec)
|
||||
@@ -140,21 +134,6 @@ def transform_path(path):
|
||||
else:
|
||||
return files
|
||||
|
||||
- def _container_init(self):
|
||||
- """Check if sos is running in a container and perform container
|
||||
- specific initialisation based on ENV_HOST_SYSROOT.
|
||||
- """
|
||||
- if ENV_CONTAINER in os.environ:
|
||||
- if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
- self._in_container = True
|
||||
- if ENV_HOST_SYSROOT in os.environ:
|
||||
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
- use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
- if use_sysroot:
|
||||
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
- self._tmp_dir = host_tmp_dir
|
||||
- return self._host_sysroot if use_sysroot else None
|
||||
-
|
||||
def runlevel_by_service(self, name):
|
||||
from subprocess import Popen, PIPE
|
||||
ret = []
|
||||
@@ -183,10 +162,6 @@ def get_tmp_dir(self, opt_tmp_dir):
|
||||
return opt_tmp_dir
|
||||
|
||||
|
||||
-# Container environment variables on Red Hat systems.
|
||||
-ENV_CONTAINER = 'container'
|
||||
-ENV_HOST_SYSROOT = 'HOST'
|
||||
-
|
||||
# Legal disclaimer text for Red Hat products
|
||||
disclaimer_text = """
|
||||
Any information provided to %(vendor)s will be treated in \
|
||||
diff --git a/sos/policies/init_systems/__init__.py b/sos/policies/init_systems/__init__.py
|
||||
index dd663e6522..beac44cee3 100644
|
||||
--- a/sos/policies/init_systems/__init__.py
|
||||
+++ b/sos/policies/init_systems/__init__.py
|
||||
@@ -29,9 +29,14 @@ class InitSystem():
|
||||
status of services
|
||||
:type query_cmd: ``str``
|
||||
|
||||
+ :param chroot: Location to chroot to for any command execution, i.e. the
|
||||
+ sysroot if we're running in a container
|
||||
+ :type chroot: ``str`` or ``None``
|
||||
+
|
||||
"""
|
||||
|
||||
- def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
||||
+ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None,
|
||||
+ chroot=None):
|
||||
"""Initialize a new InitSystem()"""
|
||||
|
||||
self.services = {}
|
||||
@@ -39,6 +44,7 @@ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
||||
self.init_cmd = init_cmd
|
||||
self.list_cmd = "%s %s" % (self.init_cmd, list_cmd) or None
|
||||
self.query_cmd = "%s %s" % (self.init_cmd, query_cmd) or None
|
||||
+ self.chroot = chroot
|
||||
|
||||
def is_enabled(self, name):
|
||||
"""Check if given service name is enabled
|
||||
@@ -108,7 +114,10 @@ def _query_service(self, name):
|
||||
"""Query an individual service"""
|
||||
if self.query_cmd:
|
||||
try:
|
||||
- return sos_get_command_output("%s %s" % (self.query_cmd, name))
|
||||
+ return sos_get_command_output(
|
||||
+ "%s %s" % (self.query_cmd, name),
|
||||
+ chroot=self.chroot
|
||||
+ )
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
diff --git a/sos/policies/init_systems/systemd.py b/sos/policies/init_systems/systemd.py
|
||||
index 1b138f97b3..76dc57e27f 100644
|
||||
--- a/sos/policies/init_systems/systemd.py
|
||||
+++ b/sos/policies/init_systems/systemd.py
|
||||
@@ -15,11 +15,12 @@
|
||||
class SystemdInit(InitSystem):
|
||||
"""InitSystem abstraction for SystemD systems"""
|
||||
|
||||
- def __init__(self):
|
||||
+ def __init__(self, chroot=None):
|
||||
super(SystemdInit, self).__init__(
|
||||
init_cmd='systemctl',
|
||||
list_cmd='list-unit-files --type=service',
|
||||
- query_cmd='status'
|
||||
+ query_cmd='status',
|
||||
+ chroot=chroot
|
||||
)
|
||||
self.load_all_services()
|
||||
|
||||
@@ -30,7 +31,7 @@ def parse_query(self, output):
|
||||
return 'unknown'
|
||||
|
||||
def load_all_services(self):
|
||||
- svcs = shell_out(self.list_cmd).splitlines()[1:]
|
||||
+ svcs = shell_out(self.list_cmd, chroot=self.chroot).splitlines()[1:]
|
||||
for line in svcs:
|
||||
try:
|
||||
name = line.split('.service')[0]
|
||||
From e869bc84c714bfc2249bbcb84e14908049ee42c4 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 27 Sep 2021 12:07:08 -0400
|
||||
Subject: [PATCH] [Plugin,utilities] Add sysroot wrapper for os.path.join
|
||||
|
||||
Adds a wrapper for `os.path.join()` which accounts for non-/ sysroots,
|
||||
like we have done previously for other `os.path` methods. Further
|
||||
updates `Plugin()` to use this wrapper where appropriate.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/report/plugins/__init__.py | 43 +++++++++++++++++-----------------
|
||||
sos/utilities.py | 6 +++++
|
||||
2 files changed, 28 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index c635b8de9..1f84bca49 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -13,7 +13,7 @@
|
||||
from sos.utilities import (sos_get_command_output, import_module, grep,
|
||||
fileobj, tail, is_executable, TIMEOUT_DEFAULT,
|
||||
path_exists, path_isdir, path_isfile, path_islink,
|
||||
- listdir)
|
||||
+ listdir, path_join)
|
||||
|
||||
import os
|
||||
import glob
|
||||
@@ -708,19 +708,6 @@ def _log_info(self, msg):
|
||||
def _log_debug(self, msg):
|
||||
self.soslog.debug(self._format_msg(msg))
|
||||
|
||||
- def join_sysroot(self, path):
|
||||
- """Join a given path with the configured sysroot
|
||||
-
|
||||
- :param path: The filesystem path that needs to be joined
|
||||
- :type path: ``str``
|
||||
-
|
||||
- :returns: The joined filesystem path
|
||||
- :rtype: ``str``
|
||||
- """
|
||||
- if path[0] == os.sep:
|
||||
- path = path[1:]
|
||||
- return os.path.join(self.sysroot, path)
|
||||
-
|
||||
def strip_sysroot(self, path):
|
||||
"""Remove the configured sysroot from a filesystem path
|
||||
|
||||
@@ -1176,7 +1163,7 @@ def _copy_dir(self, srcpath):
|
||||
|
||||
def _get_dest_for_srcpath(self, srcpath):
|
||||
if self.use_sysroot():
|
||||
- srcpath = self.join_sysroot(srcpath)
|
||||
+ srcpath = self.path_join(srcpath)
|
||||
for copied in self.copied_files:
|
||||
if srcpath == copied["srcpath"]:
|
||||
return copied["dstpath"]
|
||||
@@ -1284,7 +1271,7 @@ def add_forbidden_path(self, forbidden, recursive=False):
|
||||
forbidden = [forbidden]
|
||||
|
||||
if self.use_sysroot():
|
||||
- forbidden = [self.join_sysroot(f) for f in forbidden]
|
||||
+ forbidden = [self.path_join(f) for f in forbidden]
|
||||
|
||||
for forbid in forbidden:
|
||||
self._log_info("adding forbidden path '%s'" % forbid)
|
||||
@@ -1438,7 +1425,7 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None,
|
||||
since = self.get_option('since')
|
||||
|
||||
logarchive_pattern = re.compile(r'.*((\.(zip|gz|bz2|xz))|[-.][\d]+)$')
|
||||
- configfile_pattern = re.compile(r"^%s/*" % self.join_sysroot("etc"))
|
||||
+ configfile_pattern = re.compile(r"^%s/*" % self.path_join("etc"))
|
||||
|
||||
if not self.test_predicate(pred=pred):
|
||||
self._log_info("skipped copy spec '%s' due to predicate (%s)" %
|
||||
@@ -1468,7 +1455,7 @@ def add_copy_spec(self, copyspecs, sizelimit=None, maxage=None,
|
||||
return False
|
||||
|
||||
if self.use_sysroot():
|
||||
- copyspec = self.join_sysroot(copyspec)
|
||||
+ copyspec = self.path_join(copyspec)
|
||||
|
||||
files = self._expand_copy_spec(copyspec)
|
||||
|
||||
@@ -1683,7 +1670,7 @@ def _add_device_cmd(self, cmds, devices, timeout=None, sizelimit=None,
|
||||
if not _dev_ok:
|
||||
continue
|
||||
if prepend_path:
|
||||
- device = os.path.join(prepend_path, device)
|
||||
+ device = self.path_join(prepend_path, device)
|
||||
_cmd = cmd % {'dev': device}
|
||||
self._add_cmd_output(cmd=_cmd, timeout=timeout,
|
||||
sizelimit=sizelimit, chroot=chroot,
|
||||
@@ -2592,7 +2579,7 @@ def __expand(paths):
|
||||
if self.path_isfile(path) or self.path_islink(path):
|
||||
found_paths.append(path)
|
||||
elif self.path_isdir(path) and self.listdir(path):
|
||||
- found_paths.extend(__expand(os.path.join(path, '*')))
|
||||
+ found_paths.extend(__expand(self.path_join(path, '*')))
|
||||
else:
|
||||
found_paths.append(path)
|
||||
except PermissionError:
|
||||
@@ -2608,7 +2595,7 @@ def __expand(paths):
|
||||
if (os.access(copyspec, os.R_OK) and self.path_isdir(copyspec) and
|
||||
self.listdir(copyspec)):
|
||||
# the directory exists and is non-empty, recurse through it
|
||||
- copyspec = os.path.join(copyspec, '*')
|
||||
+ copyspec = self.path_join(copyspec, '*')
|
||||
expanded = glob.glob(copyspec, recursive=True)
|
||||
recursed_files = []
|
||||
for _path in expanded:
|
||||
@@ -2877,6 +2864,20 @@ def listdir(self, path):
|
||||
"""
|
||||
return listdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
|
||||
+ def path_join(self, path, *p):
|
||||
+ """Helper to call the sos.utilities wrapper that allows the
|
||||
+ corresponding `os` call to account for sysroot
|
||||
+
|
||||
+ :param path: The leading path passed to os.path.join()
|
||||
+ :type path: ``str``
|
||||
+
|
||||
+ :param p: Following path section(s) to be joined with ``path``,
|
||||
+ an empty parameter will result in a path that ends with
|
||||
+ a separator
|
||||
+ :type p: ``str``
|
||||
+ """
|
||||
+ return path_join(path, *p, sysroot=self.sysroot)
|
||||
+
|
||||
def postproc(self):
|
||||
"""Perform any postprocessing. To be replaced by a plugin if required.
|
||||
"""
|
||||
diff --git a/sos/utilities.py b/sos/utilities.py
|
||||
index c940e066d..b75751539 100644
|
||||
--- a/sos/utilities.py
|
||||
+++ b/sos/utilities.py
|
||||
@@ -242,6 +242,12 @@ def listdir(path, sysroot):
|
||||
return _os_wrapper(path, sysroot, 'listdir', os)
|
||||
|
||||
|
||||
+def path_join(path, *p, sysroot=os.sep):
|
||||
+ if not path.startswith(sysroot):
|
||||
+ path = os.path.join(sysroot, path.lstrip(os.sep))
|
||||
+ return os.path.join(path, *p)
|
||||
+
|
||||
+
|
||||
class AsyncReader(threading.Thread):
|
||||
"""Used to limit command output to a given size without deadlocking
|
||||
sos.
|
||||
From 9596473d1779b9c48e9923c220aaf2b8d9b3bebf Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Thu, 18 Nov 2021 13:17:14 -0500
|
||||
Subject: [PATCH] [global] Align sysroot determination and usage across sos
|
||||
|
||||
The determination of sysroot - being automatic, user-specified, or
|
||||
controlled via environment variables in a container - has gotten muddied
|
||||
over time. This has resulted in different parts of the project;
|
||||
`Policy`, `Plugin`, `SoSComponent`, etc... to not always be in sync when
|
||||
sysroot is not `/`, thus causing varying and unexpected/unintended
|
||||
behavior.
|
||||
|
||||
Fix this by only determining sysroot within `Policy()` initialization,
|
||||
and then using that determination across all aspects of the project that
|
||||
use or reference sysroot.
|
||||
|
||||
This results in several changes:
|
||||
|
||||
- `PackageManager()` will now (again) correctly reference host package
|
||||
lists when sos is run in a container.
|
||||
|
||||
- `ContainerRuntime()` is now able to activate when sos is running in a
|
||||
container.
|
||||
|
||||
- Plugins will now properly use sysroot for _all_ plugin enablement
|
||||
triggers.
|
||||
|
||||
- Plugins, Policy, and SoSComponents now all reference the
|
||||
`self.sysroot` variable, rather than changing between `sysroot`.
|
||||
`_host_sysroot`, and `commons['sysroot']`. `_host_sysroot` has been
|
||||
removed from `Policy`.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/archive.py | 2 +-
|
||||
sos/component.py | 2 +-
|
||||
sos/policies/__init__.py | 11 +----------
|
||||
sos/policies/distros/__init__.py | 33 +++++++++++++++++++------------
|
||||
sos/policies/distros/debian.py | 2 +-
|
||||
sos/policies/distros/redhat.py | 3 +--
|
||||
sos/policies/runtimes/__init__.py | 15 +++++++++-----
|
||||
sos/policies/runtimes/docker.py | 4 ++--
|
||||
sos/report/__init__.py | 6 ++----
|
||||
sos/report/plugins/__init__.py | 22 +++++++++++----------
|
||||
sos/report/plugins/unpackaged.py | 7 ++++---
|
||||
sos/utilities.py | 13 ++++++++----
|
||||
12 files changed, 64 insertions(+), 56 deletions(-)
|
||||
|
||||
diff --git a/sos/archive.py b/sos/archive.py
|
||||
index b02b247595..e3c68b7789 100644
|
||||
--- a/sos/archive.py
|
||||
+++ b/sos/archive.py
|
||||
@@ -153,7 +153,7 @@ def dest_path(self, name):
|
||||
return (os.path.join(self._archive_root, name))
|
||||
|
||||
def join_sysroot(self, path):
|
||||
- if path.startswith(self.sysroot):
|
||||
+ if not self.sysroot or path.startswith(self.sysroot):
|
||||
return path
|
||||
if path[0] == os.sep:
|
||||
path = path[1:]
|
||||
diff --git a/sos/component.py b/sos/component.py
|
||||
index 5ac6e47f4f..dba0aabf2b 100644
|
||||
--- a/sos/component.py
|
||||
+++ b/sos/component.py
|
||||
@@ -109,7 +109,7 @@ def __init__(self, parser, parsed_args, cmdline_args):
|
||||
try:
|
||||
import sos.policies
|
||||
self.policy = sos.policies.load(sysroot=self.opts.sysroot)
|
||||
- self.sysroot = self.policy.host_sysroot()
|
||||
+ self.sysroot = self.policy.sysroot
|
||||
except KeyboardInterrupt:
|
||||
self._exit(0)
|
||||
self._is_root = self.policy.is_root()
|
||||
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
|
||||
index fb8db1d724..ef9188deb4 100644
|
||||
--- a/sos/policies/__init__.py
|
||||
+++ b/sos/policies/__init__.py
|
||||
@@ -110,7 +110,6 @@ class Policy(object):
|
||||
presets = {"": PresetDefaults()}
|
||||
presets_path = PRESETS_PATH
|
||||
_in_container = False
|
||||
- _host_sysroot = '/'
|
||||
|
||||
def __init__(self, sysroot=None, probe_runtime=True):
|
||||
"""Subclasses that choose to override this initializer should call
|
||||
@@ -124,7 +123,7 @@ def __init__(self, sysroot=None, probe_runtime=True):
|
||||
self.package_manager = PackageManager()
|
||||
self.valid_subclasses = [IndependentPlugin]
|
||||
self.set_exec_path()
|
||||
- self._host_sysroot = sysroot
|
||||
+ self.sysroot = sysroot
|
||||
self.register_presets(GENERIC_PRESETS)
|
||||
|
||||
def check(self, remote=''):
|
||||
@@ -177,14 +176,6 @@ def in_container(self):
|
||||
"""
|
||||
return self._in_container
|
||||
|
||||
- def host_sysroot(self):
|
||||
- """Get the host's default sysroot
|
||||
-
|
||||
- :returns: Host sysroot
|
||||
- :rtype: ``str`` or ``None``
|
||||
- """
|
||||
- return self._host_sysroot
|
||||
-
|
||||
def dist_version(self):
|
||||
"""
|
||||
Return the OS version
|
||||
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
||||
index 7bdc81b852..c69fc1e73c 100644
|
||||
--- a/sos/policies/distros/__init__.py
|
||||
+++ b/sos/policies/distros/__init__.py
|
||||
@@ -71,19 +71,18 @@ class LinuxPolicy(Policy):
|
||||
def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
||||
super(LinuxPolicy, self).__init__(sysroot=sysroot,
|
||||
probe_runtime=probe_runtime)
|
||||
- self.init_kernel_modules()
|
||||
|
||||
- # need to set _host_sysroot before PackageManager()
|
||||
if sysroot:
|
||||
- self._container_init()
|
||||
- self._host_sysroot = sysroot
|
||||
+ self.sysroot = sysroot
|
||||
else:
|
||||
- sysroot = self._container_init()
|
||||
+ self.sysroot = self._container_init()
|
||||
+
|
||||
+ self.init_kernel_modules()
|
||||
|
||||
if init is not None:
|
||||
self.init_system = init
|
||||
elif os.path.isdir("/run/systemd/system/"):
|
||||
- self.init_system = SystemdInit(chroot=sysroot)
|
||||
+ self.init_system = SystemdInit(chroot=self.sysroot)
|
||||
else:
|
||||
self.init_system = InitSystem()
|
||||
|
||||
@@ -149,27 +148,30 @@ def _container_init(self):
|
||||
if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
self._in_container = True
|
||||
if ENV_HOST_SYSROOT in os.environ:
|
||||
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
- use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
+ _host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
+ use_sysroot = self._in_container and _host_sysroot is not None
|
||||
if use_sysroot:
|
||||
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
+ host_tmp_dir = os.path.abspath(_host_sysroot + self._tmp_dir)
|
||||
self._tmp_dir = host_tmp_dir
|
||||
- return self._host_sysroot if use_sysroot else None
|
||||
+ return _host_sysroot if use_sysroot else None
|
||||
|
||||
def init_kernel_modules(self):
|
||||
"""Obtain a list of loaded kernel modules to reference later for plugin
|
||||
enablement and SoSPredicate checks
|
||||
"""
|
||||
self.kernel_mods = []
|
||||
+ release = os.uname().release
|
||||
|
||||
# first load modules from lsmod
|
||||
- lines = shell_out("lsmod", timeout=0).splitlines()
|
||||
+ lines = shell_out("lsmod", timeout=0, chroot=self.sysroot).splitlines()
|
||||
self.kernel_mods.extend([
|
||||
line.split()[0].strip() for line in lines[1:]
|
||||
])
|
||||
|
||||
# next, include kernel builtins
|
||||
- builtins = "/usr/lib/modules/%s/modules.builtin" % os.uname().release
|
||||
+ builtins = self.join_sysroot(
|
||||
+ "/usr/lib/modules/%s/modules.builtin" % release
|
||||
+ )
|
||||
try:
|
||||
with open(builtins, "r") as mfile:
|
||||
for line in mfile:
|
||||
@@ -186,7 +188,7 @@ def init_kernel_modules(self):
|
||||
'dm_mod': 'CONFIG_BLK_DEV_DM'
|
||||
}
|
||||
|
||||
- booted_config = "/boot/config-%s" % os.uname().release
|
||||
+ booted_config = self.join_sysroot("/boot/config-%s" % release)
|
||||
kconfigs = []
|
||||
try:
|
||||
with open(booted_config, "r") as kfile:
|
||||
@@ -200,6 +202,11 @@ def init_kernel_modules(self):
|
||||
if config_strings[builtin] in kconfigs:
|
||||
self.kernel_mods.append(builtin)
|
||||
|
||||
+ def join_sysroot(self, path):
|
||||
+ if self.sysroot and self.sysroot != '/':
|
||||
+ path = os.path.join(self.sysroot, path.lstrip('/'))
|
||||
+ return path
|
||||
+
|
||||
def pre_work(self):
|
||||
# this method will be called before the gathering begins
|
||||
|
||||
diff --git a/sos/policies/distros/debian.py b/sos/policies/distros/debian.py
|
||||
index 95b389a65e..639fd5eba3 100644
|
||||
--- a/sos/policies/distros/debian.py
|
||||
+++ b/sos/policies/distros/debian.py
|
||||
@@ -27,7 +27,7 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
||||
remote_exec=None):
|
||||
super(DebianPolicy, self).__init__(sysroot=sysroot, init=init,
|
||||
probe_runtime=probe_runtime)
|
||||
- self.package_manager = DpkgPackageManager(chroot=sysroot,
|
||||
+ self.package_manager = DpkgPackageManager(chroot=self.sysroot,
|
||||
remote_exec=remote_exec)
|
||||
self.valid_subclasses += [DebianPlugin]
|
||||
|
||||
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
||||
index eb44240736..4b14abaf3a 100644
|
||||
--- a/sos/policies/distros/redhat.py
|
||||
+++ b/sos/policies/distros/redhat.py
|
||||
@@ -42,7 +42,6 @@ class RedHatPolicy(LinuxPolicy):
|
||||
_redhat_release = '/etc/redhat-release'
|
||||
_tmp_dir = "/var/tmp"
|
||||
_in_container = False
|
||||
- _host_sysroot = '/'
|
||||
default_scl_prefix = '/opt/rh'
|
||||
name_pattern = 'friendly'
|
||||
upload_url = None
|
||||
@@ -57,7 +56,7 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
||||
probe_runtime=probe_runtime)
|
||||
self.usrmove = False
|
||||
|
||||
- self.package_manager = RpmPackageManager(chroot=sysroot,
|
||||
+ self.package_manager = RpmPackageManager(chroot=self.sysroot,
|
||||
remote_exec=remote_exec)
|
||||
|
||||
self.valid_subclasses += [RedHatPlugin]
|
||||
diff --git a/sos/policies/runtimes/__init__.py b/sos/policies/runtimes/__init__.py
|
||||
index f28d6a1df3..2e60ad2361 100644
|
||||
--- a/sos/policies/runtimes/__init__.py
|
||||
+++ b/sos/policies/runtimes/__init__.py
|
||||
@@ -64,7 +64,7 @@ def check_is_active(self):
|
||||
:returns: ``True`` if the runtime is active, else ``False``
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- if is_executable(self.binary):
|
||||
+ if is_executable(self.binary, self.policy.sysroot):
|
||||
self.active = True
|
||||
return True
|
||||
return False
|
||||
@@ -78,7 +78,7 @@ def get_containers(self, get_all=False):
|
||||
containers = []
|
||||
_cmd = "%s ps %s" % (self.binary, '-a' if get_all else '')
|
||||
if self.active:
|
||||
- out = sos_get_command_output(_cmd)
|
||||
+ out = sos_get_command_output(_cmd, chroot=self.policy.sysroot)
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines()[1:]:
|
||||
ent = ent.split()
|
||||
@@ -112,8 +112,10 @@ def get_images(self):
|
||||
images = []
|
||||
fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}'
|
||||
if self.active:
|
||||
- out = sos_get_command_output("%s images --format '%s'"
|
||||
- % (self.binary, fmt))
|
||||
+ out = sos_get_command_output(
|
||||
+ "%s images --format '%s'" % (self.binary, fmt),
|
||||
+ chroot=self.policy.sysroot
|
||||
+ )
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines():
|
||||
ent = ent.split()
|
||||
@@ -129,7 +131,10 @@ def get_volumes(self):
|
||||
"""
|
||||
vols = []
|
||||
if self.active:
|
||||
- out = sos_get_command_output("%s volume ls" % self.binary)
|
||||
+ out = sos_get_command_output(
|
||||
+ "%s volume ls" % self.binary,
|
||||
+ chroot=self.policy.sysroot
|
||||
+ )
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines()[1:]:
|
||||
ent = ent.split()
|
||||
diff --git a/sos/policies/runtimes/docker.py b/sos/policies/runtimes/docker.py
|
||||
index 759dfaf6a0..e81f580ec3 100644
|
||||
--- a/sos/policies/runtimes/docker.py
|
||||
+++ b/sos/policies/runtimes/docker.py
|
||||
@@ -18,9 +18,9 @@ class DockerContainerRuntime(ContainerRuntime):
|
||||
name = 'docker'
|
||||
binary = 'docker'
|
||||
|
||||
- def check_is_active(self):
|
||||
+ def check_is_active(self, sysroot=None):
|
||||
# the daemon must be running
|
||||
- if (is_executable('docker') and
|
||||
+ if (is_executable('docker', sysroot) and
|
||||
(self.policy.init_system.is_running('docker') or
|
||||
self.policy.init_system.is_running('snap.docker.dockerd'))):
|
||||
self.active = True
|
||||
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
||||
index a4c92accd3..a6c72778fc 100644
|
||||
--- a/sos/report/__init__.py
|
||||
+++ b/sos/report/__init__.py
|
||||
@@ -173,14 +173,12 @@ def __init__(self, parser, args, cmdline):
|
||||
self._set_directories()
|
||||
|
||||
msg = "default"
|
||||
- host_sysroot = self.policy.host_sysroot()
|
||||
+ self.sysroot = self.policy.sysroot
|
||||
# set alternate system root directory
|
||||
if self.opts.sysroot:
|
||||
msg = "cmdline"
|
||||
- self.sysroot = self.opts.sysroot
|
||||
- elif self.policy.in_container() and host_sysroot != os.sep:
|
||||
+ elif self.policy.in_container() and self.sysroot != os.sep:
|
||||
msg = "policy"
|
||||
- self.sysroot = host_sysroot
|
||||
self.soslog.debug("set sysroot to '%s' (%s)" % (self.sysroot, msg))
|
||||
|
||||
if self.opts.chroot not in chroot_modes:
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index 46028bb124..e180ae1727 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -724,7 +724,7 @@ def strip_sysroot(self, path):
|
||||
"""
|
||||
if not self.use_sysroot():
|
||||
return path
|
||||
- if path.startswith(self.sysroot):
|
||||
+ if self.sysroot and path.startswith(self.sysroot):
|
||||
return path[len(self.sysroot):]
|
||||
return path
|
||||
|
||||
@@ -743,8 +743,10 @@ def tmp_in_sysroot(self):
|
||||
``False``
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- paths = [self.sysroot, self.archive.get_tmp_dir()]
|
||||
- return os.path.commonprefix(paths) == self.sysroot
|
||||
+ # if sysroot is still None, that implies '/'
|
||||
+ _sysroot = self.sysroot or '/'
|
||||
+ paths = [_sysroot, self.archive.get_tmp_dir()]
|
||||
+ return os.path.commonprefix(paths) == _sysroot
|
||||
|
||||
def is_installed(self, package_name):
|
||||
"""Is the package $package_name installed?
|
||||
@@ -2621,7 +2623,7 @@ def __expand(paths):
|
||||
return list(set(expanded))
|
||||
|
||||
def _collect_copy_specs(self):
|
||||
- for path in self.copy_paths:
|
||||
+ for path in sorted(self.copy_paths, reverse=True):
|
||||
self._log_info("collecting path '%s'" % path)
|
||||
self._do_copy_path(path)
|
||||
self.generate_copyspec_tags()
|
||||
@@ -2749,7 +2751,7 @@ def _check_plugin_triggers(self, files, packages, commands, services,
|
||||
|
||||
return ((any(self.path_exists(fname) for fname in files) or
|
||||
any(self.is_installed(pkg) for pkg in packages) or
|
||||
- any(is_executable(cmd) for cmd in commands) or
|
||||
+ any(is_executable(cmd, self.sysroot) for cmd in commands) or
|
||||
any(self.is_module_loaded(mod) for mod in self.kernel_mods) or
|
||||
any(self.is_service(svc) for svc in services) or
|
||||
any(self.container_exists(cntr) for cntr in containers)) and
|
||||
@@ -2817,7 +2819,7 @@ def path_exists(self, path):
|
||||
:returns: True if the path exists in sysroot, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_exists(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_exists(path, self.sysroot)
|
||||
|
||||
def path_isdir(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2830,7 +2832,7 @@ def path_isdir(self, path):
|
||||
:returns: True if the path is a dir, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_isdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_isdir(path, self.sysroot)
|
||||
|
||||
def path_isfile(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2843,7 +2845,7 @@ def path_isfile(self, path):
|
||||
:returns: True if the path is a file, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_isfile(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_isfile(path, self.sysroot)
|
||||
|
||||
def path_islink(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2856,7 +2858,7 @@ def path_islink(self, path):
|
||||
:returns: True if the path is a link, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_islink(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_islink(path, self.sysroot)
|
||||
|
||||
def listdir(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2869,7 +2871,7 @@ def listdir(self, path):
|
||||
:returns: Contents of path, if it is a directory
|
||||
:rtype: ``list``
|
||||
"""
|
||||
- return listdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return listdir(path, self.sysroot)
|
||||
|
||||
def path_join(self, path, *p):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
diff --git a/sos/report/plugins/unpackaged.py b/sos/report/plugins/unpackaged.py
|
||||
index 772b1d1fbb..24203c4b13 100644
|
||||
--- a/sos/report/plugins/unpackaged.py
|
||||
+++ b/sos/report/plugins/unpackaged.py
|
||||
@@ -58,10 +58,11 @@ def format_output(files):
|
||||
"""
|
||||
expanded = []
|
||||
for f in files:
|
||||
- if self.path_islink(f):
|
||||
- expanded.append("{} -> {}".format(f, os.readlink(f)))
|
||||
+ fp = self.path_join(f)
|
||||
+ if self.path_islink(fp):
|
||||
+ expanded.append("{} -> {}".format(fp, os.readlink(fp)))
|
||||
else:
|
||||
- expanded.append(f)
|
||||
+ expanded.append(fp)
|
||||
return expanded
|
||||
|
||||
# Check command predicate to avoid costly processing
|
||||
diff --git a/sos/utilities.py b/sos/utilities.py
|
||||
index b757515397..d66309334b 100644
|
||||
--- a/sos/utilities.py
|
||||
+++ b/sos/utilities.py
|
||||
@@ -96,11 +96,15 @@ def grep(pattern, *files_or_paths):
|
||||
return matches
|
||||
|
||||
|
||||
-def is_executable(command):
|
||||
+def is_executable(command, sysroot=None):
|
||||
"""Returns if a command matches an executable on the PATH"""
|
||||
|
||||
paths = os.environ.get("PATH", "").split(os.path.pathsep)
|
||||
candidates = [command] + [os.path.join(p, command) for p in paths]
|
||||
+ if sysroot:
|
||||
+ candidates += [
|
||||
+ os.path.join(sysroot, c.lstrip('/')) for c in candidates
|
||||
+ ]
|
||||
return any(os.access(path, os.X_OK) for path in candidates)
|
||||
|
||||
|
||||
@@ -216,8 +220,9 @@ def get_human_readable(size, precision=2):
|
||||
|
||||
|
||||
def _os_wrapper(path, sysroot, method, module=os.path):
|
||||
- if sysroot not in [None, '/']:
|
||||
- path = os.path.join(sysroot, path.lstrip('/'))
|
||||
+ if sysroot and sysroot != os.sep:
|
||||
+ if not path.startswith(sysroot):
|
||||
+ path = os.path.join(sysroot, path.lstrip('/'))
|
||||
_meth = getattr(module, method)
|
||||
return _meth(path)
|
||||
|
||||
@@ -243,7 +248,7 @@ def listdir(path, sysroot):
|
||||
|
||||
|
||||
def path_join(path, *p, sysroot=os.sep):
|
||||
- if not path.startswith(sysroot):
|
||||
+ if sysroot and not path.startswith(sysroot):
|
||||
path = os.path.join(sysroot, path.lstrip(os.sep))
|
||||
return os.path.join(path, *p)
|
||||
|
||||
From a43124e1f6217107838eed4d70339d100cbbc77a Mon Sep 17 00:00:00 2001
|
||||
From: Pavel Moravec <pmoravec@redhat.com>
|
||||
Date: Wed, 9 Feb 2022 19:45:27 +0100
|
||||
Subject: [PATCH] [policies] Set fallback to None sysroot
|
||||
|
||||
9596473 commit added a regression allowing to set sysroot to None
|
||||
when running sos report on a regular system (outside a container). In
|
||||
such a case, we need to fallback to '/' sysroot.
|
||||
|
||||
Resolves: #2846
|
||||
|
||||
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
||||
---
|
||||
sos/policies/distros/__init__.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
||||
index f3c1de11..9048f1c4 100644
|
||||
--- a/sos/policies/distros/__init__.py
|
||||
+++ b/sos/policies/distros/__init__.py
|
||||
@@ -78,7 +78,7 @@ class LinuxPolicy(Policy):
|
||||
if sysroot:
|
||||
self.sysroot = sysroot
|
||||
else:
|
||||
- self.sysroot = self._container_init()
|
||||
+ self.sysroot = self._container_init() or '/'
|
||||
|
||||
self.init_kernel_modules()
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
@ -1797,3 +1797,33 @@ index 229c7de4..3208a655 100644
|
||||
--
|
||||
2.31.1
|
||||
|
||||
From 7ebb2ce0bcd13c1b3aada648aceb20b5aff636d9 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Tue, 15 Feb 2022 14:18:02 -0500
|
||||
Subject: [PATCH] [host] Skip entire /etc/sos/cleaner directory
|
||||
|
||||
While `default_mapping` is typically the only file expected under
|
||||
`/etc/sos/cleaner/` it is possible for other mapping files (such as
|
||||
backups) to appear there.
|
||||
|
||||
Make the `add_forbidden_path()` spec here target the entire cleaner
|
||||
directory to avoid ever capturing these map files.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/report/plugins/host.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sos/report/plugins/host.py b/sos/report/plugins/host.py
|
||||
index 5e21da7b8e..95a3b9cd95 100644
|
||||
--- a/sos/report/plugins/host.py
|
||||
+++ b/sos/report/plugins/host.py
|
||||
@@ -20,7 +20,7 @@ class Host(Plugin, IndependentPlugin):
|
||||
|
||||
def setup(self):
|
||||
|
||||
- self.add_forbidden_path('/etc/sos/cleaner/default_mapping')
|
||||
+ self.add_forbidden_path('/etc/sos/cleaner')
|
||||
|
||||
self.add_cmd_output('hostname', root_symlink='hostname')
|
||||
self.add_cmd_output('uptime', root_symlink='uptime')
|
||||
|
@ -1608,159 +1608,6 @@ index 00000000..a4897f19
|
||||
--
|
||||
2.31.1
|
||||
|
||||
From e869bc84c714bfc2249bbcb84e14908049ee42c4 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 27 Sep 2021 12:07:08 -0400
|
||||
Subject: [PATCH 1/2] [Plugin,utilities] Add sysroot wrapper for os.path.join
|
||||
|
||||
Adds a wrapper for `os.path.join()` which accounts for non-/ sysroots,
|
||||
like we have done previously for other `os.path` methods. Further
|
||||
updates `Plugin()` to use this wrapper where appropriate.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/report/plugins/__init__.py | 43 +++++++++++++++++-----------------
|
||||
sos/utilities.py | 6 +++++
|
||||
2 files changed, 28 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index c635b8de..1f84bca4 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -13,7 +13,7 @@
|
||||
from sos.utilities import (sos_get_command_output, import_module, grep,
|
||||
fileobj, tail, is_executable, TIMEOUT_DEFAULT,
|
||||
path_exists, path_isdir, path_isfile, path_islink,
|
||||
- listdir)
|
||||
+ listdir, path_join)
|
||||
|
||||
import os
|
||||
import glob
|
||||
@@ -708,19 +708,6 @@ class Plugin():
|
||||
def _log_debug(self, msg):
|
||||
self.soslog.debug(self._format_msg(msg))
|
||||
|
||||
- def join_sysroot(self, path):
|
||||
- """Join a given path with the configured sysroot
|
||||
-
|
||||
- :param path: The filesystem path that needs to be joined
|
||||
- :type path: ``str``
|
||||
-
|
||||
- :returns: The joined filesystem path
|
||||
- :rtype: ``str``
|
||||
- """
|
||||
- if path[0] == os.sep:
|
||||
- path = path[1:]
|
||||
- return os.path.join(self.sysroot, path)
|
||||
-
|
||||
def strip_sysroot(self, path):
|
||||
"""Remove the configured sysroot from a filesystem path
|
||||
|
||||
@@ -1176,7 +1163,7 @@ class Plugin():
|
||||
|
||||
def _get_dest_for_srcpath(self, srcpath):
|
||||
if self.use_sysroot():
|
||||
- srcpath = self.join_sysroot(srcpath)
|
||||
+ srcpath = self.path_join(srcpath)
|
||||
for copied in self.copied_files:
|
||||
if srcpath == copied["srcpath"]:
|
||||
return copied["dstpath"]
|
||||
@@ -1284,7 +1271,7 @@ class Plugin():
|
||||
forbidden = [forbidden]
|
||||
|
||||
if self.use_sysroot():
|
||||
- forbidden = [self.join_sysroot(f) for f in forbidden]
|
||||
+ forbidden = [self.path_join(f) for f in forbidden]
|
||||
|
||||
for forbid in forbidden:
|
||||
self._log_info("adding forbidden path '%s'" % forbid)
|
||||
@@ -1438,7 +1425,7 @@ class Plugin():
|
||||
since = self.get_option('since')
|
||||
|
||||
logarchive_pattern = re.compile(r'.*((\.(zip|gz|bz2|xz))|[-.][\d]+)$')
|
||||
- configfile_pattern = re.compile(r"^%s/*" % self.join_sysroot("etc"))
|
||||
+ configfile_pattern = re.compile(r"^%s/*" % self.path_join("etc"))
|
||||
|
||||
if not self.test_predicate(pred=pred):
|
||||
self._log_info("skipped copy spec '%s' due to predicate (%s)" %
|
||||
@@ -1468,7 +1455,7 @@ class Plugin():
|
||||
return False
|
||||
|
||||
if self.use_sysroot():
|
||||
- copyspec = self.join_sysroot(copyspec)
|
||||
+ copyspec = self.path_join(copyspec)
|
||||
|
||||
files = self._expand_copy_spec(copyspec)
|
||||
|
||||
@@ -1683,7 +1670,7 @@ class Plugin():
|
||||
if not _dev_ok:
|
||||
continue
|
||||
if prepend_path:
|
||||
- device = os.path.join(prepend_path, device)
|
||||
+ device = self.path_join(prepend_path, device)
|
||||
_cmd = cmd % {'dev': device}
|
||||
self._add_cmd_output(cmd=_cmd, timeout=timeout,
|
||||
sizelimit=sizelimit, chroot=chroot,
|
||||
@@ -2592,7 +2579,7 @@ class Plugin():
|
||||
if self.path_isfile(path) or self.path_islink(path):
|
||||
found_paths.append(path)
|
||||
elif self.path_isdir(path) and self.listdir(path):
|
||||
- found_paths.extend(__expand(os.path.join(path, '*')))
|
||||
+ found_paths.extend(__expand(self.path_join(path, '*')))
|
||||
else:
|
||||
found_paths.append(path)
|
||||
except PermissionError:
|
||||
@@ -2608,7 +2595,7 @@ class Plugin():
|
||||
if (os.access(copyspec, os.R_OK) and self.path_isdir(copyspec) and
|
||||
self.listdir(copyspec)):
|
||||
# the directory exists and is non-empty, recurse through it
|
||||
- copyspec = os.path.join(copyspec, '*')
|
||||
+ copyspec = self.path_join(copyspec, '*')
|
||||
expanded = glob.glob(copyspec, recursive=True)
|
||||
recursed_files = []
|
||||
for _path in expanded:
|
||||
@@ -2877,6 +2864,20 @@ class Plugin():
|
||||
"""
|
||||
return listdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
|
||||
+ def path_join(self, path, *p):
|
||||
+ """Helper to call the sos.utilities wrapper that allows the
|
||||
+ corresponding `os` call to account for sysroot
|
||||
+
|
||||
+ :param path: The leading path passed to os.path.join()
|
||||
+ :type path: ``str``
|
||||
+
|
||||
+ :param p: Following path section(s) to be joined with ``path``,
|
||||
+ an empty parameter will result in a path that ends with
|
||||
+ a separator
|
||||
+ :type p: ``str``
|
||||
+ """
|
||||
+ return path_join(path, *p, sysroot=self.sysroot)
|
||||
+
|
||||
def postproc(self):
|
||||
"""Perform any postprocessing. To be replaced by a plugin if required.
|
||||
"""
|
||||
diff --git a/sos/utilities.py b/sos/utilities.py
|
||||
index c940e066..b7575153 100644
|
||||
--- a/sos/utilities.py
|
||||
+++ b/sos/utilities.py
|
||||
@@ -242,6 +242,12 @@ def listdir(path, sysroot):
|
||||
return _os_wrapper(path, sysroot, 'listdir', os)
|
||||
|
||||
|
||||
+def path_join(path, *p, sysroot=os.sep):
|
||||
+ if not path.startswith(sysroot):
|
||||
+ path = os.path.join(sysroot, path.lstrip(os.sep))
|
||||
+ return os.path.join(path, *p)
|
||||
+
|
||||
+
|
||||
class AsyncReader(threading.Thread):
|
||||
"""Used to limit command output to a given size without deadlocking
|
||||
sos.
|
||||
--
|
||||
2.31.1
|
||||
|
||||
|
||||
From 07d96d52ef69b9f8fe1ef32a1b88089d31c33fe8 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 27 Sep 2021 12:28:27 -0400
|
||||
@ -3679,697 +3526,6 @@ index e84b52da..1bfa741f 100644
|
||||
--
|
||||
2.31.1
|
||||
|
||||
From 3d064102f8ca6662fd9602512e1cb05cf8746dfd Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 27 Sep 2021 19:01:16 -0400
|
||||
Subject: [PATCH] [Systemd, Policy] Correct InitSystem chrooting when chroot is
|
||||
needed
|
||||
|
||||
This commit resolves a situation in which `sos` is being run in a
|
||||
container but the `SystemdInit` InitSystem would not properly load
|
||||
information from the host, thus causing the `Plugin.is_service*()`
|
||||
methods to erroneously fail or return `False`.
|
||||
|
||||
Fix this scenario by pulling the `_container_init()` and related logic
|
||||
to check for a containerized host sysroot out of the Red Hat specific
|
||||
policy and into the base `LinuxPolicy` class so that the init system can
|
||||
be initialized with the correct sysroot, which is now used to chroot the
|
||||
calls to the relevant `systemctl` commands.
|
||||
|
||||
For now, this does impose the use of looking for the `container` env var
|
||||
(automatically set by docker, podman, and crio regardless of
|
||||
distribution) and the use of the `HOST` env var to read where the host's
|
||||
`/` filesystem is mounted within the container. If desired in the
|
||||
future, this can be changed to allow policy-specific overrides. For now
|
||||
however, this extends host collection via an sos container for all
|
||||
distributions currently shipping sos.
|
||||
|
||||
Note that this issue only affected the `InitSystem` abstraction for
|
||||
loading information about local services, and did not affect init system
|
||||
related commands called by plugins as part of those collections.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/policies/distros/__init__.py | 28 ++++++++++++++++++++++++++-
|
||||
sos/policies/distros/redhat.py | 27 +-------------------------
|
||||
sos/policies/init_systems/__init__.py | 13 +++++++++++--
|
||||
sos/policies/init_systems/systemd.py | 7 ++++---
|
||||
4 files changed, 43 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
||||
index f5b9fd5b01..c33a356a75 100644
|
||||
--- a/sos/policies/distros/__init__.py
|
||||
+++ b/sos/policies/distros/__init__.py
|
||||
@@ -29,6 +29,10 @@
|
||||
except ImportError:
|
||||
REQUESTS_LOADED = False
|
||||
|
||||
+# Container environment variables for detecting if we're in a container
|
||||
+ENV_CONTAINER = 'container'
|
||||
+ENV_HOST_SYSROOT = 'HOST'
|
||||
+
|
||||
|
||||
class LinuxPolicy(Policy):
|
||||
"""This policy is meant to be an abc class that provides common
|
||||
@@ -69,10 +73,17 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
||||
probe_runtime=probe_runtime)
|
||||
self.init_kernel_modules()
|
||||
|
||||
+ # need to set _host_sysroot before PackageManager()
|
||||
+ if sysroot:
|
||||
+ self._container_init()
|
||||
+ self._host_sysroot = sysroot
|
||||
+ else:
|
||||
+ sysroot = self._container_init()
|
||||
+
|
||||
if init is not None:
|
||||
self.init_system = init
|
||||
elif os.path.isdir("/run/systemd/system/"):
|
||||
- self.init_system = SystemdInit()
|
||||
+ self.init_system = SystemdInit(chroot=sysroot)
|
||||
else:
|
||||
self.init_system = InitSystem()
|
||||
|
||||
@@ -130,6 +141,21 @@ def get_local_name(self):
|
||||
def sanitize_filename(self, name):
|
||||
return re.sub(r"[^-a-z,A-Z.0-9]", "", name)
|
||||
|
||||
+ def _container_init(self):
|
||||
+ """Check if sos is running in a container and perform container
|
||||
+ specific initialisation based on ENV_HOST_SYSROOT.
|
||||
+ """
|
||||
+ if ENV_CONTAINER in os.environ:
|
||||
+ if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
+ self._in_container = True
|
||||
+ if ENV_HOST_SYSROOT in os.environ:
|
||||
+ self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
+ use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
+ if use_sysroot:
|
||||
+ host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
+ self._tmp_dir = host_tmp_dir
|
||||
+ return self._host_sysroot if use_sysroot else None
|
||||
+
|
||||
def init_kernel_modules(self):
|
||||
"""Obtain a list of loaded kernel modules to reference later for plugin
|
||||
enablement and SoSPredicate checks
|
||||
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
||||
index b3a84336be..3476e21fb2 100644
|
||||
--- a/sos/policies/distros/redhat.py
|
||||
+++ b/sos/policies/distros/redhat.py
|
||||
@@ -17,7 +17,7 @@
|
||||
from sos.presets.redhat import (RHEL_PRESETS, ATOMIC_PRESETS, RHV, RHEL,
|
||||
CB, RHOSP, RHOCP, RH_CFME, RH_SATELLITE,
|
||||
ATOMIC)
|
||||
-from sos.policies.distros import LinuxPolicy
|
||||
+from sos.policies.distros import LinuxPolicy, ENV_HOST_SYSROOT
|
||||
from sos.policies.package_managers.rpm import RpmPackageManager
|
||||
from sos import _sos as _
|
||||
|
||||
@@ -56,12 +56,6 @@ def __init__(self, sysroot=None, init=None, probe_runtime=True,
|
||||
super(RedHatPolicy, self).__init__(sysroot=sysroot, init=init,
|
||||
probe_runtime=probe_runtime)
|
||||
self.usrmove = False
|
||||
- # need to set _host_sysroot before PackageManager()
|
||||
- if sysroot:
|
||||
- self._container_init()
|
||||
- self._host_sysroot = sysroot
|
||||
- else:
|
||||
- sysroot = self._container_init()
|
||||
|
||||
self.package_manager = RpmPackageManager(chroot=sysroot,
|
||||
remote_exec=remote_exec)
|
||||
@@ -140,21 +134,6 @@ def transform_path(path):
|
||||
else:
|
||||
return files
|
||||
|
||||
- def _container_init(self):
|
||||
- """Check if sos is running in a container and perform container
|
||||
- specific initialisation based on ENV_HOST_SYSROOT.
|
||||
- """
|
||||
- if ENV_CONTAINER in os.environ:
|
||||
- if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
- self._in_container = True
|
||||
- if ENV_HOST_SYSROOT in os.environ:
|
||||
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
- use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
- if use_sysroot:
|
||||
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
- self._tmp_dir = host_tmp_dir
|
||||
- return self._host_sysroot if use_sysroot else None
|
||||
-
|
||||
def runlevel_by_service(self, name):
|
||||
from subprocess import Popen, PIPE
|
||||
ret = []
|
||||
@@ -183,10 +162,6 @@ def get_tmp_dir(self, opt_tmp_dir):
|
||||
return opt_tmp_dir
|
||||
|
||||
|
||||
-# Container environment variables on Red Hat systems.
|
||||
-ENV_CONTAINER = 'container'
|
||||
-ENV_HOST_SYSROOT = 'HOST'
|
||||
-
|
||||
# Legal disclaimer text for Red Hat products
|
||||
disclaimer_text = """
|
||||
Any information provided to %(vendor)s will be treated in \
|
||||
diff --git a/sos/policies/init_systems/__init__.py b/sos/policies/init_systems/__init__.py
|
||||
index dd663e6522..beac44cee3 100644
|
||||
--- a/sos/policies/init_systems/__init__.py
|
||||
+++ b/sos/policies/init_systems/__init__.py
|
||||
@@ -29,9 +29,14 @@ class InitSystem():
|
||||
status of services
|
||||
:type query_cmd: ``str``
|
||||
|
||||
+ :param chroot: Location to chroot to for any command execution, i.e. the
|
||||
+ sysroot if we're running in a container
|
||||
+ :type chroot: ``str`` or ``None``
|
||||
+
|
||||
"""
|
||||
|
||||
- def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
||||
+ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None,
|
||||
+ chroot=None):
|
||||
"""Initialize a new InitSystem()"""
|
||||
|
||||
self.services = {}
|
||||
@@ -39,6 +44,7 @@ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None):
|
||||
self.init_cmd = init_cmd
|
||||
self.list_cmd = "%s %s" % (self.init_cmd, list_cmd) or None
|
||||
self.query_cmd = "%s %s" % (self.init_cmd, query_cmd) or None
|
||||
+ self.chroot = chroot
|
||||
|
||||
def is_enabled(self, name):
|
||||
"""Check if given service name is enabled
|
||||
@@ -108,7 +114,10 @@ def _query_service(self, name):
|
||||
"""Query an individual service"""
|
||||
if self.query_cmd:
|
||||
try:
|
||||
- return sos_get_command_output("%s %s" % (self.query_cmd, name))
|
||||
+ return sos_get_command_output(
|
||||
+ "%s %s" % (self.query_cmd, name),
|
||||
+ chroot=self.chroot
|
||||
+ )
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
diff --git a/sos/policies/init_systems/systemd.py b/sos/policies/init_systems/systemd.py
|
||||
index 1b138f97b3..76dc57e27f 100644
|
||||
--- a/sos/policies/init_systems/systemd.py
|
||||
+++ b/sos/policies/init_systems/systemd.py
|
||||
@@ -15,11 +15,12 @@
|
||||
class SystemdInit(InitSystem):
|
||||
"""InitSystem abstraction for SystemD systems"""
|
||||
|
||||
- def __init__(self):
|
||||
+ def __init__(self, chroot=None):
|
||||
super(SystemdInit, self).__init__(
|
||||
init_cmd='systemctl',
|
||||
list_cmd='list-unit-files --type=service',
|
||||
- query_cmd='status'
|
||||
+ query_cmd='status',
|
||||
+ chroot=chroot
|
||||
)
|
||||
self.load_all_services()
|
||||
|
||||
@@ -30,7 +31,7 @@ def parse_query(self, output):
|
||||
return 'unknown'
|
||||
|
||||
def load_all_services(self):
|
||||
- svcs = shell_out(self.list_cmd).splitlines()[1:]
|
||||
+ svcs = shell_out(self.list_cmd, chroot=self.chroot).splitlines()[1:]
|
||||
for line in svcs:
|
||||
try:
|
||||
name = line.split('.service')[0]
|
||||
--
|
||||
2.31.1
|
||||
|
||||
From 9596473d1779b9c48e9923c220aaf2b8d9b3bebf Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Thu, 18 Nov 2021 13:17:14 -0500
|
||||
Subject: [PATCH] [global] Align sysroot determination and usage across sos
|
||||
|
||||
The determination of sysroot - being automatic, user-specified, or
|
||||
controlled via environment variables in a container - has gotten muddied
|
||||
over time. This has resulted in different parts of the project;
|
||||
`Policy`, `Plugin`, `SoSComponent`, etc... to not always be in sync when
|
||||
sysroot is not `/`, thus causing varying and unexpected/unintended
|
||||
behavior.
|
||||
|
||||
Fix this by only determining sysroot within `Policy()` initialization,
|
||||
and then using that determination across all aspects of the project that
|
||||
use or reference sysroot.
|
||||
|
||||
This results in several changes:
|
||||
|
||||
- `PackageManager()` will now (again) correctly reference host package
|
||||
lists when sos is run in a container.
|
||||
|
||||
- `ContainerRuntime()` is now able to activate when sos is running in a
|
||||
container.
|
||||
|
||||
- Plugins will now properly use sysroot for _all_ plugin enablement
|
||||
triggers.
|
||||
|
||||
- Plugins, Policy, and SoSComponents now all reference the
|
||||
`self.sysroot` variable, rather than changing between `sysroot`.
|
||||
`_host_sysroot`, and `commons['sysroot']`. `_host_sysroot` has been
|
||||
removed from `Policy`.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/archive.py | 2 +-
|
||||
sos/component.py | 2 +-
|
||||
sos/policies/__init__.py | 11 +----------
|
||||
sos/policies/distros/__init__.py | 33 +++++++++++++++++++------------
|
||||
sos/policies/distros/debian.py | 2 +-
|
||||
sos/policies/distros/redhat.py | 3 +--
|
||||
sos/policies/runtimes/__init__.py | 15 +++++++++-----
|
||||
sos/policies/runtimes/docker.py | 4 ++--
|
||||
sos/report/__init__.py | 6 ++----
|
||||
sos/report/plugins/__init__.py | 22 +++++++++++----------
|
||||
sos/report/plugins/unpackaged.py | 7 ++++---
|
||||
sos/utilities.py | 13 ++++++++----
|
||||
12 files changed, 64 insertions(+), 56 deletions(-)
|
||||
|
||||
diff --git a/sos/archive.py b/sos/archive.py
|
||||
index b02b2475..e3c68b77 100644
|
||||
--- a/sos/archive.py
|
||||
+++ b/sos/archive.py
|
||||
@@ -153,7 +153,7 @@ class FileCacheArchive(Archive):
|
||||
return (os.path.join(self._archive_root, name))
|
||||
|
||||
def join_sysroot(self, path):
|
||||
- if path.startswith(self.sysroot):
|
||||
+ if not self.sysroot or path.startswith(self.sysroot):
|
||||
return path
|
||||
if path[0] == os.sep:
|
||||
path = path[1:]
|
||||
diff --git a/sos/component.py b/sos/component.py
|
||||
index 5ac6e47f..dba0aabf 100644
|
||||
--- a/sos/component.py
|
||||
+++ b/sos/component.py
|
||||
@@ -109,7 +109,7 @@ class SoSComponent():
|
||||
try:
|
||||
import sos.policies
|
||||
self.policy = sos.policies.load(sysroot=self.opts.sysroot)
|
||||
- self.sysroot = self.policy.host_sysroot()
|
||||
+ self.sysroot = self.policy.sysroot
|
||||
except KeyboardInterrupt:
|
||||
self._exit(0)
|
||||
self._is_root = self.policy.is_root()
|
||||
diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py
|
||||
index fb8db1d7..ef9188de 100644
|
||||
--- a/sos/policies/__init__.py
|
||||
+++ b/sos/policies/__init__.py
|
||||
@@ -110,7 +110,6 @@ any third party.
|
||||
presets = {"": PresetDefaults()}
|
||||
presets_path = PRESETS_PATH
|
||||
_in_container = False
|
||||
- _host_sysroot = '/'
|
||||
|
||||
def __init__(self, sysroot=None, probe_runtime=True):
|
||||
"""Subclasses that choose to override this initializer should call
|
||||
@@ -124,7 +123,7 @@ any third party.
|
||||
self.package_manager = PackageManager()
|
||||
self.valid_subclasses = [IndependentPlugin]
|
||||
self.set_exec_path()
|
||||
- self._host_sysroot = sysroot
|
||||
+ self.sysroot = sysroot
|
||||
self.register_presets(GENERIC_PRESETS)
|
||||
|
||||
def check(self, remote=''):
|
||||
@@ -177,14 +176,6 @@ any third party.
|
||||
"""
|
||||
return self._in_container
|
||||
|
||||
- def host_sysroot(self):
|
||||
- """Get the host's default sysroot
|
||||
-
|
||||
- :returns: Host sysroot
|
||||
- :rtype: ``str`` or ``None``
|
||||
- """
|
||||
- return self._host_sysroot
|
||||
-
|
||||
def dist_version(self):
|
||||
"""
|
||||
Return the OS version
|
||||
diff --git a/sos/policies/distros/__init__.py b/sos/policies/distros/__init__.py
|
||||
index 7bdc81b8..c69fc1e7 100644
|
||||
--- a/sos/policies/distros/__init__.py
|
||||
+++ b/sos/policies/distros/__init__.py
|
||||
@@ -71,19 +71,18 @@ class LinuxPolicy(Policy):
|
||||
def __init__(self, sysroot=None, init=None, probe_runtime=True):
|
||||
super(LinuxPolicy, self).__init__(sysroot=sysroot,
|
||||
probe_runtime=probe_runtime)
|
||||
- self.init_kernel_modules()
|
||||
|
||||
- # need to set _host_sysroot before PackageManager()
|
||||
if sysroot:
|
||||
- self._container_init()
|
||||
- self._host_sysroot = sysroot
|
||||
+ self.sysroot = sysroot
|
||||
else:
|
||||
- sysroot = self._container_init()
|
||||
+ self.sysroot = self._container_init()
|
||||
+
|
||||
+ self.init_kernel_modules()
|
||||
|
||||
if init is not None:
|
||||
self.init_system = init
|
||||
elif os.path.isdir("/run/systemd/system/"):
|
||||
- self.init_system = SystemdInit(chroot=sysroot)
|
||||
+ self.init_system = SystemdInit(chroot=self.sysroot)
|
||||
else:
|
||||
self.init_system = InitSystem()
|
||||
|
||||
@@ -149,27 +148,30 @@ class LinuxPolicy(Policy):
|
||||
if os.environ[ENV_CONTAINER] in ['docker', 'oci', 'podman']:
|
||||
self._in_container = True
|
||||
if ENV_HOST_SYSROOT in os.environ:
|
||||
- self._host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
- use_sysroot = self._in_container and self._host_sysroot is not None
|
||||
+ _host_sysroot = os.environ[ENV_HOST_SYSROOT]
|
||||
+ use_sysroot = self._in_container and _host_sysroot is not None
|
||||
if use_sysroot:
|
||||
- host_tmp_dir = os.path.abspath(self._host_sysroot + self._tmp_dir)
|
||||
+ host_tmp_dir = os.path.abspath(_host_sysroot + self._tmp_dir)
|
||||
self._tmp_dir = host_tmp_dir
|
||||
- return self._host_sysroot if use_sysroot else None
|
||||
+ return _host_sysroot if use_sysroot else None
|
||||
|
||||
def init_kernel_modules(self):
|
||||
"""Obtain a list of loaded kernel modules to reference later for plugin
|
||||
enablement and SoSPredicate checks
|
||||
"""
|
||||
self.kernel_mods = []
|
||||
+ release = os.uname().release
|
||||
|
||||
# first load modules from lsmod
|
||||
- lines = shell_out("lsmod", timeout=0).splitlines()
|
||||
+ lines = shell_out("lsmod", timeout=0, chroot=self.sysroot).splitlines()
|
||||
self.kernel_mods.extend([
|
||||
line.split()[0].strip() for line in lines[1:]
|
||||
])
|
||||
|
||||
# next, include kernel builtins
|
||||
- builtins = "/usr/lib/modules/%s/modules.builtin" % os.uname().release
|
||||
+ builtins = self.join_sysroot(
|
||||
+ "/usr/lib/modules/%s/modules.builtin" % release
|
||||
+ )
|
||||
try:
|
||||
with open(builtins, "r") as mfile:
|
||||
for line in mfile:
|
||||
@@ -186,7 +188,7 @@ class LinuxPolicy(Policy):
|
||||
'dm_mod': 'CONFIG_BLK_DEV_DM'
|
||||
}
|
||||
|
||||
- booted_config = "/boot/config-%s" % os.uname().release
|
||||
+ booted_config = self.join_sysroot("/boot/config-%s" % release)
|
||||
kconfigs = []
|
||||
try:
|
||||
with open(booted_config, "r") as kfile:
|
||||
@@ -200,6 +202,11 @@ class LinuxPolicy(Policy):
|
||||
if config_strings[builtin] in kconfigs:
|
||||
self.kernel_mods.append(builtin)
|
||||
|
||||
+ def join_sysroot(self, path):
|
||||
+ if self.sysroot and self.sysroot != '/':
|
||||
+ path = os.path.join(self.sysroot, path.lstrip('/'))
|
||||
+ return path
|
||||
+
|
||||
def pre_work(self):
|
||||
# this method will be called before the gathering begins
|
||||
|
||||
diff --git a/sos/policies/distros/debian.py b/sos/policies/distros/debian.py
|
||||
index 95b389a6..639fd5eb 100644
|
||||
--- a/sos/policies/distros/debian.py
|
||||
+++ b/sos/policies/distros/debian.py
|
||||
@@ -27,7 +27,7 @@ class DebianPolicy(LinuxPolicy):
|
||||
remote_exec=None):
|
||||
super(DebianPolicy, self).__init__(sysroot=sysroot, init=init,
|
||||
probe_runtime=probe_runtime)
|
||||
- self.package_manager = DpkgPackageManager(chroot=sysroot,
|
||||
+ self.package_manager = DpkgPackageManager(chroot=self.sysroot,
|
||||
remote_exec=remote_exec)
|
||||
self.valid_subclasses += [DebianPlugin]
|
||||
|
||||
diff --git a/sos/policies/distros/redhat.py b/sos/policies/distros/redhat.py
|
||||
index eb442407..4b14abaf 100644
|
||||
--- a/sos/policies/distros/redhat.py
|
||||
+++ b/sos/policies/distros/redhat.py
|
||||
@@ -42,7 +42,6 @@ class RedHatPolicy(LinuxPolicy):
|
||||
_redhat_release = '/etc/redhat-release'
|
||||
_tmp_dir = "/var/tmp"
|
||||
_in_container = False
|
||||
- _host_sysroot = '/'
|
||||
default_scl_prefix = '/opt/rh'
|
||||
name_pattern = 'friendly'
|
||||
upload_url = None
|
||||
@@ -57,7 +56,7 @@ class RedHatPolicy(LinuxPolicy):
|
||||
probe_runtime=probe_runtime)
|
||||
self.usrmove = False
|
||||
|
||||
- self.package_manager = RpmPackageManager(chroot=sysroot,
|
||||
+ self.package_manager = RpmPackageManager(chroot=self.sysroot,
|
||||
remote_exec=remote_exec)
|
||||
|
||||
self.valid_subclasses += [RedHatPlugin]
|
||||
diff --git a/sos/policies/runtimes/__init__.py b/sos/policies/runtimes/__init__.py
|
||||
index f28d6a1d..2e60ad23 100644
|
||||
--- a/sos/policies/runtimes/__init__.py
|
||||
+++ b/sos/policies/runtimes/__init__.py
|
||||
@@ -64,7 +64,7 @@ class ContainerRuntime():
|
||||
:returns: ``True`` if the runtime is active, else ``False``
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- if is_executable(self.binary):
|
||||
+ if is_executable(self.binary, self.policy.sysroot):
|
||||
self.active = True
|
||||
return True
|
||||
return False
|
||||
@@ -78,7 +78,7 @@ class ContainerRuntime():
|
||||
containers = []
|
||||
_cmd = "%s ps %s" % (self.binary, '-a' if get_all else '')
|
||||
if self.active:
|
||||
- out = sos_get_command_output(_cmd)
|
||||
+ out = sos_get_command_output(_cmd, chroot=self.policy.sysroot)
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines()[1:]:
|
||||
ent = ent.split()
|
||||
@@ -112,8 +112,10 @@ class ContainerRuntime():
|
||||
images = []
|
||||
fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}'
|
||||
if self.active:
|
||||
- out = sos_get_command_output("%s images --format '%s'"
|
||||
- % (self.binary, fmt))
|
||||
+ out = sos_get_command_output(
|
||||
+ "%s images --format '%s'" % (self.binary, fmt),
|
||||
+ chroot=self.policy.sysroot
|
||||
+ )
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines():
|
||||
ent = ent.split()
|
||||
@@ -129,7 +131,10 @@ class ContainerRuntime():
|
||||
"""
|
||||
vols = []
|
||||
if self.active:
|
||||
- out = sos_get_command_output("%s volume ls" % self.binary)
|
||||
+ out = sos_get_command_output(
|
||||
+ "%s volume ls" % self.binary,
|
||||
+ chroot=self.policy.sysroot
|
||||
+ )
|
||||
if out['status'] == 0:
|
||||
for ent in out['output'].splitlines()[1:]:
|
||||
ent = ent.split()
|
||||
diff --git a/sos/policies/runtimes/docker.py b/sos/policies/runtimes/docker.py
|
||||
index 759dfaf6..e81f580e 100644
|
||||
--- a/sos/policies/runtimes/docker.py
|
||||
+++ b/sos/policies/runtimes/docker.py
|
||||
@@ -18,9 +18,9 @@ class DockerContainerRuntime(ContainerRuntime):
|
||||
name = 'docker'
|
||||
binary = 'docker'
|
||||
|
||||
- def check_is_active(self):
|
||||
+ def check_is_active(self, sysroot=None):
|
||||
# the daemon must be running
|
||||
- if (is_executable('docker') and
|
||||
+ if (is_executable('docker', sysroot) and
|
||||
(self.policy.init_system.is_running('docker') or
|
||||
self.policy.init_system.is_running('snap.docker.dockerd'))):
|
||||
self.active = True
|
||||
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
||||
index a4c92acc..a6c72778 100644
|
||||
--- a/sos/report/__init__.py
|
||||
+++ b/sos/report/__init__.py
|
||||
@@ -173,14 +173,12 @@ class SoSReport(SoSComponent):
|
||||
self._set_directories()
|
||||
|
||||
msg = "default"
|
||||
- host_sysroot = self.policy.host_sysroot()
|
||||
+ self.sysroot = self.policy.sysroot
|
||||
# set alternate system root directory
|
||||
if self.opts.sysroot:
|
||||
msg = "cmdline"
|
||||
- self.sysroot = self.opts.sysroot
|
||||
- elif self.policy.in_container() and host_sysroot != os.sep:
|
||||
+ elif self.policy.in_container() and self.sysroot != os.sep:
|
||||
msg = "policy"
|
||||
- self.sysroot = host_sysroot
|
||||
self.soslog.debug("set sysroot to '%s' (%s)" % (self.sysroot, msg))
|
||||
|
||||
if self.opts.chroot not in chroot_modes:
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index 46028bb1..e180ae17 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -724,7 +724,7 @@ class Plugin():
|
||||
"""
|
||||
if not self.use_sysroot():
|
||||
return path
|
||||
- if path.startswith(self.sysroot):
|
||||
+ if self.sysroot and path.startswith(self.sysroot):
|
||||
return path[len(self.sysroot):]
|
||||
return path
|
||||
|
||||
@@ -743,8 +743,10 @@ class Plugin():
|
||||
``False``
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- paths = [self.sysroot, self.archive.get_tmp_dir()]
|
||||
- return os.path.commonprefix(paths) == self.sysroot
|
||||
+ # if sysroot is still None, that implies '/'
|
||||
+ _sysroot = self.sysroot or '/'
|
||||
+ paths = [_sysroot, self.archive.get_tmp_dir()]
|
||||
+ return os.path.commonprefix(paths) == _sysroot
|
||||
|
||||
def is_installed(self, package_name):
|
||||
"""Is the package $package_name installed?
|
||||
@@ -2621,7 +2623,7 @@ class Plugin():
|
||||
return list(set(expanded))
|
||||
|
||||
def _collect_copy_specs(self):
|
||||
- for path in self.copy_paths:
|
||||
+ for path in sorted(self.copy_paths, reverse=True):
|
||||
self._log_info("collecting path '%s'" % path)
|
||||
self._do_copy_path(path)
|
||||
self.generate_copyspec_tags()
|
||||
@@ -2749,7 +2751,7 @@ class Plugin():
|
||||
|
||||
return ((any(self.path_exists(fname) for fname in files) or
|
||||
any(self.is_installed(pkg) for pkg in packages) or
|
||||
- any(is_executable(cmd) for cmd in commands) or
|
||||
+ any(is_executable(cmd, self.sysroot) for cmd in commands) or
|
||||
any(self.is_module_loaded(mod) for mod in self.kernel_mods) or
|
||||
any(self.is_service(svc) for svc in services) or
|
||||
any(self.container_exists(cntr) for cntr in containers)) and
|
||||
@@ -2817,7 +2819,7 @@ class Plugin():
|
||||
:returns: True if the path exists in sysroot, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_exists(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_exists(path, self.sysroot)
|
||||
|
||||
def path_isdir(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2830,7 +2832,7 @@ class Plugin():
|
||||
:returns: True if the path is a dir, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_isdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_isdir(path, self.sysroot)
|
||||
|
||||
def path_isfile(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2843,7 +2845,7 @@ class Plugin():
|
||||
:returns: True if the path is a file, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_isfile(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_isfile(path, self.sysroot)
|
||||
|
||||
def path_islink(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2856,7 +2858,7 @@ class Plugin():
|
||||
:returns: True if the path is a link, else False
|
||||
:rtype: ``bool``
|
||||
"""
|
||||
- return path_islink(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return path_islink(path, self.sysroot)
|
||||
|
||||
def listdir(self, path):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
@@ -2869,7 +2871,7 @@ class Plugin():
|
||||
:returns: Contents of path, if it is a directory
|
||||
:rtype: ``list``
|
||||
"""
|
||||
- return listdir(path, self.commons['cmdlineopts'].sysroot)
|
||||
+ return listdir(path, self.sysroot)
|
||||
|
||||
def path_join(self, path, *p):
|
||||
"""Helper to call the sos.utilities wrapper that allows the
|
||||
diff --git a/sos/report/plugins/unpackaged.py b/sos/report/plugins/unpackaged.py
|
||||
index 772b1d1f..24203c4b 100644
|
||||
--- a/sos/report/plugins/unpackaged.py
|
||||
+++ b/sos/report/plugins/unpackaged.py
|
||||
@@ -58,10 +58,11 @@ class Unpackaged(Plugin, RedHatPlugin):
|
||||
"""
|
||||
expanded = []
|
||||
for f in files:
|
||||
- if self.path_islink(f):
|
||||
- expanded.append("{} -> {}".format(f, os.readlink(f)))
|
||||
+ fp = self.path_join(f)
|
||||
+ if self.path_islink(fp):
|
||||
+ expanded.append("{} -> {}".format(fp, os.readlink(fp)))
|
||||
else:
|
||||
- expanded.append(f)
|
||||
+ expanded.append(fp)
|
||||
return expanded
|
||||
|
||||
# Check command predicate to avoid costly processing
|
||||
diff --git a/sos/utilities.py b/sos/utilities.py
|
||||
index b7575153..d6630933 100644
|
||||
--- a/sos/utilities.py
|
||||
+++ b/sos/utilities.py
|
||||
@@ -96,11 +96,15 @@ def grep(pattern, *files_or_paths):
|
||||
return matches
|
||||
|
||||
|
||||
-def is_executable(command):
|
||||
+def is_executable(command, sysroot=None):
|
||||
"""Returns if a command matches an executable on the PATH"""
|
||||
|
||||
paths = os.environ.get("PATH", "").split(os.path.pathsep)
|
||||
candidates = [command] + [os.path.join(p, command) for p in paths]
|
||||
+ if sysroot:
|
||||
+ candidates += [
|
||||
+ os.path.join(sysroot, c.lstrip('/')) for c in candidates
|
||||
+ ]
|
||||
return any(os.access(path, os.X_OK) for path in candidates)
|
||||
|
||||
|
||||
@@ -216,8 +220,9 @@ def get_human_readable(size, precision=2):
|
||||
|
||||
|
||||
def _os_wrapper(path, sysroot, method, module=os.path):
|
||||
- if sysroot not in [None, '/']:
|
||||
- path = os.path.join(sysroot, path.lstrip('/'))
|
||||
+ if sysroot and sysroot != os.sep:
|
||||
+ if not path.startswith(sysroot):
|
||||
+ path = os.path.join(sysroot, path.lstrip('/'))
|
||||
_meth = getattr(module, method)
|
||||
return _meth(path)
|
||||
|
||||
@@ -243,7 +248,7 @@ def listdir(path, sysroot):
|
||||
|
||||
|
||||
def path_join(path, *p, sysroot=os.sep):
|
||||
- if not path.startswith(sysroot):
|
||||
+ if sysroot and not path.startswith(sysroot):
|
||||
path = os.path.join(sysroot, path.lstrip(os.sep))
|
||||
return os.path.join(path, *p)
|
||||
|
||||
--
|
||||
2.31.1
|
||||
|
||||
From 8bf602108f75db10e449eff5e2266c6466504086 Mon Sep 17 00:00:00 2001
|
||||
From: Nadia Pinaeva <npinaeva@redhat.com>
|
||||
Date: Thu, 2 Dec 2021 16:30:44 +0100
|
||||
@ -5868,20 +5024,122 @@ index cb20772fd..b59eade9a 100644
|
||||
|
||||
def test_ip_parser_valid_ipv4_line(self):
|
||||
line = 'foobar foo 10.0.0.1/24 barfoo bar'
|
||||
From: Pavel Moravec <pmoravec@redhat.com>
|
||||
Subject: downstream-only patch to allow container_runtime change on 4.2
|
||||
sos cluster/collector already, as any 4.2 released version will support
|
||||
it.
|
||||
diff -rup a/sos/collector/sosnode.py b/sos/collector/sosnode.py
|
||||
From 2ae16e0245e1b01b8547e507abb69c11871a8467 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 21 Feb 2022 14:37:09 -0500
|
||||
Subject: [PATCH] [sosnode] Handle downstream versioning for runtime option
|
||||
check
|
||||
|
||||
First, adds parsing and formatting for an sos installation's release
|
||||
version according to the loaded package manager for that node.
|
||||
|
||||
Adds a fallback version check for 4.2-13 for RHEL downstreams that
|
||||
backport the `container-runtime` option into sos-4.2.
|
||||
|
||||
Carry this in upstream to account for use cases where a workstation used
|
||||
to run `collect` from may be from a different stream than those used by
|
||||
cluster nodes.
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/collector/sosnode.py | 60 ++++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 51 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/sos/collector/sosnode.py b/sos/collector/sosnode.py
|
||||
index 7bbe0cd1..d9b998b0 100644
|
||||
--- a/sos/collector/sosnode.py
|
||||
+++ b/sos/collector/sosnode.py
|
||||
@@ -586,8 +586,6 @@ class SosNode():
|
||||
if self.opts.cmd_timeout:
|
||||
@@ -275,21 +275,34 @@ class SosNode():
|
||||
def _load_sos_info(self):
|
||||
"""Queries the node for information about the installed version of sos
|
||||
"""
|
||||
+ ver = None
|
||||
+ rel = None
|
||||
if self.host.container_version_command is None:
|
||||
pkg = self.host.package_manager.pkg_version(self.host.sos_pkg_name)
|
||||
if pkg is not None:
|
||||
ver = '.'.join(pkg['version'])
|
||||
- self.sos_info['version'] = ver
|
||||
+ if pkg['release']:
|
||||
+ rel = pkg['release']
|
||||
+
|
||||
else:
|
||||
# use the containerized policy's command
|
||||
pkgs = self.run_command(self.host.container_version_command,
|
||||
use_container=True, need_root=True)
|
||||
if pkgs['status'] == 0:
|
||||
- ver = pkgs['output'].strip().split('-')[1]
|
||||
- if ver:
|
||||
- self.sos_info['version'] = ver
|
||||
- else:
|
||||
- self.sos_info['version'] = None
|
||||
+ _, ver, rel = pkgs['output'].strip().split('-')
|
||||
+
|
||||
+ if ver:
|
||||
+ if len(ver.split('.')) == 2:
|
||||
+ # safeguard against maintenance releases throwing off the
|
||||
+ # comparison by LooseVersion
|
||||
+ ver += '.0'
|
||||
+ try:
|
||||
+ ver += '-%s' % rel.split('.')[0]
|
||||
+ except Exception as err:
|
||||
+ self.log_debug("Unable to fully parse sos release: %s" % err)
|
||||
+
|
||||
+ self.sos_info['version'] = ver
|
||||
+
|
||||
if self.sos_info['version']:
|
||||
self.log_info('sos version is %s' % self.sos_info['version'])
|
||||
else:
|
||||
@@ -381,9 +394,37 @@ class SosNode():
|
||||
"""Checks to see if the sos installation on the node is AT LEAST the
|
||||
given ver. This means that if the installed version is greater than
|
||||
ver, this will still return True
|
||||
+
|
||||
+ :param ver: Version number we are trying to verify is installed
|
||||
+ :type ver: ``str``
|
||||
+
|
||||
+ :returns: True if installed version is at least ``ver``, else False
|
||||
+ :rtype: ``bool``
|
||||
"""
|
||||
- return self.sos_info['version'] is not None and \
|
||||
- LooseVersion(self.sos_info['version']) >= ver
|
||||
+ def _format_version(ver):
|
||||
+ # format the version we're checking to a standard form of X.Y.Z-R
|
||||
+ try:
|
||||
+ _fver = ver.split('-')[0]
|
||||
+ _rel = ''
|
||||
+ if '-' in ver:
|
||||
+ _rel = '-' + ver.split('-')[-1].split('.')[0]
|
||||
+ if len(_fver.split('.')) == 2:
|
||||
+ _fver += '.0'
|
||||
+
|
||||
+ return _fver + _rel
|
||||
+ except Exception as err:
|
||||
+ self.log_debug("Unable to format '%s': %s" % (ver, err))
|
||||
+ return ver
|
||||
+
|
||||
+ _ver = _format_version(ver)
|
||||
+
|
||||
+ try:
|
||||
+ _node_ver = LooseVersion(self.sos_info['version'])
|
||||
+ _test_ver = LooseVersion(_ver)
|
||||
+ return _node_ver >= _test_ver
|
||||
+ except Exception as err:
|
||||
+ self.log_error("Error checking sos version: %s" % err)
|
||||
+ return False
|
||||
|
||||
def is_installed(self, pkg):
|
||||
"""Checks if a given package is installed on the node"""
|
||||
@@ -587,7 +628,8 @@ class SosNode():
|
||||
sos_opts.append('--cmd-timeout=%s'
|
||||
% quote(str(self.opts.cmd_timeout)))
|
||||
-
|
||||
|
||||
- if self.check_sos_version('4.3'):
|
||||
+ # handle downstream versions that backported this option
|
||||
+ if self.check_sos_version('4.3') or self.check_sos_version('4.2-13'):
|
||||
if self.opts.container_runtime != 'auto':
|
||||
sos_opts.append(
|
||||
"--container-runtime=%s" % self.opts.container_runtime
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
@ -43,3 +43,210 @@ index 78604a15a..25c38cccc 100644
|
||||
|
||||
|
||||
class DebianOVNHost(OVNHost, DebianPlugin, UbuntuPlugin):
|
||||
From 21fc376d97a5f74743e2b7cf7069349e874b979e Mon Sep 17 00:00:00 2001
|
||||
From: Hemanth Nakkina <hemanth.nakkina@canonical.com>
|
||||
Date: Fri, 4 Feb 2022 07:57:59 +0530
|
||||
Subject: [PATCH] [ovn-central] collect NB/SB ovsdb-server cluster status
|
||||
|
||||
Add commands to collect cluster status of Northbound and
|
||||
Southbound ovsdb servers.
|
||||
|
||||
Resolves: #2840
|
||||
|
||||
Signed-off-by: Hemanth Nakkina hemanth.nakkina@canonical.com
|
||||
---
|
||||
sos/report/plugins/ovn_central.py | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sos/report/plugins/ovn_central.py b/sos/report/plugins/ovn_central.py
|
||||
index 0f947d4c5..2f0438df3 100644
|
||||
--- a/sos/report/plugins/ovn_central.py
|
||||
+++ b/sos/report/plugins/ovn_central.py
|
||||
@@ -84,6 +84,14 @@ def setup(self):
|
||||
else:
|
||||
self.add_copy_spec("/var/log/ovn/*.log")
|
||||
|
||||
+ # ovsdb nb/sb cluster status commands
|
||||
+ ovsdb_cmds = [
|
||||
+ 'ovs-appctl -t {} cluster/status OVN_Northbound'.format(
|
||||
+ self.ovn_nbdb_sock_path),
|
||||
+ 'ovs-appctl -t {} cluster/status OVN_Southbound'.format(
|
||||
+ self.ovn_sbdb_sock_path),
|
||||
+ ]
|
||||
+
|
||||
# Some user-friendly versions of DB output
|
||||
nbctl_cmds = [
|
||||
'ovn-nbctl show',
|
||||
@@ -109,7 +117,8 @@ def setup(self):
|
||||
|
||||
self.add_database_output(nb_tables, nbctl_cmds, 'ovn-nbctl')
|
||||
|
||||
- cmds = nbctl_cmds
|
||||
+ cmds = ovsdb_cmds
|
||||
+ cmds += nbctl_cmds
|
||||
|
||||
# Can only run sbdb commands if we are the leader
|
||||
co = {'cmd': "ovs-appctl -t {} cluster/status OVN_Southbound".
|
||||
@@ -148,10 +157,12 @@ def setup(self):
|
||||
class RedHatOVNCentral(OVNCentral, RedHatPlugin):
|
||||
|
||||
packages = ('openvswitch-ovn-central', 'ovn.*-central', )
|
||||
+ ovn_nbdb_sock_path = '/var/run/openvswitch/ovnnb_db.ctl'
|
||||
ovn_sbdb_sock_path = '/var/run/openvswitch/ovnsb_db.ctl'
|
||||
|
||||
|
||||
class DebianOVNCentral(OVNCentral, DebianPlugin, UbuntuPlugin):
|
||||
|
||||
packages = ('ovn-central', )
|
||||
+ ovn_nbdb_sock_path = '/var/run/ovn/ovnnb_db.ctl'
|
||||
ovn_sbdb_sock_path = '/var/run/ovn/ovnsb_db.ctl'
|
||||
From d0f9d507b0ec63c9e8f3e5d7b6507d9d0f97c038 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Tue, 15 Feb 2022 16:24:47 -0500
|
||||
Subject: [PATCH] [runtimes] Allow container IDs to be used with
|
||||
`container_exists()`
|
||||
|
||||
As container runtimes can interchange container names and container IDs,
|
||||
sos should also allow the use of container IDs when checking for the
|
||||
presence of a given container.
|
||||
|
||||
In particular, this change unblocks the use of `Plugin.exec_cmd()` when
|
||||
used in conjunction with `Plugin.get_container_by_name()` to pick a
|
||||
container based on a provided regex that the container name may match.
|
||||
|
||||
Related: #2856
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/policies/runtimes/__init__.py | 17 +++++++++++++++++
|
||||
sos/report/plugins/__init__.py | 6 +++---
|
||||
2 files changed, 20 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/sos/policies/runtimes/__init__.py b/sos/policies/runtimes/__init__.py
|
||||
index 5ac673544..d28373496 100644
|
||||
--- a/sos/policies/runtimes/__init__.py
|
||||
+++ b/sos/policies/runtimes/__init__.py
|
||||
@@ -147,6 +147,23 @@ def get_volumes(self):
|
||||
vols.append(ent[-1])
|
||||
return vols
|
||||
|
||||
+ def container_exists(self, container):
|
||||
+ """Check if a given container ID or name exists on the system from the
|
||||
+ perspective of the container runtime.
|
||||
+
|
||||
+ Note that this will only check _running_ containers
|
||||
+
|
||||
+ :param container: The name or ID of the container
|
||||
+ :type container: ``str``
|
||||
+
|
||||
+ :returns: True if the container exists, else False
|
||||
+ :rtype: ``bool``
|
||||
+ """
|
||||
+ for _contup in self.containers:
|
||||
+ if container in _contup:
|
||||
+ return True
|
||||
+ return False
|
||||
+
|
||||
def fmt_container_cmd(self, container, cmd, quotecmd):
|
||||
"""Format a command to run inside a container using the runtime
|
||||
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index 2988be089..cc5cb65bc 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -2593,7 +2593,7 @@ def container_exists(self, name):
|
||||
"""If a container runtime is present, check to see if a container with
|
||||
a given name is currently running
|
||||
|
||||
- :param name: The name of the container to check presence of
|
||||
+ :param name: The name or ID of the container to check presence of
|
||||
:type name: ``str``
|
||||
|
||||
:returns: ``True`` if `name` exists, else ``False``
|
||||
@@ -2601,8 +2601,8 @@ def container_exists(self, name):
|
||||
"""
|
||||
_runtime = self._get_container_runtime()
|
||||
if _runtime is not None:
|
||||
- con = _runtime.get_container_by_name(name)
|
||||
- return con is not None
|
||||
+ return (_runtime.container_exists(name) or
|
||||
+ _runtime.get_container_by_name(name) is not None)
|
||||
return False
|
||||
|
||||
def get_all_containers_by_regex(self, regex, get_all=False):
|
||||
|
||||
From de9b020a72d1ceda39587db4c6d5acf72cd90da2 Mon Sep 17 00:00:00 2001
|
||||
From: Fernando Royo <froyo@redhat.com>
|
||||
Date: Tue, 15 Feb 2022 10:00:38 +0100
|
||||
Subject: [PATCH] [ovn_central] Rename container responsable of Red Hat
|
||||
ovn_central plugin
|
||||
|
||||
ovn_central plugin is running by container with
|
||||
name 'ovn-dbs-bundle*', a typo has been identified and
|
||||
this cause plugin ovn_central not enabled by default as it
|
||||
does not recognize any container responsible of this.
|
||||
|
||||
This patch fix this container name match, searching schema db
|
||||
keeping backward compatibility with openvswitch.
|
||||
---
|
||||
sos/report/plugins/ovn_central.py | 23 ++++++++++++-----------
|
||||
1 file changed, 12 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/sos/report/plugins/ovn_central.py b/sos/report/plugins/ovn_central.py
|
||||
index 2f0438df..2f34bff0 100644
|
||||
--- a/sos/report/plugins/ovn_central.py
|
||||
+++ b/sos/report/plugins/ovn_central.py
|
||||
@@ -24,7 +24,7 @@ class OVNCentral(Plugin):
|
||||
short_desc = 'OVN Northd'
|
||||
plugin_name = "ovn_central"
|
||||
profiles = ('network', 'virt')
|
||||
- containers = ('ovs-db-bundle.*',)
|
||||
+ containers = ('ovn-dbs-bundle.*',)
|
||||
|
||||
def get_tables_from_schema(self, filename, skip=[]):
|
||||
if self._container_name:
|
||||
@@ -66,7 +66,7 @@ class OVNCentral(Plugin):
|
||||
cmds.append('%s list %s' % (ovn_cmd, table))
|
||||
|
||||
def setup(self):
|
||||
- self._container_name = self.get_container_by_name('ovs-dbs-bundle.*')
|
||||
+ self._container_name = self.get_container_by_name(self.containers[0])
|
||||
|
||||
ovs_rundir = os.environ.get('OVS_RUNDIR')
|
||||
for pidfile in ['ovnnb_db.pid', 'ovnsb_db.pid', 'ovn-northd.pid']:
|
||||
@@ -110,12 +110,11 @@ class OVNCentral(Plugin):
|
||||
'ovn-sbctl get-connection',
|
||||
]
|
||||
|
||||
- schema_dir = '/usr/share/openvswitch'
|
||||
-
|
||||
- nb_tables = self.get_tables_from_schema(self.path_join(
|
||||
- schema_dir, 'ovn-nb.ovsschema'))
|
||||
-
|
||||
- self.add_database_output(nb_tables, nbctl_cmds, 'ovn-nbctl')
|
||||
+ # backward compatibility
|
||||
+ for path in ['/usr/share/openvswitch', '/usr/share/ovn']:
|
||||
+ nb_tables = self.get_tables_from_schema(self.path_join(
|
||||
+ path, 'ovn-nb.ovsschema'))
|
||||
+ self.add_database_output(nb_tables, nbctl_cmds, 'ovn-nbctl')
|
||||
|
||||
cmds = ovsdb_cmds
|
||||
cmds += nbctl_cmds
|
||||
@@ -125,9 +124,11 @@ class OVNCentral(Plugin):
|
||||
format(self.ovn_sbdb_sock_path),
|
||||
"output": "Leader: self"}
|
||||
if self.test_predicate(self, pred=SoSPredicate(self, cmd_outputs=co)):
|
||||
- sb_tables = self.get_tables_from_schema(self.path_join(
|
||||
- schema_dir, 'ovn-sb.ovsschema'), ['Logical_Flow'])
|
||||
- self.add_database_output(sb_tables, sbctl_cmds, 'ovn-sbctl')
|
||||
+ # backward compatibility
|
||||
+ for path in ['/usr/share/openvswitch', '/usr/share/ovn']:
|
||||
+ sb_tables = self.get_tables_from_schema(self.path_join(
|
||||
+ path, 'ovn-sb.ovsschema'), ['Logical_Flow'])
|
||||
+ self.add_database_output(sb_tables, sbctl_cmds, 'ovn-sbctl')
|
||||
cmds += sbctl_cmds
|
||||
|
||||
# If OVN is containerized, we need to run the above commands inside
|
||||
--
|
||||
2.34.1
|
||||
|
||||
|
94
SOURCES/sos-bz2054882-plugopt-logging-effective-opts.patch
Normal file
94
SOURCES/sos-bz2054882-plugopt-logging-effective-opts.patch
Normal file
@ -0,0 +1,94 @@
|
||||
From 5824cd5d3bddf39e0382d568419e2453abc93d8a Mon Sep 17 00:00:00 2001
|
||||
From: Jake Hunsaker <jhunsake@redhat.com>
|
||||
Date: Mon, 30 Aug 2021 15:09:07 -0400
|
||||
Subject: [PATCH] [options] Fix logging on plugopts in effective sos command
|
||||
|
||||
First, provide a special-case handling for plugin options specified in
|
||||
sos.conf in `SoSOptions.to_args().has_value()` that allows for plugin
|
||||
options to be included in the "effective options now" log message.
|
||||
|
||||
Second, move the logging of said message (and thus the merging of
|
||||
preset options, if used), to being _prior_ to the loading of plugin
|
||||
options.
|
||||
|
||||
Combined, plugin options specified in sos.conf will now be logged
|
||||
properly and this logging will occur before we set (and log the setting
|
||||
of) those options.
|
||||
|
||||
Resolves: #2663
|
||||
|
||||
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
|
||||
---
|
||||
sos/options.py | 2 ++
|
||||
sos/report/__init__.py | 30 ++++++++++++++++--------------
|
||||
2 files changed, 18 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/sos/options.py b/sos/options.py
|
||||
index a014a022..7bea3ffc 100644
|
||||
--- a/sos/options.py
|
||||
+++ b/sos/options.py
|
||||
@@ -281,6 +281,8 @@ class SoSOptions():
|
||||
null_values = ("False", "None", "[]", '""', "''", "0")
|
||||
if not value or value in null_values:
|
||||
return False
|
||||
+ if name == 'plugopts' and value:
|
||||
+ return True
|
||||
if name in self.arg_defaults:
|
||||
if str(value) == str(self.arg_defaults[name]):
|
||||
return False
|
||||
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
|
||||
index b0159e5b..82484f1d 100644
|
||||
--- a/sos/report/__init__.py
|
||||
+++ b/sos/report/__init__.py
|
||||
@@ -925,20 +925,6 @@ class SoSReport(SoSComponent):
|
||||
self._exit(1)
|
||||
|
||||
def setup(self):
|
||||
- # Log command line options
|
||||
- msg = "[%s:%s] executing 'sos %s'"
|
||||
- self.soslog.info(msg % (__name__, "setup", " ".join(self.cmdline)))
|
||||
-
|
||||
- # Log active preset defaults
|
||||
- preset_args = self.preset.opts.to_args()
|
||||
- msg = ("[%s:%s] using '%s' preset defaults (%s)" %
|
||||
- (__name__, "setup", self.preset.name, " ".join(preset_args)))
|
||||
- self.soslog.info(msg)
|
||||
-
|
||||
- # Log effective options after applying preset defaults
|
||||
- self.soslog.info("[%s:%s] effective options now: %s" %
|
||||
- (__name__, "setup", " ".join(self.opts.to_args())))
|
||||
-
|
||||
self.ui_log.info(_(" Setting up plugins ..."))
|
||||
for plugname, plug in self.loaded_plugins:
|
||||
try:
|
||||
@@ -1386,11 +1372,27 @@ class SoSReport(SoSComponent):
|
||||
self.report_md.add_list('disabled_plugins', self.opts.skip_plugins)
|
||||
self.report_md.add_section('plugins')
|
||||
|
||||
+ def _merge_preset_options(self):
|
||||
+ # Log command line options
|
||||
+ msg = "[%s:%s] executing 'sos %s'"
|
||||
+ self.soslog.info(msg % (__name__, "setup", " ".join(self.cmdline)))
|
||||
+
|
||||
+ # Log active preset defaults
|
||||
+ preset_args = self.preset.opts.to_args()
|
||||
+ msg = ("[%s:%s] using '%s' preset defaults (%s)" %
|
||||
+ (__name__, "setup", self.preset.name, " ".join(preset_args)))
|
||||
+ self.soslog.info(msg)
|
||||
+
|
||||
+ # Log effective options after applying preset defaults
|
||||
+ self.soslog.info("[%s:%s] effective options now: %s" %
|
||||
+ (__name__, "setup", " ".join(self.opts.to_args())))
|
||||
+
|
||||
def execute(self):
|
||||
try:
|
||||
self.policy.set_commons(self.get_commons())
|
||||
self.load_plugins()
|
||||
self._set_all_options()
|
||||
+ self._merge_preset_options()
|
||||
self._set_tunables()
|
||||
self._check_for_unknown_plugins()
|
||||
self._set_plugin_options()
|
||||
--
|
||||
2.34.1
|
||||
|
39
SOURCES/sos-bz2055547-honour-plugins-timeout-hardcoded.patch
Normal file
39
SOURCES/sos-bz2055547-honour-plugins-timeout-hardcoded.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From 7069e99d1c5c443f96a98a7ed6db67fa14683e67 Mon Sep 17 00:00:00 2001
|
||||
From: Pavel Moravec <pmoravec@redhat.com>
|
||||
Date: Thu, 17 Feb 2022 09:14:15 +0100
|
||||
Subject: [PATCH] [report] Honor plugins' hardcoded plugin_timeout
|
||||
|
||||
Currently, plugin's plugin_timeout hardcoded default is superseded by
|
||||
whatever --plugin-timeout value, even when this option is not used and
|
||||
we eval it to TIMEOUT_DEFAULT.
|
||||
|
||||
In this case of not setting --plugin-timeout either -k plugin.timeout,
|
||||
honour plugin's plugin_timeout instead.
|
||||
|
||||
Resolves: #2863
|
||||
Closes: #2864
|
||||
|
||||
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
|
||||
---
|
||||
sos/report/plugins/__init__.py | 5 ++++-
|
||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
|
||||
index cc5cb65b..336b4d22 100644
|
||||
--- a/sos/report/plugins/__init__.py
|
||||
+++ b/sos/report/plugins/__init__.py
|
||||
@@ -636,7 +636,10 @@ class Plugin():
|
||||
if opt_timeout is None:
|
||||
_timeout = own_timeout
|
||||
elif opt_timeout is not None and own_timeout == -1:
|
||||
- _timeout = int(opt_timeout)
|
||||
+ if opt_timeout == TIMEOUT_DEFAULT:
|
||||
+ _timeout = default_timeout
|
||||
+ else:
|
||||
+ _timeout = int(opt_timeout)
|
||||
elif opt_timeout is not None and own_timeout > -1:
|
||||
_timeout = own_timeout
|
||||
else:
|
||||
--
|
||||
2.34.1
|
||||
|
@ -5,7 +5,7 @@
|
||||
Summary: A set of tools to gather troubleshooting information from a system
|
||||
Name: sos
|
||||
Version: 4.2
|
||||
Release: 13%{?dist}
|
||||
Release: 15%{?dist}
|
||||
Group: Applications/System
|
||||
Source0: https://github.com/sosreport/sos/archive/%{version}/sos-%{version}.tar.gz
|
||||
Source1: sos-audit-%{auditversion}.tgz
|
||||
@ -42,7 +42,8 @@ Patch18: sos-bz2036697-ocp-backports.patch
|
||||
Patch19: sos-bz2043102-foreman-tasks-msgpack.patch
|
||||
Patch20: sos-bz2041488-virsh-in-foreground.patch
|
||||
Patch21: sos-bz2042966-ovn-proper-package-enablement.patch
|
||||
|
||||
Patch22: sos-bz2054882-plugopt-logging-effective-opts.patch
|
||||
Patch23: sos-bz2055547-honour-plugins-timeout-hardcoded.patch
|
||||
|
||||
%description
|
||||
Sos is a set of tools that gathers information about system
|
||||
@ -74,6 +75,8 @@ support technicians and developers.
|
||||
%patch19 -p1
|
||||
%patch20 -p1
|
||||
%patch21 -p1
|
||||
%patch22 -p1
|
||||
%patch23 -p1
|
||||
|
||||
%build
|
||||
%py3_build
|
||||
@ -140,6 +143,18 @@ of the system. Currently storage and filesystem commands are audited.
|
||||
%ghost /etc/audit/rules.d/40-sos-storage.rules
|
||||
|
||||
%changelog
|
||||
* Wed Feb 23 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-15
|
||||
- [sosnode] Handle downstream versioning for runtime option
|
||||
Resolves: bz2036697
|
||||
- [options] Fix logging on plugopts in effective sos command
|
||||
Resolves: bz2054882
|
||||
- [report] Honor plugins' hardcoded plugin_timeout
|
||||
Resolves: bz2055547
|
||||
- [policies] Set fallback to None sysroot, don't chroot to '/'
|
||||
Resolves: bz1873185
|
||||
- [ovn_central] Rename container responsable of Red Hat
|
||||
Resolves: bz2042966
|
||||
|
||||
* Wed Jan 26 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-13
|
||||
- [virsh] Catch parsing exception
|
||||
Resolves: bz2041488
|
||||
|
Loading…
Reference in New Issue
Block a user