From e206710a236b03fe38f5dc1b4d42f6fff6a9864a Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Tue, 7 Nov 2023 11:43:14 +0100 Subject: [PATCH] Introduce the checkmptctl actor --- .../el7toel8/actors/checkmptctl/actor.py | 19 ++++ .../checkmptctl/libraries/checkmptctl.py | 97 +++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 repos/system_upgrade/el7toel8/actors/checkmptctl/actor.py create mode 100644 repos/system_upgrade/el7toel8/actors/checkmptctl/libraries/checkmptctl.py diff --git a/repos/system_upgrade/el7toel8/actors/checkmptctl/actor.py b/repos/system_upgrade/el7toel8/actors/checkmptctl/actor.py new file mode 100644 index 0000000000..b8fc884d7e --- /dev/null +++ b/repos/system_upgrade/el7toel8/actors/checkmptctl/actor.py @@ -0,0 +1,19 @@ +from leapp.actors import Actor +from leapp.libraries.actor.checkmptctl import check_mptctl +from leapp.models import ActiveKernelModulesFacts +from leapp.reporting import Report +from leapp.tags import ChecksPhaseTag, IPUWorkflowTag + + +class CheckMptctl(Actor): + """ + Check if a process uses the mptctl kernel module that will be removed. + It could prevent the unloading of this module which does not handle HW. + """ + name = "check_mptctl" + consumes = (ActiveKernelModulesFacts,) + produces = (Report,) + tags = (ChecksPhaseTag, IPUWorkflowTag,) + + def process(self): + check_mptctl() diff --git a/repos/system_upgrade/el7toel8/actors/checkmptctl/libraries/checkmptctl.py b/repos/system_upgrade/el7toel8/actors/checkmptctl/libraries/checkmptctl.py new file mode 100644 index 0000000000..de8c8b4f5b --- /dev/null +++ b/repos/system_upgrade/el7toel8/actors/checkmptctl/libraries/checkmptctl.py @@ -0,0 +1,97 @@ +#!/usr/libexec/platform-python + +from os import listdir, readlink +from os.path import islink +from leapp import reporting +from leapp.libraries.stdlib import api +from leapp.models import ActiveKernelModulesFacts + +iodevs = ['/dev/mptctl', '/dev/mpt2ctl', '/dev/mpt3ctl'] + + +def get_open_files(): + """ + Mimics fuser to get the filenames corresponding to + open file descriptors for running processes + """ + open_files = {} + for pid in listdir('/proc'): + if not pid.isdigit(): + continue + open_list = [] + for fd in listdir('/proc/%s/fd' % pid): + fd_path = '/proc/%s/fd/%s' % (pid, fd) + if islink(fd_path): + open_list.append(readlink(fd_path)) + if len(open_list): + open_files[pid] = open_list + return open_files + + +def get_process_info(pid): + """ Return the PID alongside the command line in use """ + try: + with open('/proc/%s/cmdline' % pid, 'r') as f: + cmdline = f.read().split('\0') + return "%s: %s" % (pid, " ".join(cmdline)) + except IOError: # in case the process is already dead + return + + +def get_mptctl_locks(open_files): + """ + Get the list of processes that prevent the unloading of the mptctl module + Note: monitoring tools from Dell and HP are known to use it. + """ + locks = [] + for pid in open_files.keys(): + if any(f in iodevs for f in open_files[pid]): + locks.append(pid) + return locks + + +def is_module_loaded(module): + """ + Determines if the given kernel module has been reported in the ActiveKernelModuleFacts as loaded. + :return: True if the module has been found in the ActiveKernelModuleFacts. + :rtype: bool + """ + for fact in api.consume(ActiveKernelModulesFacts): + for active_module in fact.kernel_modules: + if active_module.filename == module: + return True + return False + + +def check_mptctl(): + """ Main actor process """ + if not is_module_loaded("mptctl"): + return + + mptctl_locks = get_mptctl_locks(get_open_files()) + + if not mptctl_locks: + return + + processes = '\n'.join([get_process_info(pid) for pid in mptctl_locks]) + + summary = ( + 'Leapp detected that the following processes are using the mptctl ' + 'kernel module which will be removed in RHEL 8:\n{0}' + ) + + hint = ( + 'Stop this application or the service that runs this process.' + ) + + reporting.create_report([ + reporting.Title( + 'Detected processes that are using mptctl.' + ), + reporting.Summary(summary.format(processes)), + reporting.Remediation(hint=hint.format(processes)), + reporting.Severity(reporting.Severity.HIGH), + reporting.Groups([reporting.Groups.KERNEL, reporting.Groups.DRIVERS]), + reporting.Groups([reporting.Groups.INHIBITOR]), + ]) +