-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resolve boot issues in hybrid azure during upgrades from RHEL 7 > 8 > 9.
This actor addresses the issue where the `/boot/grub2/grub.cfg` file is overwritten during the upgrade process by an old RHEL7 configuration leftover on the system, causing the system to fail to boot. The problem occurs on hybrid Azure images, which support both UEFI and Legacy systems and have both `grub-pc` and `grub-efi` packages installed. It is caused by one of the scriplets in `grub-efi` which overwrites the old configuration. If old configuration is detected, this actor regenerates the grub configuration using `grub2-mkconfig -o /boot/grub2/grub.cfg` after installing rpms to ensure the correct boot configuration is in place. The fix is applied specifically to Azure hybrid cloud systems. JIRA: RHEL-38255
- Loading branch information
Showing
5 changed files
with
471 additions
and
0 deletions.
There are no files selected for viewing
34 changes: 34 additions & 0 deletions
34
repos/system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/actor.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from leapp.actors import Actor | ||
from leapp.libraries.actor import ensurevalidgrubcfghybrid | ||
from leapp.models import HybridImage | ||
from leapp.tags import ApplicationsPhaseTag, IPUWorkflowTag | ||
|
||
|
||
class EnsureValidGrubcfgHybrid(Actor): | ||
""" | ||
Resolve boot failures in Azure Gen1 VMs during upgrades from RHEL 7 to RHEL 8 to RHEL 9. | ||
This actor addresses the issue where the `/boot/grub2/grub.cfg` file is | ||
overwritten during the upgrade process by an old RHEL7 configuration | ||
leftover on the system, causing the system to fail to boot. | ||
The problem occurs on hybrid Azure images, which support both UEFI and | ||
Legacy systems and have both `grub-pc` and `grub-efi` packages installed. | ||
It is caused by one of the scriplets in `grub-efi` which overwrites the old | ||
configuration. | ||
If old configuration is detected, this actor regenerates the grub | ||
configuration using `grub2-mkconfig -o /boot/grub2/grub.cfg` after | ||
installing rpms to ensure the correct boot configuration is in place. | ||
The fix is applied specifically to Azure hybrid cloud systems. | ||
""" | ||
|
||
name = 'ensure_valid_grubcfg_hybrid' | ||
consumes = (HybridImage,) | ||
produces = () | ||
tags = (ApplicationsPhaseTag, IPUWorkflowTag) | ||
|
||
def process(self): | ||
ensurevalidgrubcfghybrid.process() |
66 changes: 66 additions & 0 deletions
66
...rade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/libraries/ensurevalidgrubcfghybrid.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import re | ||
|
||
from leapp.libraries.common.config.architecture import ARCH_ACCEPTED | ||
from leapp.libraries.stdlib import api, CalledProcessError, run | ||
from leapp.models import HybridImage | ||
from leapp.exceptions import StopActorExecutionError | ||
|
||
GRUB_CFG_PATH = '/boot/grub2/grub.cfg' | ||
|
||
MATCH_ARCH = r'({})'.format('|'.join(ARCH_ACCEPTED)) | ||
MATCH_RHEL7_KERNEL_VERSION = r"\d+\.\d+\.\d+-\d+(\.\d+)*\.el7\.{}".format(MATCH_ARCH) | ||
MATCH_RHEL7_KERNEL_DEFINITION = r"vmlinuz-{}".format(MATCH_RHEL7_KERNEL_VERSION) | ||
|
||
|
||
def process(): | ||
if not _is_hybrid_image(): | ||
api.current_logger().info('System is not a hybrid image. Skipping.') | ||
return | ||
|
||
grubcfg = _read_grubcfg() | ||
if _is_grubcfg_invalid(grubcfg): | ||
_run_grub2_mkconfig() | ||
|
||
|
||
def _is_hybrid_image(): | ||
return next(api.consume(HybridImage), None) is not None | ||
|
||
|
||
def _read_grubcfg(): | ||
api.current_logger().debug('Reading {}:'.format(GRUB_CFG_PATH)) | ||
with open(GRUB_CFG_PATH, 'r') as fin: | ||
grubcfg = fin.read() | ||
|
||
api.current_logger().debug(grubcfg) | ||
return grubcfg | ||
|
||
|
||
def _is_grubcfg_invalid(grubcfg): | ||
return _contains_rhel7_kernel_definition(grubcfg) | ||
|
||
|
||
def _contains_rhel7_kernel_definition(grubcfg): | ||
api.current_logger().debug("Looking for RHEL7 kernel version ...") | ||
|
||
match = re.search(MATCH_RHEL7_KERNEL_DEFINITION, grubcfg) | ||
|
||
api.current_logger().debug( | ||
"Matched: {}".format(match.group() if match else "[NO MATCH]") | ||
) | ||
|
||
return match is not None | ||
|
||
|
||
def _run_grub2_mkconfig(): | ||
api.current_logger().info("Regenerating {}".format(GRUB_CFG_PATH)) | ||
|
||
try: | ||
run([ | ||
'grub2-mkconfig', | ||
'-o', | ||
GRUB_CFG_PATH | ||
]) | ||
except CalledProcessError as err: | ||
msg = 'Could not regenerate {}: {}'.format(GRUB_CFG_PATH, str(err)) | ||
api.current_logger().error(msg) | ||
raise StopActorExecutionError(msg) |
52 changes: 52 additions & 0 deletions
52
...ystem_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/invalid_grub.cfg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
|
||
# Created by osbuild | ||
|
||
set timeout=10 | ||
|
||
# load the grubenv file | ||
load_env | ||
|
||
# selection of the next boot entry | ||
if [ "${next_entry}" ] ; then | ||
set default="${next_entry}" | ||
set next_entry= | ||
save_env next_entry | ||
set boot_once=true | ||
else | ||
set default="${saved_entry}" | ||
fi | ||
|
||
if [ "${prev_saved_entry}" ]; then | ||
set saved_entry="${prev_saved_entry}" | ||
save_env saved_entry | ||
set prev_saved_entry= | ||
save_env prev_saved_entry | ||
set boot_once=true | ||
fi | ||
|
||
function savedefault { | ||
if [ -z "${boot_once}" ]; then | ||
saved_entry="${chosen}" | ||
save_env saved_entry | ||
fi | ||
} | ||
|
||
serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1 | ||
terminal_input serial console | ||
terminal_output serial console | ||
|
||
menuentry 'Red Hat Enterprise Linux Server (3.10.0-1160.119.1.el7.x86_64) 7.9 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted --id 'gnulinux-3.10.0-1160.99.1.el7.x86_64-advanced-76a22bf4-f153-4541-b6c7-0332c0dfaeac' { | ||
insmod all_video | ||
set gfxpayload=keep | ||
search --no-floppy --set=root --fs-uuid 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
linuxefi /vmlinuz-3.10.0-1160.119.1.el7.x86_64 root=UUID=d3c9a2bd-7ffb-4113-9b8f-234c13b18274 ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y LANG=en_US.UTF-8 | ||
initrdefi /initramfs-3.10.0-1160.119.1.el7.x86_64.img | ||
} | ||
menuentry 'Red Hat Enterprise Linux (3.10.0-1160.99.1.el7.x86_64) 7.9 (Maipo)' --class red --class gnu-linux --class gnu --class os --unrestricted --id 'gnulinux-3.10.0-1160.99.1.el7.x86_64-advanced-76a22bf4-f153-4541-b6c7-0332c0dfaeac' { | ||
insmod all_video | ||
set gfxpayload=keep | ||
search --no-floppy --set=root --fs-uuid 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
linuxefi /vmlinuz-3.10.0-1160.99.1.el7.x86_64 root=UUID=d3c9a2bd-7ffb-4113-9b8f-234c13b18274 ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y | ||
initrdefi /initramfs-3.10.0-1160.99.1.el7.x86_64.img | ||
} | ||
|
195 changes: 195 additions & 0 deletions
195
.../system_upgrade/el8toel9/actors/cloud/ensurevalidgrubcfghybrid/tests/files/valid_grub.cfg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
# | ||
# DO NOT EDIT THIS FILE | ||
# | ||
# It is automatically generated by grub2-mkconfig using templates | ||
# from /etc/grub.d and settings from /etc/default/grub | ||
# | ||
|
||
### BEGIN /etc/grub.d/00_header ### | ||
set pager=1 | ||
|
||
if [ -f ${config_directory}/grubenv ]; then | ||
load_env -f ${config_directory}/grubenv | ||
elif [ -s $prefix/grubenv ]; then | ||
load_env | ||
fi | ||
if [ "${next_entry}" ] ; then | ||
set default="${next_entry}" | ||
set next_entry= | ||
save_env next_entry | ||
set boot_once=true | ||
else | ||
set default="${saved_entry}" | ||
fi | ||
|
||
if [ x"${feature_menuentry_id}" = xy ]; then | ||
menuentry_id_option="--id" | ||
else | ||
menuentry_id_option="" | ||
fi | ||
|
||
export menuentry_id_option | ||
|
||
if [ "${prev_saved_entry}" ]; then | ||
set saved_entry="${prev_saved_entry}" | ||
save_env saved_entry | ||
set prev_saved_entry= | ||
save_env prev_saved_entry | ||
set boot_once=true | ||
fi | ||
|
||
function savedefault { | ||
if [ -z "${boot_once}" ]; then | ||
saved_entry="${chosen}" | ||
save_env saved_entry | ||
fi | ||
} | ||
|
||
function load_video { | ||
if [ x$feature_all_video_module = xy ]; then | ||
insmod all_video | ||
else | ||
insmod efi_gop | ||
insmod efi_uga | ||
insmod ieee1275_fb | ||
insmod vbe | ||
insmod vga | ||
insmod video_bochs | ||
insmod video_cirrus | ||
fi | ||
} | ||
|
||
serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1 | ||
terminal_input serial console | ||
terminal_output serial console | ||
if [ x$feature_timeout_style = xy ] ; then | ||
set timeout_style=countdown | ||
set timeout=10 | ||
# Fallback hidden-timeout code in case the timeout_style feature is | ||
# unavailable. | ||
elif sleep --interruptible 10 ; then | ||
set timeout=0 | ||
fi | ||
### END /etc/grub.d/00_header ### | ||
|
||
### BEGIN /etc/grub.d/00_tuned ### | ||
set tuned_params="" | ||
set tuned_initrd="" | ||
### END /etc/grub.d/00_tuned ### | ||
|
||
### BEGIN /etc/grub.d/01_users ### | ||
if [ -f ${prefix}/user.cfg ]; then | ||
source ${prefix}/user.cfg | ||
if [ -n "${GRUB2_PASSWORD}" ]; then | ||
set superusers="root" | ||
export superusers | ||
password_pbkdf2 root ${GRUB2_PASSWORD} | ||
fi | ||
fi | ||
### END /etc/grub.d/01_users ### | ||
|
||
### BEGIN /etc/grub.d/08_fallback_counting ### | ||
insmod increment | ||
# Check if boot_counter exists and boot_success=0 to activate this behaviour. | ||
if [ -n "${boot_counter}" -a "${boot_success}" = "0" ]; then | ||
# if countdown has ended, choose to boot rollback deployment, | ||
# i.e. default=1 on OSTree-based systems. | ||
if [ "${boot_counter}" = "0" -o "${boot_counter}" = "-1" ]; then | ||
set default=1 | ||
set boot_counter=-1 | ||
# otherwise decrement boot_counter | ||
else | ||
decrement boot_counter | ||
fi | ||
save_env boot_counter | ||
fi | ||
### END /etc/grub.d/08_fallback_counting ### | ||
|
||
### BEGIN /etc/grub.d/10_linux ### | ||
insmod part_gpt | ||
insmod xfs | ||
set root='hd0,gpt2' | ||
if [ x$feature_platform_search_hint = xy ]; then | ||
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
else | ||
search --no-floppy --fs-uuid --set=root 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
fi | ||
insmod part_gpt | ||
insmod xfs | ||
set boot='hd0,gpt2' | ||
if [ x$feature_platform_search_hint = xy ]; then | ||
search --no-floppy --fs-uuid --set=boot --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
else | ||
search --no-floppy --fs-uuid --set=boot 61779359-8d11-49ba-bc9d-8d038ee4b108 | ||
fi | ||
|
||
# This section was generated by a script. Do not modify the generated file - all changes | ||
# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files. | ||
# | ||
# The blscfg command parses the BootLoaderSpec files stored in /boot/loader/entries and | ||
# populates the boot menu. Please refer to the Boot Loader Specification documentation | ||
# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/. | ||
|
||
# The kernelopts variable should be defined in the grubenv file. But to ensure that menu | ||
# entries populated from BootLoaderSpec files that use this variable work correctly even | ||
# without a grubenv file, define a fallback kernelopts variable if this has not been set. | ||
# | ||
# The kernelopts variable in the grubenv file can be modified using the grubby tool or by | ||
# executing the grub2-mkconfig tool. For the latter, the values of the GRUB_CMDLINE_LINUX | ||
# and GRUB_CMDLINE_LINUX_DEFAULT options from /etc/default/grub file are used to set both | ||
# the kernelopts variable in the grubenv file and the fallback kernelopts variable. | ||
if [ -z "${kernelopts}" ]; then | ||
set kernelopts="root=/dev/mapper/rootvg-rootlv ro ro crashkernel=auto console=tty1 console=ttyS0 earlyprintk=ttyS0 rootdelay=300 scsi_mod.use_blk_mq=y " | ||
fi | ||
|
||
insmod blscfg | ||
blscfg | ||
### END /etc/grub.d/10_linux ### | ||
|
||
### BEGIN /etc/grub.d/10_reset_boot_success ### | ||
# Hiding the menu is ok if last boot was ok or if this is a first boot attempt to boot the entry | ||
if [ "${boot_success}" = "1" -o "${boot_indeterminate}" = "1" ]; then | ||
set menu_hide_ok=1 | ||
else | ||
set menu_hide_ok=0 | ||
fi | ||
# Reset boot_indeterminate after a successful boot | ||
if [ "${boot_success}" = "1" ] ; then | ||
set boot_indeterminate=0 | ||
# Avoid boot_indeterminate causing the menu to be hidden more then once | ||
elif [ "${boot_indeterminate}" = "1" ]; then | ||
set boot_indeterminate=2 | ||
fi | ||
# Reset boot_success for current boot | ||
set boot_success=0 | ||
save_env boot_success boot_indeterminate | ||
### END /etc/grub.d/10_reset_boot_success ### | ||
|
||
### BEGIN /etc/grub.d/12_menu_auto_hide ### | ||
### END /etc/grub.d/12_menu_auto_hide ### | ||
|
||
### BEGIN /etc/grub.d/20_linux_xen ### | ||
### END /etc/grub.d/20_linux_xen ### | ||
|
||
### BEGIN /etc/grub.d/20_ppc_terminfo ### | ||
### END /etc/grub.d/20_ppc_terminfo ### | ||
|
||
### BEGIN /etc/grub.d/30_os-prober ### | ||
### END /etc/grub.d/30_os-prober ### | ||
|
||
### BEGIN /etc/grub.d/30_uefi-firmware ### | ||
### END /etc/grub.d/30_uefi-firmware ### | ||
|
||
### BEGIN /etc/grub.d/40_custom ### | ||
# This file provides an easy way to add custom menu entries. Simply type the | ||
# menu entries you want to add after this comment. Be careful not to change | ||
# the 'exec tail' line above. | ||
### END /etc/grub.d/40_custom ### | ||
|
||
### BEGIN /etc/grub.d/41_custom ### | ||
if [ -f ${config_directory}/custom.cfg ]; then | ||
source ${config_directory}/custom.cfg | ||
elif [ -z "${config_directory}" -a -f $prefix/custom.cfg ]; then | ||
source $prefix/custom.cfg; | ||
fi | ||
### END /etc/grub.d/41_custom ### |
Oops, something went wrong.