Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RHELC-1717] Fix the latest RHEL kernel not set as default on CentOS Stream 9 #1403

Merged
merged 4 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

class ListNonRedHatPkgsLeft(actions.Action):
id = "LIST_NON_RED_HAT_PKGS_LEFT"
dependencies = ("KERNEL_PACKAGES_INSTALLATION",)
dependencies = ("REMOVE_NON_RHEL_KERNELS",)

def run(self):
"""List all the packages that have not been replaced by the
Expand Down
133 changes: 25 additions & 108 deletions convert2rhel/actions/conversion/preserve_only_rhel_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,11 @@

import glob
import os
import re

from convert2rhel import actions, logger, pkghandler, pkgmanager, utils
from convert2rhel.systeminfo import system_info


_kernel_update_needed = None

loggerinst = logger.root_logger.getChild(__name__)


Expand All @@ -33,113 +30,32 @@ class InstallRhelKernel(actions.Action):
dependencies = ("CONVERT_SYSTEM_PACKAGES",)

def run(self):
"""Install and update the RHEL kernel."""
super(InstallRhelKernel, self).run()
loggerinst.task("Prepare kernel")

# Solution for RHELC-1707
# Update is needed in the UpdateKernel action
global _kernel_update_needed

loggerinst.info("Installing RHEL kernel ...")
output, ret_code = pkgmanager.call_yum_cmd(command="install", args=["kernel"])
_kernel_update_needed = False

if ret_code != 0:
self.set_result(
level="ERROR",
id="FAILED_TO_INSTALL_RHEL_KERNEL",
title="Failed to install RHEL kernel",
description="There was an error while attempting to install the RHEL kernel from yum.",
remediations="Please check that you can access the repositories that provide the RHEL kernel.",
)
return
"""Ensure that the RHEL kernel is installed.

# Check which of the kernel versions are already installed.
# Example output from yum and dnf:
# "Package kernel-4.18.0-193.el8.x86_64 is already installed."
# When calling install, yum/dnf essentially reports all the already installed versions.
already_installed = re.findall(r" (.*?)(?: is)? already installed", output, re.MULTILINE)
The RHEL kernel might have not been installed during the main conversion transaction in case the installed
non-RHEL kernel(s) conflicted with the available RHEL kernels.
"""
super(InstallRhelKernel, self).run()
loggerinst.info("Verifying that RHEL kernel has been installed")

# Mitigates an edge case, when the kernel meta-package might not be installed prior to the conversion
# with only kernel-core being on the system.
# During that scenario the kernel meta package gets actually installed leaving the already_installed unmatched
if not already_installed:
return
rhel_kernels = pkghandler.get_installed_pkgs_by_key_id(system_info.key_ids_rhel, name="kernel")

# Get list of kernel pkgs not signed by Red Hat
non_rhel_kernels_pkg_info = pkghandler.get_installed_pkgs_w_different_key_id(system_info.key_ids_rhel, "kernel")
# Extract the NEVRA from the package object to a list
non_rhel_kernels = [pkghandler.get_pkg_nevra(kernel) for kernel in non_rhel_kernels_pkg_info]
rhel_kernels = [kernel for kernel in already_installed if kernel not in non_rhel_kernels]

# There is no RHEL kernel installed on the system at this point.
# Generally that would mean, that there is either only one kernel
# package installed on the system by the time of the conversion.
# Or none of the kernel packages installed is possible to be handled
# during the main transaction.
if not rhel_kernels:
info_message = (
"Conflict of kernels: The running kernel has the same version as the latest RHEL kernel.\n"
"The kernel package could not be replaced during the main transaction.\n"
"We will try to install a lower version of the package,\n"
"remove the conflicting kernel and then update to the latest security patched version."
)
loggerinst.info("\n{}".format(info_message))
pkghandler.handle_no_newer_rhel_kernel_available()
_kernel_update_needed = True

# In this case all kernel packages were already replaced during the main transaction.
# Having elif here to prevent breaking the action. Otherwise, when the first condition applies,
# and the pkghandler.handle_no_newer_rhel_kernel_available() we can assume the Action finished.
elif not non_rhel_kernels:
return

# At this point we need to decide if the highest package version in the rhel_kernels list
# is higher than the highest package version in the non_rhel_kernels list
else:
latest_installed_non_rhel_kernel = pkghandler.get_highest_package_version(
("non-RHEL kernel", non_rhel_kernels)
)
loggerinst.debug(
"Latest installed kernel version from the original vendor: {}".format(latest_installed_non_rhel_kernel)
"RHEL kernel has not been installed in the main conversion transaction."
"We are about to handle its installation separately."
)
latest_installed_rhel_kernel = pkghandler.get_highest_package_version(("RHEL kernel", rhel_kernels))
loggerinst.debug("Latest installed RHEL kernel version: {}".format(latest_installed_rhel_kernel))
is_rhel_kernel_higher = pkghandler.compare_package_versions(
latest_installed_rhel_kernel, latest_installed_non_rhel_kernel
)

# If the highest version of the RHEL kernel package installed at this point is indeed
# higher than any non-RHEL package, we don't need to do anything else.
if is_rhel_kernel_higher == 1:
return

# This also contains a scenario, where the running non-RHEL kernel is of a higher version
# than the latest one available in the RHEL repositories.
# That might happen and happened before, when the original vendor patches the package
# with a higher release number.
pkghandler.handle_no_newer_rhel_kernel_available()
_kernel_update_needed = True


class VerifyRhelKernelInstalled(actions.Action):
id = "VERIFY_RHEL_KERNEL_INSTALLED"
dependencies = ("INSTALL_RHEL_KERNEL",)

def run(self):
"""Verify that the RHEL kernel has been successfully installed and raise an ERROR if not"""
super(VerifyRhelKernelInstalled, self).run()

loggerinst.info("Verifying that RHEL kernel has been installed")
installed_rhel_kernels = pkghandler.get_installed_pkgs_by_key_id(system_info.key_ids_rhel, name="kernel")
if len(installed_rhel_kernels) <= 0:
self.set_result(
level="ERROR",
id="NO_RHEL_KERNEL_INSTALLED",
title="No RHEL kernel installed",
description="There is no RHEL kernel installed on the system.",
remediations="Verify that the repository used for installing kernel contains RHEL packages.",
remediations="Verify that the repository used for installing kernel contains RHEL packages and install"
" the kernel manually.",
)
return

Expand All @@ -154,7 +70,7 @@ def run(self):

class FixInvalidGrub2Entries(actions.Action):
id = "FIX_INVALID_GRUB2_ENTRIES"
dependencies = ("KERNEL_PACKAGES_INSTALLATION",)
dependencies = ("REMOVE_NON_RHEL_KERNELS",)

def run(self):
"""
Expand Down Expand Up @@ -252,11 +168,11 @@ def run(self):


