Skip to content

Commit

Permalink
Fix error message when repoquery fails to retrieve information on kmo…
Browse files Browse the repository at this point in the history
…d packages (oamg#818)

* When repoquery fails to run (for instance, when repoquery decides that there isn't enough disk space
  to download metadata from the repository), we were printing an error message that there were no kmod
  containing packages.  With this change, we will print an error message that says repoquery failed.

* Now that we are printing a unified report for pre-check failures, we need to include the referenced
  yum output in the logger.critical message.  Otherwise, the report will say to look at the "above yum
  output", but that output won't be present in the report handed to insights.

Fixes https://issues.redhat.com/browse/RHELC-895
Fixes oamg#610
  • Loading branch information
abadger authored Nov 2, 2023
1 parent 0c8decd commit 8a7b98c
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 36 deletions.
52 changes: 48 additions & 4 deletions convert2rhel/actions/pre_ponr_changes/kernel_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ class RHELKernelModuleNotFound(Exception):
pass


class PackageRepositoryError(Exception):
pass


class EnsureKernelModulesCompatibility(actions.Action):
id = "ENSURE_KERNEL_MODULES_COMPATIBILITY"
dependencies = ("SUBSCRIBE_SYSTEM",)
Expand All @@ -59,16 +63,41 @@ def _get_loaded_kmods(self):

def _get_rhel_supported_kmods(self):
"""Return set of target RHEL supported kernel modules."""
precache = [
"yum",
"makecache",
"--releasever=%s" % system_info.releasever,
"--setopt=*.skip_if_unavailable=False",
]
basecmd = [
"repoquery",
"--releasever=%s" % system_info.releasever,
]

if system_info.version.major >= 8:
basecmd.append("--setopt=module_platform_id=platform:el" + str(system_info.version.major))
precache.append("--setopt=module_platform_id=platform:el" + str(system_info.version.major))

active_repos = ["--disablerepo=*"]
for repoid in system_info.get_enabled_rhel_repos():
basecmd.extend(("--repoid", repoid))
active_repos.extend(("--enablerepo", repoid))
precache.extend(active_repos)
basecmd.extend(active_repos)

# Retrieve the yum metadata for the repos we use. yum makecache will
# error out if there is a problem downloading the metadata (for instance,
# no disk space left to save it) whereas repoquery will return no results
# if there is already some metadata available.

precache_out, precache_exit_code = run_subprocess(precache, print_output=False)
if precache_exit_code != 0:
raise PackageRepositoryError(
"We were unable to download the repository metadata for (%s) to"
" determine packages containing kernel modules. Can be caused by"
" not enough disk space in /var/cache or too little memory. The"
" yum output below may have a clue for what went wrong in this"
" case:\n\n%s" % (", ".join(system_info.get_enabled_rhel_repos()), precache_out)
)

cmd = basecmd[:]
cmd.append("-f")
Expand All @@ -77,8 +106,15 @@ def _get_rhel_supported_kmods(self):
# Without the release package installed, dnf can't determine the
# modularity platform ID. get output of a command to get all
# packages which are the source of kmods
kmod_pkgs_str, _ = run_subprocess(cmd, print_output=False)

kmod_pkgs_str, repoquery_exit_code = run_subprocess(cmd, print_output=False)

if repoquery_exit_code != 0:
raise PackageRepositoryError(
"We were unable to query the repositories (%s) to"
" determine packages containing kernel modules."
" Output from the failed repoquery command:\n\n%s"
% (", ".join(system_info.get_enabled_rhel_repos()), kmod_pkgs_str)
)
# from these packages we select only the latest one
kmod_pkgs = self._get_most_recent_unique_kernel_pkgs(kmod_pkgs_str.rstrip("\n").split())
if not kmod_pkgs:
Expand Down Expand Up @@ -245,6 +281,14 @@ def run(self):
return

logger.debug("All loaded kernel modules are available in RHEL.")
except PackageRepositoryError as e:
self.set_result(
level="ERROR",
id="PROBLEM_WITH_PACKAGE_REPO",
title="Could not download package metadata",
description="There was an error retrieving the package metadata to verify kernel modules are available in RHEL.",
diagnosis=str(e),
)
except RHELKernelModuleNotFound as e:
self.set_result(
level="ERROR",
Expand All @@ -260,5 +304,5 @@ def run(self):
id="CANNOT_COMPARE_PACKAGE_VERSIONS",
title="Error while comparing packages",
description="There was an error while detecting the kernel package which corresponds to the kernel modules present on the system.",
diagnosis="Package comparison failed: %s" % e,
diagnosis="Package comparison failed: %s" % str(e),
)
9 changes: 7 additions & 2 deletions convert2rhel/pkghandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def _enable(self):
# and we need these packages to be replaced with the provided RPMs from RHEL.
command="install",
args=rpms_to_install,
print_output=True,
print_output=False,
# When installing subscription-manager packages, the RHEL repos are
# not available yet for getting dependencies so we need to use the repos that are
# available on the system
Expand All @@ -237,7 +237,8 @@ def _enable(self):
)
if ret_code:
loggerinst.critical_no_exit(
"Failed to install subscription-manager packages. See the above yum output for details."
"Failed to install subscription-manager packages. Check the yum output below for details:\n\n %s"
% output
)
raise exceptions.CriticalError(
id_="FAILED_TO_INSTALL_SUBSCRIPTION_MANAGER_PACKAGES",
Expand All @@ -247,6 +248,10 @@ def _enable(self):
% (utils.format_sequence_as_message(rpms_to_install), output, ret_code),
)

