AlmaLinux changes

This commit is contained in:
eabdullin 2022-04-28 16:53:02 +03:00
commit 9e6d64ca8f
9 changed files with 6974 additions and 2 deletions

View File

@ -363,3 +363,954 @@ index 10952566..a4c92acc 100644
--
2.31.1
From c6a5bbb8d75aadd5c7f76d3f469929aba2cf8060 Mon Sep 17 00:00:00 2001
From: Pavel Moravec <pmoravec@redhat.com>
Date: Wed, 5 Jan 2022 10:33:58 +0100
Subject: [PATCH] [report] Provide better warning about estimate-mode
As --estimate-only calculates disk usage based on `stat` data that
differs from outputs of other commands like `du`, enhance the warning
about reliability of the calculated estimation.
Also add a rule-of-thumb recommendation of real disk space requirements.
Resolves: #2815
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
man/en/sos-report.1 | 10 +++++++---
sos/report/__init__.py | 3 ++-
2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/man/en/sos-report.1 b/man/en/sos-report.1
index 464a77e54..e34773986 100644
--- a/man/en/sos-report.1
+++ b/man/en/sos-report.1
@@ -343,9 +343,13 @@ is available at the end.
Plugins will be collected sequentially, size of collected files and commands outputs
will be calculated and the plugin files will be immediatelly deleted prior execution
-of the next plugin. This still can consume whole free disk space, though. Please note,
-size estimations may not be accurate for highly utilized systems due to changes between
-an estimate and a real execution.
+of the next plugin. This still can consume whole free disk space, though.
+
+Please note, size estimations may not be accurate for highly utilized systems due to
+changes between an estimate and a real execution. Also some difference between
+estimation (using `stat` command) and other commands used (i.e. `du`).
+
+A rule of thumb is to reserve at least double the estimation.
.TP
.B \--upload
If specified, attempt to upload the resulting archive to a vendor defined location.
diff --git a/sos/report/__init__.py b/sos/report/__init__.py
index ef61fb344..e0617b45e 100644
--- a/sos/report/__init__.py
+++ b/sos/report/__init__.py
@@ -1330,7 +1330,8 @@ def final_work(self):
self.ui_log.info("Please note the estimation is relevant to the "
"current options.")
self.ui_log.info("Be aware that the real disk space requirements "
- "might be different.")
+ "might be different. A rule of thumb is to "
+ "reserve at least double the estimation.")
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

View File

