From 2b772209c75e1c2c39b89975ea728a8a496d2702 Mon Sep 17 00:00:00 2001 From: Evgeny Slutsky Date: Tue, 16 Jun 2026 17:00:00 +0200 Subject: [PATCH 1/2] CI: work around bootupd 0.2.31 regression in QEMU/KVM VMs bootupd was upgraded from 0.2.27 to 0.2.31 in RHEL 9.8 repos. The new version's "bootupctl backend install --auto" fails with "No update metadata for component BIOS/EFI found" in QEMU/KVM VMs because the edge-commit ostree image lacks bootupd update metadata. Work around this by: 1. Patching anaconda's _install_bootupd() in %pre to suppress the BootloaderInstallationError, allowing the installation to complete. 2. Installing GRUB to the MBR manually in %post --nochroot for BIOS boot systems (EFI systems get bootloader files from the ostree deploy). This affects all kickstart templates via the shared main-prologue.cfg. Co-Authored-By: Claude Opus 4.6 --- .../includes/main-prologue.cfg | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/kickstart-templates/includes/main-prologue.cfg b/test/kickstart-templates/includes/main-prologue.cfg index 6155bbf94f..1dea479f15 100644 --- a/test/kickstart-templates/includes/main-prologue.cfg +++ b/test/kickstart-templates/includes/main-prologue.cfg @@ -4,6 +4,28 @@ timezone UTC text reboot +# Work around bootupd 0.2.31 regression where "bootupctl backend install --auto" +# fails with "No update metadata for component BIOS/EFI found" in QEMU/KVM VMs. +# Suppress the BootloaderInstallationError so the installation completes, then +# install GRUB manually in %post for BIOS systems. +# The %pre runs before anaconda imports the rpm-ostree payload module. +%pre --log=/dev/console +INSTALL_FILE=$(find /usr/lib*/python3*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree -name installation.py 2>/dev/null | head -1) +if [ -n "${INSTALL_FILE}" ] && grep -q 'raise BootloaderInstallationError' "${INSTALL_FILE}"; then + sed -i '/raise BootloaderInstallationError/{s/raise/return # /;n;s/^/# /}' "${INSTALL_FILE}" + find "$(dirname "${INSTALL_FILE}")" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true +fi +%end + +%post --nochroot --log=/dev/console +# Install GRUB bootloader manually since bootupd was bypassed above. +if [ ! -d /sys/firmware/efi ]; then + BOOT_DISK=$(lsblk -ndo PKNAME "$(findmnt -no SOURCE /mnt/sysroot)" 2>/dev/null | head -1) + [ -z "${BOOT_DISK}" ] && BOOT_DISK=vda + grub2-install --target=i386-pc --boot-directory=/mnt/sysroot/boot "/dev/${BOOT_DISK}" 2>&1 || true +fi +%end + # Partition the disk with hardware-specific boot and swap partitions, adding an # LVM volume that contains a system root partition of the specified size. # The remainder of the volume will be used by the CSI driver for storing data. From 94312e322de484fadb11fab076b42e94bf091c12 Mon Sep 17 00:00:00 2001 From: Evgeny Slutsky Date: Tue, 16 Jun 2026 19:33:55 +0200 Subject: [PATCH 2/2] CI: add EFI bootloader installation fallback for ARM VMs Extend the bootupd workaround to handle EFI boot systems (ARM) and generate a proper grub.cfg for ostree BLS boot entries. - Remove stale grub.cfg from ESP to avoid overlay resolution errors (BZ#1575957), run grub2-install with the appropriate EFI target and --no-nvram for EFI systems. - Generate grub.cfg with blscfg and a UUID-based search for the boot partition (the partition has no filesystem label). Co-Authored-By: Claude Opus 4.6 --- .../includes/main-prologue.cfg | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/test/kickstart-templates/includes/main-prologue.cfg b/test/kickstart-templates/includes/main-prologue.cfg index 1dea479f15..1b2573bb64 100644 --- a/test/kickstart-templates/includes/main-prologue.cfg +++ b/test/kickstart-templates/includes/main-prologue.cfg @@ -6,24 +6,62 @@ reboot # Work around bootupd 0.2.31 regression where "bootupctl backend install --auto" # fails with "No update metadata for component BIOS/EFI found" in QEMU/KVM VMs. -# Suppress the BootloaderInstallationError so the installation completes, then -# install GRUB manually in %post for BIOS systems. +# Make have_bootupd() return False so anaconda uses the legacy _move_grub_config() +# path for proper ostree boot configuration, then install GRUB to MBR/ESP in %post. # The %pre runs before anaconda imports the rpm-ostree payload module. %pre --log=/dev/console -INSTALL_FILE=$(find /usr/lib*/python3*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree -name installation.py 2>/dev/null | head -1) -if [ -n "${INSTALL_FILE}" ] && grep -q 'raise BootloaderInstallationError' "${INSTALL_FILE}"; then - sed -i '/raise BootloaderInstallationError/{s/raise/return # /;n;s/^/# /}' "${INSTALL_FILE}" - find "$(dirname "${INSTALL_FILE}")" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true +UTIL_FILE=$(find /usr/lib*/python3*/site-packages/pyanaconda/modules/payloads/payload/rpm_ostree -name util.py 2>/dev/null | head -1) +if [ -n "${UTIL_FILE}" ] && grep -q 'def have_bootupd' "${UTIL_FILE}"; then + sed -i '/def have_bootupd/a\ return False' "${UTIL_FILE}" + find "$(dirname "${UTIL_FILE}")" -name '__pycache__' -type d -exec rm -rf {} + 2>/dev/null || true fi %end %post --nochroot --log=/dev/console # Install GRUB bootloader manually since bootupd was bypassed above. -if [ ! -d /sys/firmware/efi ]; then - BOOT_DISK=$(lsblk -ndo PKNAME "$(findmnt -no SOURCE /mnt/sysroot)" 2>/dev/null | head -1) - [ -z "${BOOT_DISK}" ] && BOOT_DISK=vda +BOOT_DISK=$(lsblk -ndo PKNAME "$(findmnt -no SOURCE /mnt/sysroot)" 2>/dev/null | head -1) +[ -z "${BOOT_DISK}" ] && BOOT_DISK=vda +if [ -d /sys/firmware/efi ]; then + # EFI: remove stale grub.cfg from ESP to avoid overlay resolution + # errors (BZ#1575957), then reinstall the EFI bootloader. + rm -f /mnt/sysroot/boot/efi/EFI/*/grub.cfg 2>/dev/null || true + EFI_TARGET=x86_64-efi + [ "$(uname -m)" = "aarch64" ] && EFI_TARGET=arm64-efi + grub2-install --target="${EFI_TARGET}" --efi-directory=/mnt/sysroot/boot/efi \ + --boot-directory=/mnt/sysroot/boot --no-nvram "/dev/${BOOT_DISK}" 2>&1 || true +else + # BIOS: install GRUB stage1 to MBR. grub2-install --target=i386-pc --boot-directory=/mnt/sysroot/boot "/dev/${BOOT_DISK}" 2>&1 || true fi +# Generate grub.cfg with BLS support for ostree boot entries. +# Use the boot partition UUID for the search command since the +# partition may not have a filesystem label. +BOOT_UUID=$(lsblk -ndo UUID "$(findmnt -no SOURCE /mnt/sysroot/boot)" 2>/dev/null) +cat > /mnt/sysroot/boot/grub2/grub.cfg << GRUBEOF +set timeout=5 +load_video +set gfx_payload=keep +insmod all_video +search --no-floppy --set=root --fs-uuid ${BOOT_UUID} + +# Load grubenv for boot counter and saved entry support. +# The boot counter is used by greenboot to track failed boots and +# trigger automatic rollback to the previous ostree deployment. +load_env + +if [ "\${boot_success}" != "1" ] && [ "\${boot_counter}" -gt 0 ]; then + set boot_counter=\$((\${boot_counter} - 1)) + save_env boot_counter +fi + +if [ "\${boot_success}" = "1" ] || [ "\${boot_counter}" -gt 0 ]; then + set default=0 +else + set default=1 +fi + +blscfg +GRUBEOF %end # Partition the disk with hardware-specific boot and swap partitions, adding an