From 3d3dbf797a66cc69eafff32c4d927a82ae96948c Mon Sep 17 00:00:00 2001 From: Preston Watson Date: Wed, 7 Aug 2024 10:52:06 -0400 Subject: [PATCH] [RHELC-1329] Port pkghandler.preserve_only_rhel_kernel() to Action framework (#1250) * [RHELC-1329] Port pkghandler.preserve_only_rhel_kernel() to Action framework * Apply suggestions from code review Co-authored-by: Rodolfo Olivieri * Code review suggestions * Unit tests * Updated unit tests * Apply suggestions from code review Co-authored-by: Rodolfo Olivieri * Update title * Fix unit tests * Apply suggestions from code review Co-authored-by: Rodolfo Olivieri * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix unit tests * Remove preserve_only_rhel_kernel call from main * Apply suggestions from code review Co-authored-by: Rodolfo Olivieri * Update RHEL_KERNEL_INSTALLED info block * Update info log for kernel install * Fix unit tests * Add unit test for invalid grub2 entries --------- Co-authored-by: Rodolfo Olivieri Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../conversion/preserve_only_rhel_kernel.py | 258 +++++++++ convert2rhel/main.py | 2 - convert2rhel/pkghandler.py | 159 ------ .../preserve_only_rhel_kernel_test.py | 526 ++++++++++++++++++ convert2rhel/unit_tests/main_test.py | 3 - convert2rhel/unit_tests/pkghandler_test.py | 271 --------- 6 files changed, 784 insertions(+), 435 deletions(-) create mode 100644 convert2rhel/actions/conversion/preserve_only_rhel_kernel.py create mode 100644 convert2rhel/unit_tests/actions/conversion/preserve_only_rhel_kernel_test.py diff --git a/convert2rhel/actions/conversion/preserve_only_rhel_kernel.py b/convert2rhel/actions/conversion/preserve_only_rhel_kernel.py new file mode 100644 index 0000000000..60add7f5fe --- /dev/null +++ b/convert2rhel/actions/conversion/preserve_only_rhel_kernel.py @@ -0,0 +1,258 @@ +# Copyright(C) 2024 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +__metaclass__ = type + +import glob +import logging +import os +import re + +from convert2rhel import actions, pkghandler, pkgmanager, utils +from convert2rhel.systeminfo import system_info + + +loggerinst = logging.getLogger(__name__) + + +class InstallRhelKernel(actions.Action): + id = "INSTALL_RHEL_KERNEL" + dependencies = ("CONVERT_SYSTEM_PACKAGES",) + + def run(self): + """Install and update the RHEL kernel.""" + super(InstallRhelKernel, self).run() + loggerinst.task("Convert: Prepare kernel") + + 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 + + # Check if kernel with same version is already installed. + # Example output from yum and dnf: + # "Package kernel-4.18.0-193.el8.x86_64 is already installed." + already_installed = re.search(r" (.*?)(?: is)? already installed", output, re.MULTILINE) + if already_installed: + rhel_kernel_nevra = already_installed.group(1) + non_rhel_kernels = pkghandler.get_installed_pkgs_w_different_fingerprint( + system_info.fingerprints_rhel, "kernel" + ) + for non_rhel_kernel in non_rhel_kernels: + # We're comparing to NEVRA since that's what yum/dnf prints out + if rhel_kernel_nevra == pkghandler.get_pkg_nevra(non_rhel_kernel): + # If the installed kernel is from a third party (non-RHEL) and has the same NEVRA as the one available + # from RHEL repos, it's necessary to install an older version RHEL kernel and the third party one will + # be removed later in the conversion process. It's because yum/dnf is unable to reinstall a kernel. + info_message = ( + "Conflict of kernels: One of the installed kernels" + " has the same version as the latest RHEL kernel." + ) + loggerinst.info("\n%s" % info_message) + self.add_message( + level="INFO", + id="CONFLICT_OF_KERNELS", + title="Conflict of installed kernel versions", + description=info_message, + ) + pkghandler.handle_no_newer_rhel_kernel_available() + kernel_update_needed = True + + if kernel_update_needed: + pkghandler.update_rhel_kernel() + + +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_fingerprint( + system_info.fingerprints_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.", + ) + return + + loggerinst.info("RHEL kernel has been verified to be on the system.") + self.add_message( + level="INFO", + id="RHEL_KERNEL_INSTALL_VERIFIED", + title="RHEL kernel install verified", + description="The RHEL kernel has been verified to be on the system.", + ) + + +class FixInvalidGrub2Entries(actions.Action): + id = "FIX_INVALID_GRUB2_ENTRIES" + dependencies = ("KERNEL_PACKAGES_INSTALLATION",) + + def run(self): + """ + On systems derived from RHEL 8 and later, /etc/machine-id is being used to identify grub2 boot loader entries per + the Boot Loader Specification. + However, at the time of executing convert2rhel, the current machine-id can be different from the machine-id from the + time when the kernels were installed. If that happens: + - convert2rhel installs the RHEL kernel, but it's not set as default + - convert2rhel removes the original OS kernels, but for these the boot entries are not removed + The solution handled by this function is to remove the non-functioning boot entries upon the removal of the original + OS kernels, and set the RHEL kernel as default. + """ + super(FixInvalidGrub2Entries, self).run() + + if system_info.version.major < 8: + # Applicable only on systems derived from RHEL 8 and later, and systems using GRUB2 (s390x uses zipl) + return + + loggerinst.info("Fixing GRUB boot loader entries.") + + machine_id = utils.get_file_content("/etc/machine-id").strip() + boot_entries = glob.glob("/boot/loader/entries/*.conf") + for entry in boot_entries: + # The boot loader entries in /boot/loader/entries/-.conf + if machine_id not in os.path.basename(entry): + loggerinst.debug("Removing boot entry %s" % entry) + os.remove(entry) + + # Removing a boot entry that used to be the default makes grubby to choose a different entry as default, but we will + # call grub --set-default to set the new default on all the proper places, e.g. for grub2-editenv + output, ret_code = utils.run_subprocess(["/usr/sbin/grubby", "--default-kernel"], print_output=False) + if ret_code: + # Not setting the default entry shouldn't be a deal breaker and the reason to stop the conversions, grub should + # pick one entry in any case. + description = "Couldn't get the default GRUB2 boot loader entry:\n%s" % output + loggerinst.warning(description) + self.add_message( + level="WARNING", + id="UNABLE_TO_GET_GRUB2_BOOT_LOADER_ENTRY", + title="Unable to get the GRUB2 boot loader entry", + description=description, + ) + return + loggerinst.debug("Setting RHEL kernel %s as the default boot loader entry." % output.strip()) + output, ret_code = utils.run_subprocess(["/usr/sbin/grubby", "--set-default", output.strip()]) + if ret_code: + description = "Couldn't set the default GRUB2 boot loader entry:\n%s" % output + loggerinst.warning(description) + self.add_message( + level="WARNING", + id="UNABLE_TO_SET_GRUB2_BOOT_LOADER_ENTRY", + title="Unable to set the GRUB2 boot loader entry", + description=description, + ) + + +class FixDefaultKernel(actions.Action): + id = "FIX_DEFAULT_KERNEL" + dependencies = ("FIX_INVALID_GRUB2_ENTRIES",) + + def run(self): + """ + Systems converted from Oracle Linux or CentOS Linux may have leftover kernel-uek or kernel-plus in + /etc/sysconfig/kernel as DEFAULTKERNEL. + This function fixes that by replacing the DEFAULTKERNEL setting from kernel-uek or kernel-plus to kernel for + RHEL7 and kernel-core for RHEL8. + """ + super(FixDefaultKernel, self).run() + + loggerinst = logging.getLogger(__name__) + + loggerinst.info("Checking for incorrect boot kernel") + kernel_sys_cfg = utils.get_file_content("/etc/sysconfig/kernel") + + possible_kernels = ["kernel-uek", "kernel-plus"] + kernel_to_change = next( + iter(kernel for kernel in possible_kernels if kernel in kernel_sys_cfg), + None, + ) + if kernel_to_change: + description = "Detected leftover boot kernel, changing to RHEL kernel" + loggerinst.warning(description) + self.add_message( + level="WARNING", + id="LEFTOVER_BOOT_KERNEL_DETECTED", + title="Leftover boot kernel detected", + description=description, + ) + # need to change to "kernel" in rhel7 and "kernel-core" in rhel8 + new_kernel_str = "DEFAULTKERNEL=" + ("kernel" if system_info.version.major == 7 else "kernel-core") + + kernel_sys_cfg = kernel_sys_cfg.replace("DEFAULTKERNEL=" + kernel_to_change, new_kernel_str) + utils.store_content_to_file("/etc/sysconfig/kernel", kernel_sys_cfg) + loggerinst.info("Boot kernel %s was changed to %s" % (kernel_to_change, new_kernel_str)) + else: + loggerinst.debug("Boot kernel validated.") + + +class KernelPkgsInstall(actions.Action): + id = "KERNEL_PACKAGES_INSTALLATION" + dependencies = ("VERIFY_RHEL_KERNEL_INSTALLED",) + + def run(self): + """Install kernel packages and remove non-RHEL kernels.""" + super(KernelPkgsInstall, self).run() + + kernel_pkgs_to_install = self.remove_non_rhel_kernels() + if kernel_pkgs_to_install: + self.install_additional_rhel_kernel_pkgs(kernel_pkgs_to_install) + + def remove_non_rhel_kernels(self): + loggerinst.info("Searching for non-RHEL kernels ...") + non_rhel_kernels = pkghandler.get_installed_pkgs_w_different_fingerprint( + system_info.fingerprints_rhel, "kernel*" + ) + if not non_rhel_kernels: + loggerinst.info("None found.") + return None + + loggerinst.info("Removing non-RHEL kernels\n") + pkghandler.print_pkg_info(non_rhel_kernels) + pkgs_to_remove = [pkghandler.get_pkg_nvra(pkg) for pkg in non_rhel_kernels] + utils.remove_pkgs(pkgs_to_remove) + return non_rhel_kernels + + def install_additional_rhel_kernel_pkgs(self, additional_pkgs): + """Convert2rhel removes all non-RHEL kernel packages, including kernel-tools, kernel-headers, etc. This function + tries to install back all of these from RHEL repositories. + """ + # OL renames some of the kernel packages by adding "-uek" (Unbreakable + # Enterprise Kernel), e.g. kernel-uek-devel instead of kernel-devel. Such + # package names need to be mapped to the RHEL kernel package names to have + # them installed on the converted system. + ol_kernel_ext = "-uek" + pkg_names = [p.nevra.name.replace(ol_kernel_ext, "", 1) for p in additional_pkgs] + for name in set(pkg_names): + if name != "kernel": + loggerinst.info("Installing RHEL %s" % name) + pkgmanager.call_yum_cmd("install", args=[name]) diff --git a/convert2rhel/main.py b/convert2rhel/main.py index f9e59268db..a0658e5931 100644 --- a/convert2rhel/main.py +++ b/convert2rhel/main.py @@ -394,8 +394,6 @@ def post_ponr_changes(): def post_ponr_conversion(): """Perform main steps for system conversion.""" - loggerinst.task("Convert: Prepare kernel") - pkghandler.preserve_only_rhel_kernel() loggerinst.task("Convert: List remaining non-Red Hat packages") pkghandler.list_non_red_hat_pkgs_left() loggerinst.task("Convert: Configure the bootloader") diff --git a/convert2rhel/pkghandler.py b/convert2rhel/pkghandler.py index 51c361288d..bf561e3723 100644 --- a/convert2rhel/pkghandler.py +++ b/convert2rhel/pkghandler.py @@ -616,52 +616,6 @@ def install_gpg_keys(): loggerinst.info("GPG key %s imported successfuly.", gpg_key) -def preserve_only_rhel_kernel(): - kernel_update_needed = install_rhel_kernel() - verify_rhel_kernel_installed() - - kernel_pkgs_to_install = remove_non_rhel_kernels() - fix_invalid_grub2_entries() - fix_default_kernel() - - if kernel_pkgs_to_install: - install_additional_rhel_kernel_pkgs(kernel_pkgs_to_install) - if kernel_update_needed: - update_rhel_kernel() - - -def install_rhel_kernel(): - """Return boolean indicating whether it's needed to update the kernel - later on. - """ - loggerinst.info("Installing RHEL kernel ...") - output, ret_code = pkgmanager.call_yum_cmd(command="install", args=["kernel"]) - - if ret_code != 0: - loggerinst.critical("Error occured while attempting to install the RHEL kernel") - - # Check if kernel with same version is already installed. - # Example output from yum and dnf: - # "Package kernel-4.18.0-193.el8.x86_64 is already installed." - already_installed = re.search(r" (.*?)(?: is)? already installed", output, re.MULTILINE) - if already_installed: - rhel_kernel_nevra = already_installed.group(1) - non_rhel_kernels = get_installed_pkgs_w_different_fingerprint(system_info.fingerprints_rhel, "kernel") - for non_rhel_kernel in non_rhel_kernels: - # We're comparing to NEVRA since that's what yum/dnf prints out - if rhel_kernel_nevra == get_pkg_nevra(non_rhel_kernel): - # If the installed kernel is from a third party (non-RHEL) and has the same NEVRA as the one available - # from RHEL repos, it's necessary to install an older version RHEL kernel and the third party one will - # be removed later in the conversion process. It's because yum/dnf is unable to reinstall a kernel. - loggerinst.info( - "\nConflict of kernels: One of the installed kernels" - " has the same version as the latest RHEL kernel." - ) - handle_no_newer_rhel_kernel_available() - return True - return False - - 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). @@ -747,119 +701,6 @@ def replace_non_rhel_installed_kernel(version): loggerinst.info("\nRHEL %s installed.\n" % pkg) -def verify_rhel_kernel_installed(): - loggerinst.info("Verifying that RHEL kernel has been installed") - if not is_rhel_kernel_installed(): - loggerinst.critical( - "No RHEL kernel installed. Verify that the repository used for installing kernel contains RHEL packages." - ) - else: - loggerinst.info("RHEL kernel has been installed.") - - -def is_rhel_kernel_installed(): - installed_rhel_kernels = get_installed_pkgs_by_fingerprint(system_info.fingerprints_rhel, name="kernel") - return len(installed_rhel_kernels) > 0 - - -def remove_non_rhel_kernels(): - loggerinst.info("Searching for non-RHEL kernels ...") - non_rhel_kernels = get_installed_pkgs_w_different_fingerprint(system_info.fingerprints_rhel, "kernel*") - if non_rhel_kernels: - loggerinst.info("Removing non-RHEL kernels\n") - print_pkg_info(non_rhel_kernels) - utils.remove_pkgs( - pkgs_to_remove=[get_pkg_nvra(pkg) for pkg in non_rhel_kernels], - ) - else: - loggerinst.info("None found.") - return non_rhel_kernels - - -def fix_default_kernel(): - """ - Systems converted from Oracle Linux or CentOS Linux may have leftover kernel-uek or kernel-plus in - /etc/sysconfig/kernel as DEFAULTKERNEL. - This function fixes that by replacing the DEFAULTKERNEL setting from kernel-uek or kernel-plus to kernel for - RHEL7 and kernel-core for RHEL8 - """ - loggerinst = logging.getLogger(__name__) - - loggerinst.info("Checking for incorrect boot kernel") - kernel_sys_cfg = utils.get_file_content("/etc/sysconfig/kernel") - - possible_kernels = ["kernel-uek", "kernel-plus"] - kernel_to_change = next( - iter(kernel for kernel in possible_kernels if kernel in kernel_sys_cfg), - None, - ) - if kernel_to_change: - loggerinst.warning("Detected leftover boot kernel, changing to RHEL kernel") - # need to change to "kernel" in rhel7 and "kernel-core" in rhel8 - new_kernel_str = "DEFAULTKERNEL=" + ("kernel" if system_info.version.major == 7 else "kernel-core") - - kernel_sys_cfg = kernel_sys_cfg.replace("DEFAULTKERNEL=" + kernel_to_change, new_kernel_str) - utils.store_content_to_file("/etc/sysconfig/kernel", kernel_sys_cfg) - loggerinst.info("Boot kernel %s was changed to %s" % (kernel_to_change, new_kernel_str)) - else: - loggerinst.debug("Boot kernel validated.") - - -def fix_invalid_grub2_entries(): - """ - On systems derived from RHEL 8 and later, /etc/machine-id is being used to identify grub2 boot loader entries per - the Boot Loader Specification. - However, at the time of executing convert2rhel, the current machine-id can be different from the machine-id from the - time when the kernels were installed. If that happens: - - convert2rhel installs the RHEL kernel, but it's not set as default - - convert2rhel removes the original OS kernels, but for these the boot entries are not removed - The solution handled by this function is to remove the non-functioning boot entries upon the removal of the original - OS kernels, and set the RHEL kernel as default. - """ - if system_info.version.major < 8 or system_info.arch == "s390x": - # Applicable only on systems derived from RHEL 8 and later, and systems using GRUB2 (s390x uses zipl) - return - - loggerinst.info("Fixing GRUB boot loader entries.") - - machine_id = utils.get_file_content("/etc/machine-id") - boot_entries = glob.glob("/boot/loader/entries/*.conf") - for entry in boot_entries: - # The boot loader entries in /boot/loader/entries/-.conf - if machine_id.strip() not in os.path.basename(entry): - loggerinst.debug("Removing boot entry %s" % entry) - os.remove(entry) - - # Removing a boot entry that used to be the default makes grubby to choose a different entry as default, but we will - # call grub --set-default to set the new default on all the proper places, e.g. for grub2-editenv - output, ret_code = utils.run_subprocess(["/usr/sbin/grubby", "--default-kernel"], print_output=False) - if ret_code: - # Not setting the default entry shouldn't be a deal breaker and the reason to stop the conversions, grub should - # pick one entry in any case. - loggerinst.warning("Couldn't get the default GRUB2 boot loader entry:\n%s" % output) - return - loggerinst.debug("Setting RHEL kernel %s as the default boot loader entry." % output.strip()) - output, ret_code = utils.run_subprocess(["/usr/sbin/grubby", "--set-default", output.strip()]) - if ret_code: - loggerinst.warning("Couldn't set the default GRUB2 boot loader entry:\n%s" % output) - - -def install_additional_rhel_kernel_pkgs(additional_pkgs): - """Convert2rhel removes all non-RHEL kernel packages, including kernel-tools, kernel-headers, etc. This function - tries to install back all of these from RHEL repositories. - """ - # OL renames some of the kernel packages by adding "-uek" (Unbreakable - # Enterprise Kernel), e.g. kernel-uek-devel instead of kernel-devel. Such - # package names need to be mapped to the RHEL kernel package names to have - # them installed on the converted system. - ol_kernel_ext = "-uek" - pkg_names = [p.nevra.name.replace(ol_kernel_ext, "", 1) for p in additional_pkgs] - for name in set(pkg_names): - if name != "kernel": - loggerinst.info("Installing RHEL %s" % name) - pkgmanager.call_yum_cmd("install", args=[name]) - - def update_rhel_kernel(): """In the corner case where the original system kernel version is the same as the latest available RHEL kernel, convert2rhel needs to install older RHEL kernel version first. In this function, RHEL kernel is updated to the diff --git a/convert2rhel/unit_tests/actions/conversion/preserve_only_rhel_kernel_test.py b/convert2rhel/unit_tests/actions/conversion/preserve_only_rhel_kernel_test.py new file mode 100644 index 0000000000..eef2cb1d78 --- /dev/null +++ b/convert2rhel/unit_tests/actions/conversion/preserve_only_rhel_kernel_test.py @@ -0,0 +1,526 @@ +# Copyright(C) 2024 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +__metaclass__ = type +import glob +import os +import re + +import pytest +import six + +from convert2rhel import actions, pkghandler, pkgmanager, unit_tests, utils +from convert2rhel.actions.conversion import preserve_only_rhel_kernel +from convert2rhel.systeminfo import Version, system_info +from convert2rhel.unit_tests import ( + CallYumCmdMocked, + FormatPkgInfoMocked, + GetInstalledPkgsByFingerprintMocked, + GetInstalledPkgsWDifferentFingerprintMocked, + RemovePkgsMocked, + RunSubprocessMocked, + StoreContentToFileMocked, + create_pkg_information, +) +from convert2rhel.unit_tests.conftest import centos7, centos8 + + +six.add_move(six.MovedModule("mock", "mock", "unittest.mock")) +from six.moves import mock + + +@pytest.fixture +def install_rhel_kernel_instance(): + return preserve_only_rhel_kernel.InstallRhelKernel() + + +@pytest.fixture +def verify_rhel_kernel_installed_instance(): + return preserve_only_rhel_kernel.VerifyRhelKernelInstalled() + + +@pytest.fixture +def fix_invalid_grub2_entries_instance(): + return preserve_only_rhel_kernel.FixInvalidGrub2Entries() + + +@pytest.fixture +def fix_default_kernel_instance(): + return preserve_only_rhel_kernel.FixDefaultKernel() + + +@pytest.fixture +def kernel_packages_install_instance(): + return preserve_only_rhel_kernel.KernelPkgsInstall() + + +class TestInstallRhelKernel: + @pytest.mark.parametrize( + ( + "subprocess_output", + "is_only_rhel_kernel", + "expected", + ), + ( + ("Package kernel-3.10.0-1127.19.1.el7.x86_64 already installed and latest version", True, False), + ("Package kernel-3.10.0-1127.19.1.el7.x86_64 already installed and latest version", False, True), + ("Installed:\nkernel", False, False), + ), + ids=( + "Kernels collide and installed is already RHEL. Do not update.", + "Kernels collide and installed is not RHEL and older. Update.", + "Kernels do not collide. Install RHEL kernel and do not update.", + ), + ) + @centos7 + def test_install_rhel_kernel( + self, subprocess_output, is_only_rhel_kernel, expected, pretend_os, install_rhel_kernel_instance, monkeypatch + ): + update_rhel_kernel_mock = mock.Mock() + + monkeypatch.setattr( + utils, "run_subprocess", RunSubprocessMocked(return_string=subprocess_output, return_code=0) + ) + monkeypatch.setattr(pkghandler, "handle_no_newer_rhel_kernel_available", mock.Mock()) + monkeypatch.setattr(pkghandler, "update_rhel_kernel", value=update_rhel_kernel_mock) + + pkg_selection = "empty" if is_only_rhel_kernel else "kernels" + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_w_different_fingerprint", + GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection=pkg_selection), + ) + install_rhel_kernel_instance.run() + if expected: + update_rhel_kernel_mock.assert_called_once() + + @pytest.mark.parametrize( + ("subprocess_output",), + ( + ("Package kernel-2.6.32-754.33.1.el7.x86_64 already installed and latest version",), + ("Package kernel-4.18.0-193.el8.x86_64 is already installed.",), + ), + ) + @centos7 + def test_install_rhel_kernel_already_installed_regexp( + self, subprocess_output, pretend_os, monkeypatch, install_rhel_kernel_instance + ): + monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked(return_string=subprocess_output)) + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_w_different_fingerprint", + GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), + ) + + install_rhel_kernel_instance.run() + + assert pkghandler.get_installed_pkgs_w_different_fingerprint.call_count == 1 + + @centos7 + def test_install_rhel_kernel_error(self, pretend_os, install_rhel_kernel_instance, monkeypatch): + + monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked(return_code=1)) + install_rhel_kernel_instance.run() + unit_tests.assert_actions_result( + install_rhel_kernel_instance, + 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.", + ) + + @centos7 + def test_install_rhel_kernel_info_msg(self, pretend_os, install_rhel_kernel_instance, monkeypatch): + subprocess_output = "Package kernel-3.10.0-1127.19.1.el7.x86_64 already installed and latest version" + monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked(return_string=subprocess_output)) + monkeypatch.setattr(pkghandler, "handle_no_newer_rhel_kernel_available", mock.Mock()) + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_w_different_fingerprint", + GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), + ) + install_rhel_kernel_instance.run() + expected = set( + ( + actions.ActionMessage( + level="INFO", + id="CONFLICT_OF_KERNELS", + title="Conflict of installed kernel versions", + description="Conflict of kernels: One of the installed kernels has the same version as the latest RHEL kernel.", + diagnosis=None, + remediations=None, + ), + ) + ) + assert expected.issuperset(install_rhel_kernel_instance.messages) + assert expected.issubset(install_rhel_kernel_instance.messages) + + +class TestKernelPkgsInstall: + @pytest.mark.parametrize( + ("kernel_pkgs_to_install",), + ( + (["example_pkg"],), + ([],), + ), + ) + def test_kernel_pkgs_install(self, monkeypatch, kernel_packages_install_instance, kernel_pkgs_to_install): + install_additional_rhel_kernel_pkgs_mock = mock.Mock() + monkeypatch.setattr( + preserve_only_rhel_kernel.KernelPkgsInstall, + "install_additional_rhel_kernel_pkgs", + value=install_additional_rhel_kernel_pkgs_mock, + ) + monkeypatch.setattr( + preserve_only_rhel_kernel.KernelPkgsInstall, + "remove_non_rhel_kernels", + mock.Mock(return_value=kernel_pkgs_to_install), + ) + + kernel_packages_install_instance.run() + if kernel_pkgs_to_install: + install_additional_rhel_kernel_pkgs_mock.assert_called_once() + + def test_remove_non_rhel_kernels(self, monkeypatch, kernel_packages_install_instance): + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_w_different_fingerprint", + GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), + ) + monkeypatch.setattr(pkghandler, "format_pkg_info", FormatPkgInfoMocked()) + monkeypatch.setattr(utils, "remove_pkgs", RemovePkgsMocked()) + + removed_pkgs = kernel_packages_install_instance.remove_non_rhel_kernels() + + assert len(removed_pkgs) == 6 + assert [p.nevra.name for p in removed_pkgs] == [ + "kernel", + "kernel-uek", + "kernel-headers", + "kernel-uek-headers", + "kernel-firmware", + "kernel-uek-firmware", + ] + + def test_install_additional_rhel_kernel_pkgs(self, monkeypatch, kernel_packages_install_instance): + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_w_different_fingerprint", + GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), + ) + monkeypatch.setattr(pkghandler, "format_pkg_info", FormatPkgInfoMocked()) + monkeypatch.setattr(utils, "remove_pkgs", RemovePkgsMocked()) + monkeypatch.setattr(pkgmanager, "call_yum_cmd", CallYumCmdMocked()) + + removed_pkgs = kernel_packages_install_instance.remove_non_rhel_kernels() + kernel_packages_install_instance.install_additional_rhel_kernel_pkgs(removed_pkgs) + assert pkgmanager.call_yum_cmd.call_count == 2 + + +class TestVerifyRHELKernelInstalled: + def test_verify_rhel_kernel_installed(self, monkeypatch, verify_rhel_kernel_installed_instance): + monkeypatch.setattr( + pkghandler, + "get_installed_pkgs_by_fingerprint", + GetInstalledPkgsByFingerprintMocked(return_value=[create_pkg_information(name="kernel")]), + ) + verify_rhel_kernel_installed_instance.run() + expected = set( + ( + actions.ActionMessage( + level="INFO", + id="RHEL_KERNEL_INSTALL_VERIFIED", + title="RHEL kernel install verified", + description="The RHEL kernel has been verified to be on the system.", + diagnosis=None, + remediations=None, + ), + ) + ) + assert expected.issuperset(verify_rhel_kernel_installed_instance.messages) + assert expected.issubset(verify_rhel_kernel_installed_instance.messages) + + def test_verify_rhel_kernel_installed_not_installed(self, monkeypatch, verify_rhel_kernel_installed_instance): + monkeypatch.setattr(pkghandler, "get_installed_pkgs_by_fingerprint", mock.Mock(return_value=[])) + + verify_rhel_kernel_installed_instance.run() + unit_tests.assert_actions_result( + verify_rhel_kernel_installed_instance, + 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.", + ) + + +class TestFixInvalidGrub2Entries: + def test_fix_invalid_grub2_entries(self, caplog, monkeypatch, fix_invalid_grub2_entries_instance): + monkeypatch.setattr(system_info, "version", Version(8, 0)) + monkeypatch.setattr(system_info, "arch", "x86_64") + monkeypatch.setattr( + utils, + "get_file_content", + lambda x: "1b11755afe1341d7a86383ca4944c324\n", + ) + monkeypatch.setattr( + glob, + "glob", + lambda x: [ + "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-0-rescue.conf", + "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-4.18.0-193.28.1.el8_2.x86_64.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-0-rescue.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-4.18.0-193.el8.x86_64.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-5.4.17-2011.7.4.el8uek.x86_64.conf", + ], + ) + monkeypatch.setattr(os, "remove", mock.Mock()) + monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked()) + + fix_invalid_grub2_entries_instance.run() + + assert os.remove.call_count == 3 + assert utils.run_subprocess.call_count == 2 + + @centos8 + @pytest.mark.parametrize( + ("return_code_1", "return_code_2", "expected"), + ( + ( + 1, + 0, + set( + ( + actions.ActionMessage( + level="WARNING", + id="UNABLE_TO_GET_GRUB2_BOOT_LOADER_ENTRY", + title="Unable to get the GRUB2 boot loader entry", + description="Couldn't get the default GRUB2 boot loader entry:\nbootloader", + diagnosis=None, + remediations=None, + ), + ) + ), + ), + ( + 0, + 1, + set( + ( + actions.ActionMessage( + level="WARNING", + id="UNABLE_TO_SET_GRUB2_BOOT_LOADER_ENTRY", + title="Unable to set the GRUB2 boot loader entry", + description="Couldn't set the default GRUB2 boot loader entry:\nbootloader", + diagnosis=None, + remediations=None, + ), + ) + ), + ), + ), + ) + def test_fix_invalid_grub2_entries_messages( + self, monkeypatch, fix_invalid_grub2_entries_instance, return_code_1, return_code_2, expected, pretend_os + ): + monkeypatch.setattr(os, "remove", mock.Mock()) + monkeypatch.setattr( + glob, + "glob", + lambda x: [ + "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-0-rescue.conf", + "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-4.18.0-193.28.1.el8_2.x86_64.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-0-rescue.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-4.18.0-193.el8.x86_64.conf", + "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-5.4.17-2011.7.4.el8uek.x86_64.conf", + ], + ) + monkeypatch.setattr( + utils, + "get_file_content", + lambda x: "1b11755afe1341d7a86383ca4944c324\n", + ) + run_subprocess_mocked = RunSubprocessMocked( + side_effect=unit_tests.run_subprocess_side_effect( + ( + ( + "/usr/sbin/grubby", + "--default-kernel", + ), + ( + "bootloader", + return_code_1, + ), + ), + ( + ( + "/usr/sbin/grubby", + "--set-default", + "bootloader", + ), + ( + "bootloader", + return_code_2, + ), + ), + ), + ) + + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mocked, + ) + + fix_invalid_grub2_entries_instance.run() + assert expected.issuperset(fix_invalid_grub2_entries_instance.messages) + assert expected.issubset(fix_invalid_grub2_entries_instance.messages) + + @pytest.mark.parametrize( + ("version", "expected"), + ( + (Version(7, 9), False), + (Version(8, 9), True), + ), + ) + def test_fix_invalid_grub2_entries_execution( + self, monkeypatch, fix_invalid_grub2_entries_instance, caplog, version, expected + ): + + monkeypatch.setattr(system_info, "version", version) + run_subprocess_mocked = RunSubprocessMocked( + side_effect=unit_tests.run_subprocess_side_effect( + ( + ( + "/usr/sbin/grubby", + "--default-kernel", + ), + ( + "bootloader", + 0, + ), + ), + ( + ( + "/usr/sbin/grubby", + "--set-default", + "bootloader", + ), + ( + "bootloader", + 0, + ), + ), + ), + ) + + monkeypatch.setattr( + utils, + "run_subprocess", + value=run_subprocess_mocked, + ) + fix_invalid_grub2_entries_instance.run() + if expected: + assert "Fixing GRUB boot loader" in caplog.text + else: + assert "Fixing GRUB boot loader" not in caplog.text + + +class TestFixDefaultKernel: + @pytest.mark.parametrize( + ("system_name", "version", "old_kernel", "new_kernel", "not_default_kernels"), + ( + ( + "Oracle Linux Server release 7.9", + Version(7, 9), + "kernel-uek", + "kernel", + ("kernel-uek", "kernel-core"), + ), + ( + "Oracle Linux Server release 8.1", + Version(8, 1), + "kernel-uek", + "kernel-core", + ("kernel-uek", "kernel"), + ), + ( + "CentOS Plus Linux Server release 7.9", + Version(7, 9), + "kernel-plus", + "kernel", + ("kernel-plus",), + ), + ), + ) + def test_fix_default_kernel_converting_success( + self, + system_name, + version, + old_kernel, + new_kernel, + not_default_kernels, + caplog, + monkeypatch, + fix_default_kernel_instance, + ): + monkeypatch.setattr(system_info, "name", system_name) + monkeypatch.setattr(system_info, "arch", "x86_64") + monkeypatch.setattr(system_info, "version", version) + monkeypatch.setattr( + utils, + "get_file_content", + lambda _: "UPDATEDEFAULT=yes\nDEFAULTKERNEL=%s\n" % old_kernel, + ) + monkeypatch.setattr(utils, "store_content_to_file", StoreContentToFileMocked()) + + fix_default_kernel_instance.run() + + warning_msgs = [r for r in caplog.records if r.levelname == "WARNING"] + assert warning_msgs + assert "Detected leftover boot kernel, changing to RHEL kernel" in warning_msgs[-1].message + + (filename, content), _ = utils.store_content_to_file.call_args + kernel_file_lines = content.splitlines() + + assert "/etc/sysconfig/kernel" == filename + assert "DEFAULTKERNEL=%s" % new_kernel in kernel_file_lines + + for kernel_name in not_default_kernels: + assert "DEFAULTKERNEL=%s" % kernel_name not in kernel_file_lines + + @centos7 + def test_fix_default_kernel_with_no_incorrect_kernel( + self, caplog, monkeypatch, fix_default_kernel_instance, pretend_os + ): + monkeypatch.setattr( + utils, + "get_file_content", + lambda _: "UPDATEDEFAULT=yes\nDEFAULTKERNEL=kernel\n", + ) + monkeypatch.setattr(utils, "store_content_to_file", StoreContentToFileMocked()) + + fix_default_kernel_instance.run() + + info_records = [m for m in caplog.records if m.levelname == "INFO"] + warning_records = [m for m in caplog.records if m.levelname == "WARNING"] + debug_records = [m for m in caplog.records if m.levelname == "DEBUG"] + + assert not warning_records + assert any("Boot kernel validated." in r.message for r in debug_records) + + for record in info_records: + assert not re.search("Boot kernel [^ ]\\+ was changed to [^ ]\\+", record.message) diff --git a/convert2rhel/unit_tests/main_test.py b/convert2rhel/unit_tests/main_test.py index 8a356abf4e..541acbc15a 100644 --- a/convert2rhel/unit_tests/main_test.py +++ b/convert2rhel/unit_tests/main_test.py @@ -207,13 +207,11 @@ def test_show_eula_nonexisting_file(self, caplog, monkeypatch, tmpdir): def test_post_ponr_conversion(monkeypatch): - perserve_only_rhel_kernel_mock = mock.Mock() list_non_red_hat_pkgs_left_mock = mock.Mock() post_ponr_set_efi_configuration_mock = mock.Mock() yum_conf_patch_mock = mock.Mock() lock_releasever_in_rhel_repositories_mock = mock.Mock() - monkeypatch.setattr(pkghandler, "preserve_only_rhel_kernel", perserve_only_rhel_kernel_mock) monkeypatch.setattr(pkghandler, "list_non_red_hat_pkgs_left", list_non_red_hat_pkgs_left_mock) monkeypatch.setattr(grub, "post_ponr_set_efi_configuration", post_ponr_set_efi_configuration_mock) monkeypatch.setattr(redhatrelease.YumConf, "patch", yum_conf_patch_mock) @@ -221,7 +219,6 @@ def test_post_ponr_conversion(monkeypatch): main.post_ponr_conversion() - assert perserve_only_rhel_kernel_mock.call_count == 1 assert list_non_red_hat_pkgs_left_mock.call_count == 1 assert post_ponr_set_efi_configuration_mock.call_count == 1 assert yum_conf_patch_mock.call_count == 1 diff --git a/convert2rhel/unit_tests/pkghandler_test.py b/convert2rhel/unit_tests/pkghandler_test.py index e127851ddb..a3ef0e3719 100644 --- a/convert2rhel/unit_tests/pkghandler_test.py +++ b/convert2rhel/unit_tests/pkghandler_test.py @@ -231,29 +231,6 @@ def test_get_rpm_header_failure(self, monkeypatch): pkghandler.get_rpm_header(unknown_pkg) -class TestPreserveOnlyRHELKernel: - @centos7 - def test_preserve_only_rhel_kernel(self, pretend_os, monkeypatch): - monkeypatch.setattr(pkghandler, "install_rhel_kernel", lambda: True) - monkeypatch.setattr(pkghandler, "fix_invalid_grub2_entries", lambda: None) - monkeypatch.setattr(pkghandler, "remove_non_rhel_kernels", mock.Mock(return_value=[])) - monkeypatch.setattr(pkghandler, "install_gpg_keys", mock.Mock()) - monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked()) - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_by_fingerprint", - GetInstalledPkgsByFingerprintMocked(return_value=[create_pkg_information(name="kernel")]), - ) - monkeypatch.setattr(system_info, "name", "CentOS7") - monkeypatch.setattr(system_info, "arch", "x86_64") - monkeypatch.setattr(utils, "store_content_to_file", StoreContentToFileMocked()) - - pkghandler.preserve_only_rhel_kernel() - - assert utils.run_subprocess.cmd == ["yum", "update", "-y", "--releasever=7Server", "kernel"] - assert pkghandler.get_installed_pkgs_by_fingerprint.call_count == 1 - - class TestGetKernelAvailability: @pytest.mark.parametrize( ("subprocess_output", "expected_installed", "expected_available"), @@ -385,158 +362,6 @@ def test_get_kernel(self): assert kernel_version == ["4.7.4-200.fc24", "4.7.4-200.fc24"] -class TestVerifyRHELKernelInstalled: - def test_verify_rhel_kernel_installed(self, monkeypatch): - monkeypatch.setattr(pkghandler, "is_rhel_kernel_installed", lambda: True) - - pkghandler.verify_rhel_kernel_installed() - - def test_verify_rhel_kernel_installed_not_installed(self, monkeypatch): - monkeypatch.setattr(pkghandler, "is_rhel_kernel_installed", lambda: False) - - with pytest.raises(SystemExit): - pkghandler.verify_rhel_kernel_installed() - - -class TestIsRHELKernelInstalled: - def test_is_rhel_kernel_installed_no(self, monkeypatch): - monkeypatch.setattr(pkghandler, "get_installed_pkgs_by_fingerprint", lambda x, name: []) - - assert not pkghandler.is_rhel_kernel_installed() - - def test_is_rhel_kernel_installed_yes(self, monkeypatch): - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_by_fingerprint", - GetInstalledPkgsByFingerprintMocked(return_value=[create_pkg_information(name="kernel")]), - ) - - assert pkghandler.is_rhel_kernel_installed() - - -class TestFixInvalidGrub2Entries: - @pytest.mark.parametrize( - ("version", "arch"), - ( - (Version(7, 0), "x86_64"), - (Version(8, 0), "s390x"), - ), - ) - def test_fix_invalid_grub2_entries_not_applicable(self, version, arch, caplog, monkeypatch): - monkeypatch.setattr(system_info, "version", version) - monkeypatch.setattr(system_info, "arch", arch) - - pkghandler.fix_invalid_grub2_entries() - - assert not [r for r in caplog.records if r.levelname != "DEBUG"] - - def test_fix_invalid_grub2_entries(self, caplog, monkeypatch): - monkeypatch.setattr(system_info, "version", Version(8, 0)) - monkeypatch.setattr(system_info, "arch", "x86_64") - monkeypatch.setattr( - utils, - "get_file_content", - lambda x: "1b11755afe1341d7a86383ca4944c324\n", - ) - monkeypatch.setattr( - glob, - "glob", - lambda x: [ - "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-0-rescue.conf", - "/boot/loader/entries/1b11755afe1341d7a86383ca4944c324-4.18.0-193.28.1.el8_2.x86_64.conf", - "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-0-rescue.conf", - "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-4.18.0-193.el8.x86_64.conf", - "/boot/loader/entries/b5aebfb91bff486bb9d44ba85e4ae683-5.4.17-2011.7.4.el8uek.x86_64.conf", - ], - ) - monkeypatch.setattr(os, "remove", mock.Mock()) - monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked()) - - pkghandler.fix_invalid_grub2_entries() - - assert os.remove.call_count == 3 - assert utils.run_subprocess.call_count == 2 - - -class TestFixDefaultKernel: - @pytest.mark.parametrize( - ("system_name", "version", "old_kernel", "new_kernel", "not_default_kernels"), - ( - ( - "Oracle Linux Server release 7.9", - Version(7, 9), - "kernel-uek", - "kernel", - ("kernel-uek", "kernel-core"), - ), - ( - "Oracle Linux Server release 8.1", - Version(8, 1), - "kernel-uek", - "kernel-core", - ("kernel-uek", "kernel"), - ), - ( - "CentOS Plus Linux Server release 7.9", - Version(7, 9), - "kernel-plus", - "kernel", - ("kernel-plus",), - ), - ), - ) - def test_fix_default_kernel_converting_success( - self, system_name, version, old_kernel, new_kernel, not_default_kernels, caplog, monkeypatch - ): - monkeypatch.setattr(system_info, "name", system_name) - monkeypatch.setattr(system_info, "arch", "x86_64") - monkeypatch.setattr(system_info, "version", version) - monkeypatch.setattr( - utils, - "get_file_content", - lambda _: "UPDATEDEFAULT=yes\nDEFAULTKERNEL=%s\n" % old_kernel, - ) - monkeypatch.setattr(utils, "store_content_to_file", StoreContentToFileMocked()) - - pkghandler.fix_default_kernel() - - warning_msgs = [r for r in caplog.records if r.levelname == "WARNING"] - assert warning_msgs - assert "Detected leftover boot kernel, changing to RHEL kernel" in warning_msgs[-1].message - - (filename, content), _dummy = utils.store_content_to_file.call_args - kernel_file_lines = content.splitlines() - - assert "/etc/sysconfig/kernel" == filename - assert "DEFAULTKERNEL=%s" % new_kernel in kernel_file_lines - - for kernel_name in not_default_kernels: - assert "DEFAULTKERNEL=%s" % kernel_name not in kernel_file_lines - - def test_fix_default_kernel_with_no_incorrect_kernel(self, caplog, monkeypatch): - monkeypatch.setattr(system_info, "name", "CentOS Plus Linux Server release 7.9") - monkeypatch.setattr(system_info, "arch", "x86_64") - monkeypatch.setattr(system_info, "version", Version(7, 9)) - monkeypatch.setattr( - utils, - "get_file_content", - lambda _: "UPDATEDEFAULT=yes\nDEFAULTKERNEL=kernel\n", - ) - monkeypatch.setattr(utils, "store_content_to_file", StoreContentToFileMocked()) - - pkghandler.fix_default_kernel() - - info_records = [m for m in caplog.records if m.levelname == "INFO"] - warning_records = [m for m in caplog.records if m.levelname == "WARNING"] - debug_records = [m for m in caplog.records if m.levelname == "DEBUG"] - - assert not warning_records - assert any("Boot kernel validated." in r.message for r in debug_records) - - for record in info_records: - assert not re.search("Boot kernel [^ ]\\+ was changed to [^ ]\\+", record.message) - - @pytest.mark.parametrize( ("version1", "version2", "expected"), ( @@ -1669,102 +1494,6 @@ def test_list_non_red_hat_pkgs_left(monkeypatch): assert pkghandler.format_pkg_info.call_args[0][0][0].nevra.name == "pkg2" -@pytest.mark.parametrize( - ( - "subprocess_output", - "is_only_rhel_kernel", - "expected", - ), - ( - ("Package kernel-3.10.0-1127.19.1.el7.x86_64 already installed and latest version", True, False), - ("Package kernel-3.10.0-1127.19.1.el7.x86_64 already installed and latest version", False, True), - ("Installed:\nkernel", False, False), - ), - ids=( - "Kernels collide and installed is already RHEL. Do not update.", - "Kernels collide and installed is not RHEL and older. Update.", - "Kernels do not collide. Install RHEL kernel and do not update.", - ), -) -@centos7 -def test_install_rhel_kernel(subprocess_output, is_only_rhel_kernel, expected, pretend_os, monkeypatch): - monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked(return_string=subprocess_output)) - monkeypatch.setattr(pkghandler, "handle_no_newer_rhel_kernel_available", mock.Mock()) - - if is_only_rhel_kernel: - pkg_selection = "empty" - else: - pkg_selection = "kernels" - - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_w_different_fingerprint", - GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection=pkg_selection), - ) - - update_kernel = pkghandler.install_rhel_kernel() - - assert update_kernel is expected - - -@pytest.mark.parametrize( - ("subprocess_output",), - ( - ("Package kernel-2.6.32-754.33.1.el7.x86_64 already installed and latest version",), - ("Package kernel-4.18.0-193.el8.x86_64 is already installed.",), - ), -) -@centos7 -def test_install_rhel_kernel_already_installed_regexp(subprocess_output, pretend_os, monkeypatch): - monkeypatch.setattr(utils, "run_subprocess", RunSubprocessMocked(return_string=subprocess_output)) - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_w_different_fingerprint", - GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), - ) - - pkghandler.install_rhel_kernel() - - assert pkghandler.get_installed_pkgs_w_different_fingerprint.call_count == 1 - - -def test_remove_non_rhel_kernels(monkeypatch): - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_w_different_fingerprint", - GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), - ) - monkeypatch.setattr(pkghandler, "format_pkg_info", FormatPkgInfoMocked()) - monkeypatch.setattr(utils, "remove_pkgs", RemovePkgsMocked()) - - removed_pkgs = pkghandler.remove_non_rhel_kernels() - - assert len(removed_pkgs) == 6 - assert [p.nevra.name for p in removed_pkgs] == [ - "kernel", - "kernel-uek", - "kernel-headers", - "kernel-uek-headers", - "kernel-firmware", - "kernel-uek-firmware", - ] - - -def test_install_additional_rhel_kernel_pkgs(monkeypatch): - monkeypatch.setattr( - pkghandler, - "get_installed_pkgs_w_different_fingerprint", - GetInstalledPkgsWDifferentFingerprintMocked(pkg_selection="kernels"), - ) - monkeypatch.setattr(pkghandler, "format_pkg_info", FormatPkgInfoMocked()) - monkeypatch.setattr(utils, "remove_pkgs", RemovePkgsMocked()) - monkeypatch.setattr(pkgmanager, "call_yum_cmd", CallYumCmdMocked()) - - removed_pkgs = pkghandler.remove_non_rhel_kernels() - pkghandler.install_additional_rhel_kernel_pkgs(removed_pkgs) - assert pkgmanager.call_yum_cmd.call_count == 2 - - @pytest.mark.parametrize( ("package_name", "subprocess_output", "expected", "expected_command"), (