@ -1595,3 +1595,235 @@ index 5cd8e9857..33b0e6c80 100644
ob_domain = self._new_obfuscated_domain(dname)
ob_domain = '.'.join([ob_domain, top_domain])
self.dataset['.'.join(domain)] = ob_domain
From f5e1298162a9393ea2d9f5c4df40dfece50f5f88 Mon Sep 17 00:00:00 2001
From: Jake Hunsaker <jhunsake@redhat.com>
Date: Thu, 6 Jan 2022 13:15:15 -0500
Subject: [PATCH 1/3] [hostname] Fix loading and detection of long base domains
Our domain matching has up to now assumed that users would be providing
'base' domains such as 'example.com' whereby something like
'foo.bar.example.com' is a subdomain (or host) within that base domain.
However, the use case exists to provide 'foo.bar.example.com' as the
base domain, without wanting to obfuscate 'example.com' directly.
This commit fixes our handling of both loading these longer domains and
doing the 'domain is part of a domain we want to obfuscate' check.
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
---
sos/cleaner/mappings/hostname_map.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/sos/cleaner/mappings/hostname_map.py b/sos/cleaner/mappings/hostname_map.py
index 33b0e6c8..7a7cf6b8 100644
--- a/sos/cleaner/mappings/hostname_map.py
+++ b/sos/cleaner/mappings/hostname_map.py
@@ -50,10 +50,14 @@ class SoSHostnameMap(SoSMap):
in this parser, we need to re-inject entries from the map_file into
these dicts and not just the underlying 'dataset' dict
"""
- for domain in self.dataset:
+ for domain, ob_pair in self.dataset.items():
if len(domain.split('.')) == 1:
self.hosts[domain.split('.')[0]] = self.dataset[domain]
else:
+ if ob_pair.startswith('obfuscateddomain'):
+ # directly exact domain matches
+ self._domains[domain] = ob_pair.split('.')[0]
+ continue
# strip the host name and trailing top-level domain so that
# we in inject the domain properly for later string matching
@@ -102,9 +106,12 @@ class SoSHostnameMap(SoSMap):
and should be obfuscated
"""
host = domain.split('.')
+ no_tld = '.'.join(domain.split('.')[0:-1])
if len(host) == 1:
# don't block on host's shortname
return host[0] in self.hosts.keys()
+ elif any([no_tld.endswith(_d) for _d in self._domains]):
+ return True
else:
domain = host[0:-1]
for known_domain in self._domains:
--
2.31.1
From e241cf33a14ecd4e848a5fd857c5d3d7d07fbd71 Mon Sep 17 00:00:00 2001
From: Jake Hunsaker <jhunsake@redhat.com>
Date: Thu, 6 Jan 2022 13:18:44 -0500
Subject: [PATCH 2/3] [cleaner] Improve parser-specific file skipping
This commit improves our handling of skipping files on a per-parser
basis, by first filtering the list of parsers that `obfuscate_line()`
will iterate over by the parser's `skip_file` class attr, rather than
relying on higher-level checks.
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
---
sos/cleaner/__init__.py | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/sos/cleaner/__init__.py b/sos/cleaner/__init__.py
index 3f530d44..5686e213 100644
--- a/sos/cleaner/__init__.py
+++ b/sos/cleaner/__init__.py
@@ -12,6 +12,7 @@ import hashlib
import json
import logging
import os
+import re
import shutil
import tempfile
@@ -640,10 +641,16 @@ third party.
self.log_debug("Obfuscating %s" % short_name or filename,
caller=arc_name)
tfile = tempfile.NamedTemporaryFile(mode='w', dir=self.tmpdir)
+ _parsers = [
+ _p for _p in self.parsers if not
+ any([
+ re.match(p, short_name) for p in _p.skip_files
+ ])
+ ]
with open(filename, 'r') as fname:
for line in fname:
try:
- line, count = self.obfuscate_line(line)
+ line, count = self.obfuscate_line(line, _parsers)
subs += count
tfile.write(line)
except Exception as err:
@@ -713,7 +720,7 @@ third party.
pass
return string_data
- def obfuscate_line(self, line):
+ def obfuscate_line(self, line, parsers=None):
"""Run a line through each of the obfuscation parsers, keeping a
cumulative total of substitutions done on that particular line.
@@ -721,6 +728,8 @@ third party.
:param line str: The raw line as read from the file being
processed
+ :param parsers: A list of parser objects to obfuscate
+ with. If None, use all.
Returns the fully obfuscated line and the number of substitutions made
"""
@@ -729,7 +738,9 @@ third party.
count = 0
if not line.strip():
return line, count
- for parser in self.parsers:
+ if parsers is None:
+ parsers = self.parsers
+ for parser in parsers:
try:
line, _count = parser.parse_line(line)
count += _count
--
2.31.1
From 96c9a833e77639a853b7d3d6f1df68bbbbe5e9cb Mon Sep 17 00:00:00 2001
From: Jake Hunsaker <jhunsake@redhat.com>
Date: Thu, 6 Jan 2022 13:20:32 -0500
Subject: [PATCH 3/3] [cleaner] Add skips for known files and usernames
Adds skips for `/proc/kallsyms` which should never be obfuscated, as
well as any packaging-related log file for the IP parser. Further, do
not obfuscate the `stack` users, as that is a well-known user for many
configurations that, if obfuscated, could result in undesired string
substitutions in normal logging.
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
---
sos/cleaner/archives/__init__.py | 2 ++
sos/cleaner/parsers/ip_parser.py | 3 ++-
sos/cleaner/parsers/username_parser.py | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/sos/cleaner/archives/__init__.py b/sos/cleaner/archives/__init__.py
index 795c5a78..cbf1f809 100644
--- a/sos/cleaner/archives/__init__.py
+++ b/sos/cleaner/archives/__init__.py
@@ -43,6 +43,7 @@ class SoSObfuscationArchive():
type_name = 'undetermined'
description = 'undetermined'
is_nested = False
+ skip_files = []
prep_files = {}
def __init__(self, archive_path, tmpdir):
@@ -111,6 +112,7 @@ class SoSObfuscationArchive():
Returns: list of files and file regexes
"""
return [
+ 'proc/kallsyms',
'sosreport-',
'sys/firmware',
'sys/fs',
diff --git a/sos/cleaner/parsers/ip_parser.py b/sos/cleaner/parsers/ip_parser.py
index 71d38be8..b007368c 100644
--- a/sos/cleaner/parsers/ip_parser.py
+++ b/sos/cleaner/parsers/ip_parser.py
@@ -37,7 +37,8 @@ class SoSIPParser(SoSCleanerParser):
'sos_commands/snappy/snap_list_--all',
'sos_commands/snappy/snap_--version',
'sos_commands/vulkan/vulkaninfo',
- 'var/log/.*dnf.*'
+ 'var/log/.*dnf.*',
+ 'var/log/.*packag.*' # get 'packages' and 'packaging' logs
]
map_file_key = 'ip_map'
diff --git a/sos/cleaner/parsers/username_parser.py b/sos/cleaner/parsers/username_parser.py
index 229c7de4..3208a655 100644
--- a/sos/cleaner/parsers/username_parser.py
+++ b/sos/cleaner/parsers/username_parser.py
@@ -32,6 +32,7 @@ class SoSUsernameParser(SoSCleanerParser):
'nobody',
'nfsnobody',
'shutdown',
+ 'stack',
'reboot',
'root',
'ubuntu',
--
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')

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
From 137abd394f64a63b6633949b5c81159af12038b7 Mon Sep 17 00:00:00 2001
From: Pavel Moravec <pmoravec@redhat.com>
Date: Fri, 14 Jan 2022 20:07:17 +0100
Subject: [PATCH] [report] pass foreground argument to collect_cmd_output
Related to: #2825
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
sos/report/plugins/__init__.py | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
index 98f163ab9..1bbdf28a4 100644
--- a/sos/report/plugins/__init__.py
+++ b/sos/report/plugins/__init__.py
@@ -1920,6 +1920,8 @@ class Plugin(object):
:param subdir: Subdir in plugin directory to save to
:param changes: Does this cmd potentially make a change
on the system?
+ :param foreground: Run the `cmd` in the foreground with a
+ TTY
:param tags: Add tags in the archive manifest
:param cmd_as_tag: Format command string to tag
@@ -2145,7 +2147,8 @@ def collect_cmd_output(self, cmd, suggest_filename=None,
root_symlink=False, timeout=None,
stderr=True, chroot=True, runat=None, env=None,
binary=False, sizelimit=None, pred=None,
- changes=False, subdir=None, tags=[]):
+ changes=False, foreground=False, subdir=None,
+ tags=[]):
"""Execute a command and save the output to a file for inclusion in the
report, then return the results for further use by the plugin
@@ -2188,6 +2191,9 @@ def collect_cmd_output(self, cmd, suggest_filename=None,
on the system?
:type changes: ``bool``
+ :param foreground: Run the `cmd` in the foreground with a TTY
+ :type foreground: ``bool``
+
:param tags: Add tags in the archive manifest
:type tags: ``str`` or a ``list`` of strings
@@ -2206,8 +2212,8 @@ def collect_cmd_output(self, cmd, suggest_filename=None,
return self._collect_cmd_output(
cmd, suggest_filename=suggest_filename, root_symlink=root_symlink,
timeout=timeout, stderr=stderr, chroot=chroot, runat=runat,
- env=env, binary=binary, sizelimit=sizelimit, subdir=subdir,
- tags=tags
+ env=env, binary=binary, sizelimit=sizelimit, foreground=foreground,
+ subdir=subdir, tags=tags
)
def exec_cmd(self, cmd, timeout=None, stderr=True, chroot=True,
From 747fef695e4ff08f320c5f03090bdefa7154c761 Mon Sep 17 00:00:00 2001
From: Pavel Moravec <pmoravec@redhat.com>
Date: Fri, 14 Jan 2022 20:10:22 +0100
Subject: [PATCH] [virsh] Call virsh commands in the foreground / with a TTY
In some virsh errors (like unable to connect to a hypervisor),
the tool requires to communicate to TTY otherwise it can get stuck
(when called via Popen with a timeout).
Calling it on foreground prevents the stuck / waiting on cmd timeout.
Resolves: #2825
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
sos/report/plugins/virsh.py | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/sos/report/plugins/virsh.py b/sos/report/plugins/virsh.py
index d6b7c16761..08f9a8488c 100644
--- a/sos/report/plugins/virsh.py
+++ b/sos/report/plugins/virsh.py
@@ -39,26 +39,30 @@ def setup(self):
]
for subcmd in subcmds:
- self.add_cmd_output('%s %s' % (cmd, subcmd))
+ self.add_cmd_output('%s %s' % (cmd, subcmd), foreground=True)
# get network, pool and nwfilter elements
for k in ['net', 'nwfilter', 'pool']:
- k_list = self.collect_cmd_output('%s %s-list' % (cmd, k))
+ k_list = self.collect_cmd_output('%s %s-list' % (cmd, k),
+ foreground=True)
if k_list['status'] == 0:
k_lines = k_list['output'].splitlines()
# the 'Name' column position changes between virsh cmds
pos = k_lines[0].split().index('Name')
for j in filter(lambda x: x, k_lines[2:]):
n = j.split()[pos]
- self.add_cmd_output('%s %s-dumpxml %s' % (cmd, k, n))
+ self.add_cmd_output('%s %s-dumpxml %s' % (cmd, k, n),
+ foreground=True)
# cycle through the VMs/domains list, ignore 2 header lines and latest
# empty line, and dumpxml domain name in 2nd column
- domains_output = self.exec_cmd('%s list --all' % cmd)
+ domains_output = self.exec_cmd('%s list --all' % cmd, foreground=True)
if domains_output['status'] == 0:
domains_lines = domains_output['output'].splitlines()[2:]
for domain in filter(lambda x: x, domains_lines):
d = domain.split()[1]
for x in ['dumpxml', 'dominfo', 'domblklist']:
- self.add_cmd_output('%s %s %s' % (cmd, x, d))
+ self.add_cmd_output('%s %s %s' % (cmd, x, d),
+ foreground=True)
+
# vim: et ts=4 sw=4
From 9bc032129ec66766f07349dd115335f104888efa Mon Sep 17 00:00:00 2001
From: Pavel Moravec <pmoravec@redhat.com>
Date: Wed, 26 Jan 2022 09:44:01 +0100
Subject: [PATCH] [virsh] Catch parsing exception
In case virsh output is malformed or missing 'Name' otherwise,
catch parsing exception and continue in next for loop iteration.
Resolves: #2836
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
sos/report/plugins/virsh.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/sos/report/plugins/virsh.py b/sos/report/plugins/virsh.py
index 08f9a8488..2ce1df15c 100644
--- a/sos/report/plugins/virsh.py
+++ b/sos/report/plugins/virsh.py
@@ -48,7 +48,11 @@ def setup(self):
if k_list['status'] == 0:
k_lines = k_list['output'].splitlines()
# the 'Name' column position changes between virsh cmds
- pos = k_lines[0].split().index('Name')
+ # catch the rare exceptions when 'Name' is not found
+ try:
+ pos = k_lines[0].split().index('Name')
+ except Exception:
+ continue
for j in filter(lambda x: x, k_lines[2:]):
n = j.split()[pos]
self.add_cmd_output('%s %s-dumpxml %s' % (cmd, k, n),

View File

@ -0,0 +1,59 @@
From 5634f7dd77eff821f37daa953fa86cc783d3b937 Mon Sep 17 00:00:00 2001
From: Pavel Moravec <pmoravec@redhat.com>
Date: Fri, 21 Jan 2022 16:27:33 +0100
Subject: [PATCH] [foreman] Use psql-msgpack-decode wrapper for dynflow >= 1.6
In dynflow >=1.6.3, dynflow* tables in postgres are encoded by
msgpack which makes plain CSV dumps unreadable. In such a case,
psql-msgpack-decode wrapper tool from dynflow-utils (of any
version) must be used instead of the plain psql command.
Resolves: #2830
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
sos/report/plugins/foreman.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/sos/report/plugins/foreman.py b/sos/report/plugins/foreman.py
index 314a651d1..3fd80e6a8 100644
--- a/sos/report/plugins/foreman.py
+++ b/sos/report/plugins/foreman.py
@@ -244,8 +244,16 @@ def setup(self):
self.add_cmd_output(_cmd, suggest_filename=table, timeout=600,
sizelimit=100, env=self.env)
+ # dynflow* tables on dynflow >=1.6.3 are encoded and hence in that
+ # case, psql-msgpack-decode wrapper tool from dynflow-utils (any
+ # version) must be used instead of plain psql command
+ dynutils = self.is_installed('dynflow-utils')
for dyn in foremancsv:
- _cmd = self.build_query_cmd(foremancsv[dyn], csv=True)
+ binary = "psql"
+ if dyn != 'foreman_tasks_tasks' and dynutils:
+ binary = "/usr/libexec/psql-msgpack-decode"
+ _cmd = self.build_query_cmd(foremancsv[dyn], csv=True,
+ binary=binary)
self.add_cmd_output(_cmd, suggest_filename=dyn, timeout=600,
sizelimit=100, env=self.env)
@@ -270,7 +278,7 @@ def setup(self):
# collect http[|s]_proxy env.variables
self.add_env_var(["http_proxy", "https_proxy"])
- def build_query_cmd(self, query, csv=False):
+ def build_query_cmd(self, query, csv=False, binary="psql"):
"""
Builds the command needed to invoke the pgsql query as the postgres
user.
@@ -281,8 +289,8 @@ def build_query_cmd(self, query, csv=False):
if csv:
query = "COPY (%s) TO STDOUT " \
"WITH (FORMAT 'csv', DELIMITER ',', HEADER)" % query
- _dbcmd = "psql --no-password -h %s -p 5432 -U foreman -d foreman -c %s"
- return _dbcmd % (self.dbhost, quote(query))
+ _dbcmd = "%s --no-password -h %s -p 5432 -U foreman -d foreman -c %s"
+ return _dbcmd % (binary, self.dbhost, quote(query))
def postproc(self):
self.do_path_regex_sub(

View File

@ -0,0 +1,252 @@
From 210b83e1d1164d29b1f6198675b8b596c4af8336 Mon Sep 17 00:00:00 2001
From: Daniel Alvarez Sanchez <dalvarez@redhat.com>
Date: Thu, 20 Jan 2022 12:58:44 +0100
Subject: [PATCH] [ovn_central] Account for Red Hat ovn package naming
Previous ovn packages were 'ovn2xxx' and now they have
been renamed to 'ovn-2xxx'. This causes sos tool to not
recognize that the packages are installed and it won't
collect the relevant data.
This patch is changing the match to be compatible
with the previous and newer naming conventions.
Signed-off-by: Daniel Alvarez Sanchez <dalvarez@redhat.com>
---
sos/report/plugins/ovn_central.py | 2 +-
sos/report/plugins/ovn_host.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sos/report/plugins/ovn_central.py b/sos/report/plugins/ovn_central.py
index ddbf288da..0f947d4c5 100644
--- a/sos/report/plugins/ovn_central.py
+++ b/sos/report/plugins/ovn_central.py
@@ -147,7 +147,7 @@ def setup(self):
class RedHatOVNCentral(OVNCentral, RedHatPlugin):
- packages = ('openvswitch-ovn-central', 'ovn2.*-central', )
+ packages = ('openvswitch-ovn-central', 'ovn.*-central', )
ovn_sbdb_sock_path = '/var/run/openvswitch/ovnsb_db.ctl'
diff --git a/sos/report/plugins/ovn_host.py b/sos/report/plugins/ovn_host.py
index 78604a15a..25c38cccc 100644
--- a/sos/report/plugins/ovn_host.py
+++ b/sos/report/plugins/ovn_host.py
@@ -55,7 +55,7 @@ def check_enabled(self):
class RedHatOVNHost(OVNHost, RedHatPlugin):
- packages = ('openvswitch-ovn-host', 'ovn2.*-host', )
+ packages = ('openvswitch-ovn-host', 'ovn.*-host', )
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

View 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

View 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

View File

@ -5,7 +5,7 @@
Summary: A set of tools to gather troubleshooting information from a system
Name: sos
Version: 4.2
Release: 8%{?dist}.alma
Release: 15%{?dist}.alma
Group: Applications/System
Source0: https://github.com/sosreport/sos/archive/%{version}/sos-%{version}.tar.gz
Source1: sos-audit-%{auditversion}.tgz
@ -41,6 +41,14 @@ Patch14: sos-bz2024893-cleaner-hostnames-improvements.patch
Patch15: sos-bz2025611-RHTS-api-change.patch
Patch16: sos-bz2034001-nvidia-GPU-info.patch
Patch17: sos-bz2031777-rhui-logs.patch
Patch18: sos-bz2037350-ocp-backports.patch
Patch19: sos-bz2043104-foreman-tasks-msgpack.patch
Patch20: sos-bz2041855-virsh-in-foreground.patch
Patch21: sos-bz2043488-ovn-proper-package-enablement.patch
Patch22: sos-bz2054883-plugopt-logging-effective-opts.patch
Patch23: sos-bz2055548-honour-plugins-timeout-hardcoded.patch
# almalinux
Patch1000: sos-almalinux-branding.patch
@ -70,6 +78,14 @@ support technicians and developers.
%patch15 -p1
%patch16 -p1
%patch17 -p1
%patch18 -p1
%patch19 -p1
%patch20 -p1
%patch21 -p1
%patch22 -p1
%patch23 -p1
# almalinux
%patch1000 -p1
@ -139,9 +155,47 @@ of the system. Currently storage and filesystem commands are audited.
%changelog
* Wed Jan 19 2022 Eduard Abdullin <eabdullin@almalinux.org> - 4.2-8.alma
* Thu Apr 28 2022 Eduard Abdullin <eabdullin@almalinux.org> - 4.2-15.alma
- Debrand for AlmaLinux
* Wed Feb 23 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-15
- [sosnode] Handle downstream versioning for runtime option
Resolves: bz2037350
- [options] Fix logging on plugopts in effective sos command
Resolves: bz2054883
- [report] Honor plugins' hardcoded plugin_timeout
Resolves: bz2055548
- [policies] Set fallback to None sysroot, don't chroot to '/'
Resolves: bz2011537
- [ovn_central] Rename container responsable of Red Hat
Resolves: bz2043488
* Wed Jan 26 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-13
- [virsh] Catch parsing exception
Resolves: bz2041855
* Tue Jan 25 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-12
- [foreman] Use psql-msgpack-decode wrapper for dynflow >= 1.6
Resolves: bz2043104
- [virsh] Call virsh commands in the foreground / with a TTY
Resolves: bz2041855
- [ovn_central] Account for Red Hat ovn package naming
Resolves: bz2043488
- [clean,parsers] Build regex lists for static items only once
Resolves: bz2037350
* Mon Jan 10 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-11
- [report] Add journal logs for NetworkManager plugin
Resolves: bz2037350
* Fri Jan 07 2022 Pavel Moravec <pmoravec@redhat.com> = 4.2-9
- add oc transport, backport various PRs for OCP
Resolves: bz2037350
- [report] Provide better warning about estimate-mode
Resolves: bz2011537
- [hostname] Fix loading and detection of long base domains
Resolves: bz2024893
* Sun Dec 19 2021 Pavel Moravec <pmoravec@redhat.com> = 4.2-8
- [rhui] New log folder
Resolves: bz2031777