class KernelPkgsInstall(actions.Action):
id = "KERNEL_PACKAGES_INSTALLATION"
dependencies = ("VERIFY_RHEL_KERNEL_INSTALLED",)
id = "REMOVE_NON_RHEL_KERNELS"
dependencies = ("INSTALL_RHEL_KERNEL",)

def run(self):
"""Install kernel packages and remove non-RHEL kernels."""
"""Remove non-RHEL kernels."""
super(KernelPkgsInstall, self).run()

kernel_pkgs_to_install = self.remove_non_rhel_kernels()
Expand Down Expand Up @@ -294,16 +210,17 @@ def install_additional_rhel_kernel_pkgs(self, additional_pkgs):

class UpdateKernel(actions.Action):
id = "UPDATE_KERNEL"
dependencies = ("FIX_DEFAULT_KERNEL",)
dependencies = ("REMOVE_NON_RHEL_KERNELS",)

def run(self):
"""Ensure that the latest RHEL kernel is installed.

The RHEL kernel we've installed during the main conversion transaction is not up-to-date in case
the latest available RHEL kernel conflicted with the installed non-RHEL kernels.

At this point though all non-RHEL kernels are already removed so the latest RHEL kernel won't conflict with
them anymore.
"""
super(UpdateKernel, self).run()
# Solution for RHELC-1707
# This variable is set in the InstallRhelKernel action
global _kernel_update_needed

if _kernel_update_needed:
# Note: Info message is in the function
pkghandler.update_rhel_kernel()
else:
loggerinst.info("RHEL kernel already present in latest version. Update not needed.\n")
pkghandler.update_rhel_kernel()
16 changes: 8 additions & 8 deletions convert2rhel/pkghandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,19 +594,19 @@ def install_gpg_keys():


def handle_no_newer_rhel_kernel_available():
"""Handle cases when the installed third party (non-RHEL) kernel has the
same version as (or newer than) the RHEL one available in the RHEL repo(s).
"""Handle cases when the installed non-RHEL kernel has the
same version as (or newer than) the latest RHEL kernel available in the RHEL repo(s).
"""
installed, available = get_kernel_availability()
to_install = [kernel for kernel in available if kernel not in installed]
installed, all_available = get_kernel_availability()
available_to_install = [kernel for kernel in all_available if kernel not in installed]

if not to_install:
# All the available RHEL kernel versions are already installed
if not available_to_install:
# All the available RHEL kernels are already installed
if len(installed) > 1:
# There's more than one installed non-RHEL kernel. We'll remove one
# of them - the one that has the same version as the available RHEL
# kernel
older = available[-1]
older = all_available[-1]
utils.remove_pkgs(pkgs_to_remove=["kernel-{}".format(older)])
pkgmanager.call_yum_cmd(command="install", args=["kernel-{}".format(older)])
else:
Expand All @@ -615,7 +615,7 @@ def handle_no_newer_rhel_kernel_available():
return

# Install the latest out of the available non-clashing RHEL kernels
pkgmanager.call_yum_cmd(command="install", args=["kernel-{}".format(to_install[-1])])
pkgmanager.call_yum_cmd(command="install", args=["kernel-{}".format(available_to_install[-1])])


def get_kernel_availability():
Expand Down
Loading
Loading