From 2c3dcc5bb5de4d3f83902bb8cb7f0fe1fa9a55b9 Mon Sep 17 00:00:00 2001 From: wang-guangge Date: Tue, 19 Dec 2023 21:03:48 +0800 Subject: [PATCH] support restore default boot kernel if kabi check failed --- hotpatch/hotupgrade.py | 19 ++++++++----- hotpatch/upgrade_en.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/hotpatch/hotupgrade.py b/hotpatch/hotupgrade.py index 37497cf..4e1ea96 100644 --- a/hotpatch/hotupgrade.py +++ b/hotpatch/hotupgrade.py @@ -43,6 +43,7 @@ class HotupgradeCommand(dnf.cli.Command): is_need_accept_kernel_hp = False is_kernel_coldpatch_installed = False kernel_coldpatch = '' + previous_boot_kernel = None @staticmethod def set_argparser(parser): @@ -80,6 +81,9 @@ class HotupgradeCommand(dnf.cli.Command): commands._checkEnabledRepo(self.base) def run(self): + self.upgrade_en = UpgradeEnhanceCommand(self.cli) + self.previous_boot_kernel = self.upgrade_en.get_default_boot_kernel() + if self.opts.pkg_specs: self.hp_list = self.opts.pkg_specs elif self.opts.cves or self.opts.advisory: @@ -181,20 +185,21 @@ class HotupgradeCommand(dnf.cli.Command): Returns: bool: if hotupgrade task success """ - upgrade_en = UpgradeEnhanceCommand(self.cli) - is_task_success = True if self.is_kernel_coldpatch_installed: if not is_all_kernel_hp_actived: logger.info(_('Gonna remove %s due to some kernel hotpatch activation failed.'), self.kernel_coldpatch) - upgrade_en.remove_rpm(str(self.kernel_coldpatch)) + self.upgrade_en.rebuild_rpm_db() + self.upgrade_en.remove_rpm(str(self.kernel_coldpatch)) + self.upgrade_en.restore_default_boot_kernel(self.previous_boot_kernel) self.is_need_accept_kernel_hp = False # process kabi check - elif not upgrade_en.kabi_check(str(self.kernel_coldpatch)) and not self.opts.force: + elif not self.upgrade_en.kabi_check(str(self.kernel_coldpatch)) and not self.opts.force: logger.info(_('Gonna remove %s due to Kabi check failed.'), self.kernel_coldpatch) # rebuild rpm database for processing kernel rpm remove operation - upgrade_en.rebuild_rpm_db() - upgrade_en.remove_rpm(str(self.kernel_coldpatch)) + self.upgrade_en.rebuild_rpm_db() + self.upgrade_en.remove_rpm(str(self.kernel_coldpatch)) + self.upgrade_en.restore_default_boot_kernel(self.previous_boot_kernel) self.is_need_accept_kernel_hp = True if target_remove_hp: @@ -203,7 +208,7 @@ class HotupgradeCommand(dnf.cli.Command): # it indicates that the hotupgrade task failed is_task_success &= False for hotpatch in target_remove_hp: - upgrade_en.remove_rpm(hotpatch) + self.upgrade_en.remove_rpm(hotpatch) return is_task_success def _apply_hp(self, hp_full_name): diff --git a/hotpatch/upgrade_en.py b/hotpatch/upgrade_en.py index 94ba4da..0bd78cc 100644 --- a/hotpatch/upgrade_en.py +++ b/hotpatch/upgrade_en.py @@ -12,6 +12,7 @@ # ******************************************************************************/ import gzip import subprocess +from typing import Optional import dnf from dnf.cli import commands @@ -36,6 +37,7 @@ def cmd_output(cmd): @dnf.plugin.register_command class UpgradeEnhanceCommand(dnf.cli.Command): SYMVERS_FILE = "/boot/symvers-%s.gz" + previous_boot_kernel = None aliases = ['upgrade-en'] summary = _( @@ -80,8 +82,65 @@ class UpgradeEnhanceCommand(dnf.cli.Command): self.skipped_grp_specs = None def run(self): + # if kernel kabi check failed, need change back to the default boot kernel version + self.previous_boot_kernel = self.get_default_boot_kernel() self.upgrade() + @staticmethod + def get_default_boot_kernel() -> Optional[str]: + """ + Get default boot kernel version. + + Returns: + str: default boot kernel + """ + cmd = ["grubby", "--default-kernel"] + # 'grubby --default-kernel' shows boot default kernel version in the system + # e.g. + # [root@openEuler ~]# grubby --default-kernel + # /boot/vmlinuz-4.19.90-2112.8.0.0131.oe1.x86_64 + output, return_code = cmd_output(cmd) + default_boot_kernel = output.split('\n')[0] + if return_code != SUCCEED: + return None + return default_boot_kernel + + @staticmethod + def restore_default_boot_kernel(target_boot_kernel: str): + """ + Restore default boot kernel version. + + Args: + target_boot_kernel(str): target boot kernel + """ + # 'grubby --set-default=/boot/vmlinuz-4.19.90-2112.8.0.0131.oe1.x86_64' can set default boot kernel version + # to kernel-4.19.90-2112.8.0.0131.oe1.x86_64 + if not target_boot_kernel: + print("Get default boot kernel before upgrade failed.") + return + + cmd = ["grubby", "--set-default=%s" % target_boot_kernel] + try: + # e.g. 4.19.90-2112.8.0.0131.oe1.x86_64 + target_boot_kernel_vere = target_boot_kernel.split('-', 1)[1] + target_boot_kernel_nevra = "kernel-%s" % target_boot_kernel_vere + except IndexError as e: + print( + "Parse target boot kernel failed. Please check if target boot kernel path is correct: %s." + % target_boot_kernel, + "\nRestore the default boot kernel failed. Please manually check the default boot kernel to prevent unexpected kernel switching after reboot.", + ) + return + + output, return_code = cmd_output(cmd) + if return_code != SUCCEED: + print( + "Restore the default boot kernel failed: %s. Please manually check the default boot kernel to prevent unexpected kernel switching after reboot." + % target_boot_kernel_nevra + ) + return + print("Restore the default boot kernel succeed: %s." % target_boot_kernel_nevra) + def run_transaction(self): """ Process kabi check for kernel rpm package installed this time. If the kernel rpm pakcgae fails kabi check, @@ -100,6 +159,8 @@ class UpgradeEnhanceCommand(dnf.cli.Command): # when processing remove operation, do not achieve the expected result of installing related rpm, # it indicates that the upgrade task failed self.remove_rpm(kernel_pkg) + # change back to the default boot kernel version before upgrade + self.restore_default_boot_kernel(self.previous_boot_kernel) exit(1) def remove_rpm(self, pkg: str): -- 2.27.0