# Need to do this here instead of in pkghandler.call_yum_cmd() to avoid
# double printing the output if an error occurred.
loggerinst.info(output.rstrip("\n"))

installed_pkg_names = get_pkg_names_from_rpm_paths(rpms_to_install)
loggerinst.info(
"\nPackages we installed or updated:\n%s" % utils.format_sequence_as_message(installed_pkg_names)
Expand Down
179 changes: 150 additions & 29 deletions convert2rhel/unit_tests/actions/pre_ponr_changes/kernel_modules_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,11 @@ def ensure_kernel_modules_compatibility_instance():
@pytest.mark.parametrize(
(
"host_kmods",
"exception",
"should_be_in_logs",
"shouldnt_be_in_logs",
),
(
(
HOST_MODULES_STUB_GOOD,
False,
"loaded kernel modules are available in RHEL",
None,
),
(
HOST_MODULES_STUB_BAD,
True,
None,
"loaded kernel modules are available in RHEL",
),
),
Expand All @@ -120,16 +110,15 @@ def test_ensure_compatibility_of_kmods(
pretend_os,
caplog,
host_kmods,
exception,
should_be_in_logs,
shouldnt_be_in_logs,
):
monkeypatch.setattr(
ensure_kernel_modules_compatibility_instance, "_get_loaded_kmods", mock.Mock(return_value=host_kmods)
)
run_subprocess_mock = mock.Mock(
side_effect=run_subprocess_side_effect(
(("uname",), ("5.8.0-7642-generic\n", 0)),
(("yum", "makecache"), ("", 0)),
(("repoquery", "-f"), (REPOQUERY_F_STUB_GOOD, 0)),
(("repoquery", "-l"), (REPOQUERY_L_STUB_GOOD, 0)),
)
Expand All @@ -140,25 +129,82 @@ def test_ensure_compatibility_of_kmods(
value=run_subprocess_mock,
)

if exception:
ensure_kernel_modules_compatibility_instance.run()
assert_actions_result(
ensure_kernel_modules_compatibility_instance,
level="OVERRIDABLE",
id="UNSUPPORTED_KERNEL_MODULES",
title="Unsupported kernel modules",
description="Unsupported kernel modules were found",
diagnosis="The following loaded kernel modules are not available in RHEL:",
remediation="Ensure you have updated the kernel to the latest available version and rebooted the system.",
ensure_kernel_modules_compatibility_instance.run()
assert_actions_result(ensure_kernel_modules_compatibility_instance, level="SUCCESS")

assert should_be_in_logs in caplog.records[-1].message


@pytest.mark.parametrize(
(
"host_kmods",
"repo_kmod_pkgs",
"makecache_output",
"error_id",
"level",
),
(
(
HOST_MODULES_STUB_BAD,
REPOQUERY_F_STUB_GOOD,
("", 0),
"UNSUPPORTED_KERNEL_MODULES",
"OVERRIDABLE",
),
(
HOST_MODULES_STUB_BAD,
REPOQUERY_F_STUB_GOOD,
("Insufficient space to run makecache", 1),
"PROBLEM_WITH_PACKAGE_REPO",
"ERROR",
),
(
HOST_MODULES_STUB_BAD,
"",
("", 0),
"NO_RHEL_KERNEL_MODULES_FOUND",
"ERROR",
),
(
HOST_MODULES_STUB_BAD,
"kernel-core-0:4.18.0-240.10.1.el8_3.x86_64\n" "kernel-core-0:4.19.0-240.10.1.el8_3.i486\n",
("", 0),
"CANNOT_COMPARE_PACKAGE_VERSIONS",
"ERROR",
),
),
)
@centos8
def test_ensure_compatibility_of_kmods_failure(
ensure_kernel_modules_compatibility_instance,
monkeypatch,
pretend_os,
caplog,
host_kmods,
repo_kmod_pkgs,
makecache_output,
error_id,
level,
):
monkeypatch.setattr(
ensure_kernel_modules_compatibility_instance, "_get_loaded_kmods", mock.Mock(return_value=host_kmods)
)
run_subprocess_mock = mock.Mock(
side_effect=run_subprocess_side_effect(
(("uname",), ("5.8.0-7642-generic\n", 0)),
(("yum", "makecache"), makecache_output),
(("repoquery", "-f"), (repo_kmod_pkgs, 0)),
(("repoquery", "-l"), (REPOQUERY_L_STUB_GOOD, 0)),
)
else:
ensure_kernel_modules_compatibility_instance.run()
assert_actions_result(ensure_kernel_modules_compatibility_instance, level="SUCCESS")
)
monkeypatch.setattr(
kernel_modules,
"run_subprocess",
value=run_subprocess_mock,
)

if should_be_in_logs:
assert should_be_in_logs in caplog.records[-1].message
if shouldnt_be_in_logs:
assert shouldnt_be_in_logs not in ensure_kernel_modules_compatibility_instance.result.diagnosis
ensure_kernel_modules_compatibility_instance.run()
assert_actions_result(ensure_kernel_modules_compatibility_instance, level=level, id=error_id)


@centos8
Expand All @@ -176,6 +222,7 @@ def test_ensure_compatibility_of_kmods_check_env_and_message(
run_subprocess_mock = mock.Mock(
side_effect=run_subprocess_side_effect(
(("uname",), ("5.8.0-7642-generic\n", 0)),
(("yum", "makecache"), ("", 0)),
(("repoquery", "-f"), (REPOQUERY_F_STUB_GOOD, 0)),
(("repoquery", "-l"), (REPOQUERY_L_STUB_GOOD, 0)),
)
Expand Down Expand Up @@ -246,6 +293,7 @@ def test_ensure_compatibility_of_kmods_excluded(
run_subprocess_mock = mock.Mock(
side_effect=run_subprocess_side_effect(
(("uname",), ("5.8.0-7642-generic\n", 0)),
(("yum", "makecache"), ("", 0)),
(("repoquery", "-f"), (REPOQUERY_F_STUB_GOOD, 0)),
(("repoquery", "-l"), (REPOQUERY_L_STUB_GOOD, 0)),
)
Expand Down Expand Up @@ -366,6 +414,10 @@ def test_get_rhel_supported_kmods(
("repoquery", "-l"),
(repoquery_l_stub, 0),
),
(
("yum", "makecache"),
("", 0),
),
)
)
monkeypatch.setattr(
Expand All @@ -386,6 +438,75 @@ def test_get_rhel_supported_kmods(
)


@pytest.mark.parametrize(
(
"repoquery_f_return",
"repoquery_l_return",
"makecache_return",
"exception",
"exception_msg",
),
(
(
(REPOQUERY_F_STUB_GOOD, 0),
(REPOQUERY_L_STUB_GOOD, 0),
("", 1),
kernel_modules.PackageRepositoryError,
"We were unable to download the repository metadata for (.*) to determine packages containing kernel modules. Can be caused by not enough disk space in /var/cache or too little memory. The yum output below may have a clue for what went wrong in this case:\n\n.*",
),
(
(REPOQUERY_F_STUB_BAD, 1),
(REPOQUERY_L_STUB_GOOD, 0),
("", 0),
kernel_modules.PackageRepositoryError,
"We were unable to query the repositories (.*) to determine packages containing kernel modules. Output from the failed repoquery command:\n\n.*",
),
(
("", 0),
(REPOQUERY_L_STUB_GOOD, 0),
("", 0),
kernel_modules.RHELKernelModuleNotFound,
"No packages containing kernel modules available in the enabled repositories (.*).",
),
),
)
@centos8
def test_get_rhel_supported_kmods_repoquery_fails(
ensure_kernel_modules_compatibility_instance,
monkeypatch,
pretend_os,
repoquery_f_return,
repoquery_l_return,
makecache_return,
exception,
exception_msg,
):
run_subprocess_mock = mock.Mock(
side_effect=run_subprocess_side_effect(
(
("repoquery", "-f"),
repoquery_f_return,
),
(
("repoquery", "-l"),
repoquery_l_return,
),
(
("yum", "makecache"),
makecache_return,
),
)
)
monkeypatch.setattr(
kernel_modules,
"run_subprocess",
value=run_subprocess_mock,
)

with pytest.raises(exception, match=exception_msg):
ensure_kernel_modules_compatibility_instance._get_rhel_supported_kmods()


@pytest.mark.parametrize(
("pkgs", "exp_res"),
(
Expand Down
2 changes: 1 addition & 1 deletion convert2rhel/unit_tests/pkghandler_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ def test_enable_call_yum_cmd_fail(self, package_set, global_system_info, caplog,
package_set.enable()

assert (
"Failed to install subscription-manager packages. See the above yum output for details."
"Failed to install subscription-manager packages. Check the yum output below for details"
in caplog.records[-1].message
)

Expand Down

0 comments on commit 8a7b98c

Please sign in to comment.