AlmaLinux changes
This commit is contained in:
commit
9e6d64ca8f
@ -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
|
||||
|
||||
|
@ -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')
|
||||
|
5145
SOURCES/sos-bz2037350-ocp-backports.patch
Normal file
5145
SOURCES/sos-bz2037350-ocp-backports.patch
Normal file
File diff suppressed because it is too large
Load Diff
146
SOURCES/sos-bz2041855-virsh-in-foreground.patch
Normal file
146
SOURCES/sos-bz2041855-virsh-in-foreground.patch
Normal 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),
|
59
SOURCES/sos-bz2043104-foreman-tasks-msgpack.patch
Normal file
59
SOURCES/sos-bz2043104-foreman-tasks-msgpack.patch
Normal 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(
|
252
SOURCES/sos-bz2043488-ovn-proper-package-enablement.patch
Normal file
252
SOURCES/sos-bz2043488-ovn-proper-package-enablement.patch
Normal 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
|
||||
|
94
SOURCES/sos-bz2054883-plugopt-logging-effective-opts.patch
Normal file
94
SOURCES/sos-bz2054883-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-bz2055548-honour-plugins-timeout-hardcoded.patch
Normal file
39
SOURCES/sos-bz2055548-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: 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
|
||||
|
Loading…
Reference in New Issue
Block a user