From c5f25819eab417673a72d6f2b121290228d2b4eb Mon Sep 17 00:00:00 2001 From: Nicholas Kuechler Date: Wed, 12 Aug 2026 08:23:15 -0500 Subject: [PATCH] feat(images): Adds ubuntu 26.04 builder update builder versions --- .github/workflows/build-ironic-images.yaml | 2 +- .../post-install.d/90-dracut-drivers | 42 +++++++++++ .../finalise.d/99-efi-boot-fix | 75 +++++++++++++++++++ ironic-images/requirements.txt | 4 +- ironic-images/{ubuntu.yaml => ubuntu-24.yaml} | 1 + ironic-images/ubuntu-26.yaml | 13 ++++ 6 files changed, 134 insertions(+), 3 deletions(-) create mode 100755 ironic-images/custom_elements/undercloud-dracut-drivers/post-install.d/90-dracut-drivers create mode 100755 ironic-images/custom_elements/undercloud-efi-boot-fix/finalise.d/99-efi-boot-fix rename ironic-images/{ubuntu.yaml => ubuntu-24.yaml} (87%) create mode 100644 ironic-images/ubuntu-26.yaml diff --git a/.github/workflows/build-ironic-images.yaml b/.github/workflows/build-ironic-images.yaml index ab9ca5b23..f86922af2 100644 --- a/.github/workflows/build-ironic-images.yaml +++ b/.github/workflows/build-ironic-images.yaml @@ -112,7 +112,7 @@ jobs: mkdir -p upload find . -maxdepth 1 -type f \( -name '*.qcow2' -o -name '*.kernel' -o -name '*.initramfs' \) -exec cp {} upload/ \; env: - ELEMENTS_PATH: "${{ env.distro == 'ipa-debian' && format('{0}/share/ironic-python-agent-builder/dib:{1}/ironic-images/custom_elements', env.pythonLocation, github.workspace) || ''}}" + ELEMENTS_PATH: "${{ env.distro == 'ipa-debian' && format('{0}/share/ironic-python-agent-builder/dib:{1}/ironic-images/custom_elements', env.pythonLocation, github.workspace) || format('{0}/ironic-images/custom_elements', github.workspace) }}" - name: Set timestamp environment variable run: echo "TIMESTAMP=$(git show --no-patch --no-notes --pretty='%cd' --date=format:'%Y%m%d%H%M%S' ${{ github.sha }})" >> $GITHUB_ENV diff --git a/ironic-images/custom_elements/undercloud-dracut-drivers/post-install.d/90-dracut-drivers b/ironic-images/custom_elements/undercloud-dracut-drivers/post-install.d/90-dracut-drivers new file mode 100755 index 000000000..57264b42c --- /dev/null +++ b/ironic-images/custom_elements/undercloud-dracut-drivers/post-install.d/90-dracut-drivers @@ -0,0 +1,42 @@ +#!/bin/bash + +if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then + set -x +fi +set -eu +set -o pipefail + +# Ubuntu 26.04 uses dracut instead of initramfs-tools. When the image is built +# on a GitHub Actions runner (no RAID controller present), dracut in hostonly +# mode won't include storage drivers needed for bare metal servers. +# +# This script: +# 1. Drops a dracut config for generic (non-hostonly) initramfs with all +# necessary drivers and systemd modules +# 2. Regenerates the initramfs after all packages are installed + +mkdir -p /etc/dracut.conf.d + +cat > /etc/dracut.conf.d/99-undercloud-baremetal.conf << 'EOF' +# Build a generic initramfs that includes all drivers, not just those +# for the build host. Required for bare metal deployment where the target +# hardware differs from the image build environment. +hostonly=no +hostonly_cmdline=no + +# Explicitly include storage controller drivers common in our fleet +add_drivers+=" megaraid_sas mpt3sas mptsas ahci nvme sd_mod sr_mod " + +# Include filesystem modules +add_drivers+=" ext4 xfs vfat " + +# Ensure systemd modules are present for proper root mount and remount +add_dracutmodules+=" systemd systemd-initrd rootfs-block fstab-sys " +EOF + +echo "Installed /etc/dracut.conf.d/99-undercloud-baremetal.conf" + +# Regenerate all initramfs images with the new configuration. +# This runs in post-install.d so all kernel packages are already installed. +dracut --regenerate-all --force +echo "Regenerated initramfs for all installed kernels" diff --git a/ironic-images/custom_elements/undercloud-efi-boot-fix/finalise.d/99-efi-boot-fix b/ironic-images/custom_elements/undercloud-efi-boot-fix/finalise.d/99-efi-boot-fix new file mode 100755 index 000000000..84e6a4a88 --- /dev/null +++ b/ironic-images/custom_elements/undercloud-efi-boot-fix/finalise.d/99-efi-boot-fix @@ -0,0 +1,75 @@ +#!/bin/bash + +if [ ${DIB_DEBUG_TRACE:-0} -gt 0 ]; then + set -x +fi +set -eu +set -o pipefail + +# During the DIB finalise phase, /boot/efi is mounted but the distro-specific +# EFI directory (EFI/ubuntu) does not exist because the shim-signed package +# installs its files to /usr/lib/shim/ rather than directly to the ESP. +# +# The bootloader element's 50-bootloader script runs grub-install --removable +# which places a plain grubx64.efi as EFI/BOOT/BOOTX64.EFI. However, the +# shim-signed package also installs a BOOTX64.CSV that references shimx64.efi, +# which IPA then uses to create UEFI NVRAM boot entries pointing to a +# non-existent \EFI\BOOT\shimx64.efi — causing boot failure. +# +# Fix: Install the signed shim and grub binaries into the proper locations +# on the ESP so the full secure boot chain works. + +ESP_BOOT_DIR="/boot/efi/EFI/BOOT" +ESP_UBUNTU_DIR="/boot/efi/EFI/ubuntu" + +# Signed shim location from shim-signed package +SHIM_SIGNED="/usr/lib/shim/shimx64.efi.signed" +# Signed grub location from grub-efi-amd64-signed package +GRUB_SIGNED="/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed" + +if [ ! -f "${SHIM_SIGNED}" ]; then + echo "WARNING: ${SHIM_SIGNED} not found, skipping EFI boot fix" + exit 0 +fi + +# Create the distro-specific EFI directory +mkdir -p "${ESP_UBUNTU_DIR}" + +# Install shimx64.efi to EFI/BOOT/ (what BOOTX64.CSV advertises) +cp "${SHIM_SIGNED}" "${ESP_BOOT_DIR}/shimx64.efi" +echo "Copied shimx64.efi to ${ESP_BOOT_DIR}/" + +# Install signed grub as grubx64.efi in EFI/BOOT/ (shim chains to this name) +if [ -f "${GRUB_SIGNED}" ]; then + cp "${GRUB_SIGNED}" "${ESP_BOOT_DIR}/grubx64.efi" + echo "Copied grubx64.efi to ${ESP_BOOT_DIR}/" +fi + +# Install shimx64.efi to EFI/ubuntu/ (standard Ubuntu location) +cp "${SHIM_SIGNED}" "${ESP_UBUNTU_DIR}/shimx64.efi" +echo "Copied shimx64.efi to ${ESP_UBUNTU_DIR}/" + +# Install signed grub to EFI/ubuntu/ +if [ -f "${GRUB_SIGNED}" ]; then + cp "${GRUB_SIGNED}" "${ESP_UBUNTU_DIR}/grubx64.efi" + echo "Copied grubx64.efi to ${ESP_UBUNTU_DIR}/" +fi + +# Copy grub.cfg to EFI/ubuntu/ so shim->grub chain can find it +if [ -f /boot/grub/grub.cfg ]; then + cp /boot/grub/grub.cfg "${ESP_UBUNTU_DIR}/grub.cfg" + echo "Copied grub.cfg to ${ESP_UBUNTU_DIR}/" +elif [ -f /boot/efi/EFI/BOOT/grub.cfg ]; then + cp /boot/efi/EFI/BOOT/grub.cfg "${ESP_UBUNTU_DIR}/grub.cfg" + echo "Copied grub.cfg from EFI/BOOT/ to ${ESP_UBUNTU_DIR}/" +fi + +# Ensure grub.cfg exists in EFI/BOOT/ for the shim->grub chain. +# The signed grub looks for grub.cfg relative to its own prefix. If booting +# via shimx64.efi -> grubx64.efi in EFI/BOOT/, grub needs a config here. +if [ ! -f "${ESP_BOOT_DIR}/grub.cfg" ]; then + if [ -f /boot/grub/grub.cfg ]; then + cp /boot/grub/grub.cfg "${ESP_BOOT_DIR}/grub.cfg" + echo "Copied grub.cfg to ${ESP_BOOT_DIR}/" + fi +fi diff --git a/ironic-images/requirements.txt b/ironic-images/requirements.txt index e71483e59..251686bc6 100644 --- a/ironic-images/requirements.txt +++ b/ironic-images/requirements.txt @@ -1,2 +1,2 @@ -diskimage-builder==3.41.0 -ironic-python-agent-builder==7.2.0 +diskimage-builder==3.42.0 +ironic-python-agent-builder==7.3.0 diff --git a/ironic-images/ubuntu.yaml b/ironic-images/ubuntu-24.yaml similarity index 87% rename from ironic-images/ubuntu.yaml rename to ironic-images/ubuntu-24.yaml index a41c82f0f..ee800a7bc 100644 --- a/ironic-images/ubuntu.yaml +++ b/ironic-images/ubuntu-24.yaml @@ -9,3 +9,4 @@ - baremetal - bootloader - package-installs + - undercloud-efi-boot-fix diff --git a/ironic-images/ubuntu-26.yaml b/ironic-images/ubuntu-26.yaml new file mode 100644 index 000000000..647bcbd19 --- /dev/null +++ b/ironic-images/ubuntu-26.yaml @@ -0,0 +1,13 @@ +- imagename: ubuntu-resolute + environment: + DISTRO_NAME: 'ubuntu' + DIB_RELEASE: 'resolute' + elements: + - ubuntu + - grub2 + - block-device-efi + - baremetal + - bootloader + - package-installs + - undercloud-efi-boot-fix + - undercloud-dracut-drivers