diff options
author | Jake Hunsaker <jhunsake@redhat.com> | 2022-08-19 14:26:59 -0400 |
---|---|---|
committer | Jake Hunsaker <jhunsake@redhat.com> | 2022-09-28 09:48:46 -0400 |
commit | dc2bff9708d7dbb6447ed2c5f28eb9bfd52667a5 (patch) | |
tree | 1e50775f39d647064dbf0661768636dd2260be1f | |
parent | d9884ab144a253b788f4cfc966301f645ffed5fb (diff) | |
download | sos-dc2bff9708d7dbb6447ed2c5f28eb9bfd52667a5.tar.gz |
[process,PackageManager] Create a mapping of processes to packages
Adds a new manual collection to the `process` plugin, that tries to
compile a mapping of running processes' binaries to an owning package
via the package manager. As such, package managers now have a new
`pkg_by_path()` method that serves this purpose.
Closes: #1350
Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
-rw-r--r-- | sos/policies/package_managers/__init__.py | 26 | ||||
-rw-r--r-- | sos/policies/package_managers/dpkg.py | 1 | ||||
-rw-r--r-- | sos/policies/package_managers/rpm.py | 1 | ||||
-rw-r--r-- | sos/report/plugins/__init__.py | 2 | ||||
-rw-r--r-- | sos/report/plugins/process.py | 25 | ||||
-rw-r--r-- | tests/report_tests/plugin_tests/collect_manual_tests.py (renamed from tests/report_tests/plugin_tests/collet_manual_tests.py) | 2 |
6 files changed, 52 insertions, 5 deletions
diff --git a/sos/policies/package_managers/__init__.py b/sos/policies/package_managers/__init__.py index 8a5c4ee5..f16a57d2 100644 --- a/sos/policies/package_managers/__init__.py +++ b/sos/policies/package_managers/__init__.py @@ -50,12 +50,13 @@ class PackageManager(): verify_command = None verify_filter = None files_command = None + query_path_command = None chroot = None files = None - def __init__(self, chroot=None, query_command=None, - verify_command=None, verify_filter=None, - files_command=None, remote_exec=None): + def __init__(self, chroot=None, query_command=None, verify_command=None, + verify_filter=None, files_command=None, + query_path_command=None, remote_exec=None): self._packages = {} self.files = [] @@ -63,6 +64,7 @@ class PackageManager(): self.verify_command = verify_command or self.verify_command self.verify_filter = verify_filter or self.verify_filter self.files_command = files_command or self.files_command + self.query_path_command = query_path_command or self.query_path_command # if needed, append the remote command to these so that this returns # the remote package details, not local @@ -192,6 +194,24 @@ class PackageManager(): self.files = files.splitlines() return self.files + def pkg_by_path(self, path): + """Given a path, return the package that owns that path. + + :param path: The filepath to check for package ownership + :type path: ``str`` + + :returns: The package name or 'unknown' + :rtype: ``str`` + """ + if not self.query_path_command: + return 'unknown' + try: + cmd = f"{self.query_path_command} {path}" + pkg = shell_out(cmd, timeout=5, chroot=self.chroot) + return pkg.splitlines() or 'unknown' + except Exception: + return 'unknown' + def build_verify_command(self, packages): """build_verify_command(self, packages) -> str Generate a command to verify the list of packages given diff --git a/sos/policies/package_managers/dpkg.py b/sos/policies/package_managers/dpkg.py index 7619e929..684c6f60 100644 --- a/sos/policies/package_managers/dpkg.py +++ b/sos/policies/package_managers/dpkg.py @@ -16,6 +16,7 @@ class DpkgPackageManager(PackageManager): """ query_command = "dpkg-query -W -f='${Package}|${Version}\\n'" + query_path_command = "dpkg -S" verify_command = "dpkg --verify" verify_filter = "" diff --git a/sos/policies/package_managers/rpm.py b/sos/policies/package_managers/rpm.py index 5150e1e0..0d16a1e3 100644 --- a/sos/policies/package_managers/rpm.py +++ b/sos/policies/package_managers/rpm.py @@ -16,6 +16,7 @@ class RpmPackageManager(PackageManager): """ query_command = 'rpm -qa --queryformat "%{NAME}|%{VERSION}|%{RELEASE}\\n"' + query_path_command = 'rpm -qf' files_command = 'rpm -qal' verify_command = 'rpm -V' verify_filter = ["debuginfo", "-devel"] diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py index 42032d50..0fb5dc20 100644 --- a/sos/report/plugins/__init__.py +++ b/sos/report/plugins/__init__.py @@ -3164,7 +3164,7 @@ class Plugin(): self._log_info(f"manual collection '{fname}' finished in {run}") if isinstance(tags, str): tags = [tags] - self.manifest.collections[fname.split('.')[0]] = { + self.manifest.collections[fname] = { 'filepath': _pfname, 'tags': tags } diff --git a/sos/report/plugins/process.py b/sos/report/plugins/process.py index 62705c4f..50279502 100644 --- a/sos/report/plugins/process.py +++ b/sos/report/plugins/process.py @@ -6,6 +6,7 @@ # # See the LICENSE file in the source distribution for further information. +import json import re from sos.report.plugins import Plugin, IndependentPlugin, PluginOpt @@ -88,4 +89,28 @@ class Process(Plugin, IndependentPlugin): "pidstat -p ALL -rudvwsRU --human -h", "pidstat -tl" ]) + + def collect(self): + with self.collection_file('pids_to_packages.json') as pfile: + if not self.policy.package_manager.query_path_command: + pfile.write('Package manager not configured for path queries') + return + _ps = self.exec_cmd('ps --no-headers aex') + pidpkg = {} + paths = {} + if not _ps['status'] == 0: + pfile.write(f"Unable to get process list: {_ps['output']}") + return + for proc in _ps['output'].splitlines(): + proc = proc.strip().split() + pid = proc[0] + path = proc[4] + if not self.path_exists(path): + continue + if path not in paths: + paths[path] = self.policy.package_manager.pkg_by_path(path) + pidpkg[pid] = {'path': path, 'package': paths[path]} + + pfile.write(json.dumps(pidpkg, indent=4)) + # vim: set et ts=4 sw=4 : diff --git a/tests/report_tests/plugin_tests/collet_manual_tests.py b/tests/report_tests/plugin_tests/collect_manual_tests.py index fdcda526..7000d5e0 100644 --- a/tests/report_tests/plugin_tests/collet_manual_tests.py +++ b/tests/report_tests/plugin_tests/collect_manual_tests.py @@ -34,4 +34,4 @@ class CollectManualTest(StageOneReportTest): pkgman = self.get_plugin_manifest('unpackaged') self.assertTrue(pkgman['collections']['unpackaged']) pyman = self.get_plugin_manifest('python') - self.assertTrue(pyman['collections']['digests']) + self.assertTrue(pyman['collections']['digests.json']) |