diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de7c18902..d13dbe4b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,7 +117,7 @@ jobs: run: | set -xeuo pipefail sudo podman run --rm -ti --privileged -v /:/target -v ./usr/bin/bootc:/usr/bin/bootc --pid=host --security-opt label=disable \ - quay.io/centos-boot/fedora-tier-1:eln bootc install-to-filesystem --target-no-signature-verification \ + quay.io/centos-boot/fedora-tier-1-dev:eln bootc install-to-filesystem --target-no-signature-verification \ --karg=foo=bar --disable-selinux --replace=alongside /target ls -al /boot/loader/ sudo grep foo=bar /boot/loader/entries/*.conf diff --git a/lib/src/bootloader.rs b/lib/src/bootloader.rs index c52aef872..f9cbeb2b1 100644 --- a/lib/src/bootloader.rs +++ b/lib/src/bootloader.rs @@ -1,16 +1,9 @@ -use std::os::unix::prelude::PermissionsExt; - -use anyhow::{Context, Result}; +use anyhow::Result; use camino::Utf8Path; -use cap_std::fs::Dir; -use cap_std::fs::Permissions; -use cap_std_ext::cap_std; -use cap_std_ext::prelude::*; use fn_error_context::context; use crate::task::Task; -const GRUB_BOOT_UUID_FILE: &str = "bootuuid.cfg"; /// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel) pub(crate) const EFI_DIR: &str = "efi"; @@ -18,17 +11,15 @@ pub(crate) const EFI_DIR: &str = "efi"; pub(crate) fn install_via_bootupd( device: &Utf8Path, rootfs: &Utf8Path, - boot_uuid: &str, - is_alongside: bool, + configopts: &crate::install::InstallConfigOpts, ) -> Result<()> { let verbose = std::env::var_os("BOOTC_BOOTLOADER_DEBUG").map(|_| "-vvvv"); - // If we're doing an alongside install, only match the host boot method because Anaconda defaults - // to only doing that. - let component_args = is_alongside.then_some("--auto"); - let args = ["backend", "install", "--with-static-configs"] + // bootc defaults to only targeting the platform boot method. + let bootupd_opts = (!configopts.generic_image).then_some(["--update-firmware", "--auto"]); + let args = ["backend", "install", "--write-uuid"] .into_iter() .chain(verbose) - .chain(component_args) + .chain(bootupd_opts.iter().copied().flatten()) .chain([ "--src-root", "/", @@ -36,22 +27,5 @@ pub(crate) fn install_via_bootupd( device.as_str(), rootfs.as_str(), ]); - Task::new_and_run("Running bootupctl to install bootloader", "bootupctl", args)?; - - let grub2_uuid_contents = format!("set BOOT_UUID=\"{boot_uuid}\"\n"); - - let bootfs = &rootfs.join("boot"); - let bootfs = - Dir::open_ambient_dir(bootfs, cap_std::ambient_authority()).context("Opening boot")?; - let grub2 = bootfs.open_dir("grub2").context("Opening boot/grub2")?; - - grub2 - .atomic_write_with_perms( - GRUB_BOOT_UUID_FILE, - grub2_uuid_contents, - Permissions::from_mode(0o644), - ) - .with_context(|| format!("Writing {GRUB_BOOT_UUID_FILE}"))?; - - Ok(()) + Task::new_and_run("Running bootupctl to install bootloader", "bootupctl", args) } diff --git a/lib/src/install.rs b/lib/src/install.rs index 367b04320..dafe20489 100644 --- a/lib/src/install.rs +++ b/lib/src/install.rs @@ -105,6 +105,15 @@ pub(crate) struct InstallConfigOpts { #[clap(long)] /// Add a kernel argument karg: Option>, + + /// Perform configuration changes suitable for a "generic" disk image. + /// At the moment: + /// + /// - All bootloader types will be installed + /// - Changes to the system firmware will be skipped + #[clap(long)] + #[serde(default)] + pub(crate) generic_image: bool, } /// Perform an installation to a block device. @@ -964,6 +973,13 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re rootfs.kargs.push("selinux=0".to_string()); } + // We verify this upfront because it's currently required by bootupd + let boot_uuid = rootfs + .get_boot_uuid()? + .or(rootfs.rootfs_uuid.as_deref()) + .ok_or_else(|| anyhow!("No uuid for boot/root"))?; + tracing::debug!("boot uuid={boot_uuid}"); + // Write the aleph data that captures the system state at the time of provisioning for aid in future debugging. { let aleph = initialize_ostree_root_from_self(state, rootfs).await?; @@ -976,16 +992,7 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re .context("Writing aleph version")?; } - let boot_uuid = rootfs - .get_boot_uuid()? - .or(rootfs.rootfs_uuid.as_deref()) - .ok_or_else(|| anyhow!("No uuid for boot/root"))?; - crate::bootloader::install_via_bootupd( - &rootfs.device, - &rootfs.rootfs, - boot_uuid, - rootfs.is_alongside, - )?; + crate::bootloader::install_via_bootupd(&rootfs.device, &rootfs.rootfs, &state.config_opts)?; tracing::debug!("Installed bootloader"); // ostree likes to have the immutable bit on the physical sysroot to ensure diff --git a/tests/kolainst/install b/tests/kolainst/install index 291a4edec..b71f4de2e 100755 --- a/tests/kolainst/install +++ b/tests/kolainst/install @@ -10,7 +10,7 @@ set -xeuo pipefail -IMAGE=quay.io/centos-boot/fedora-tier-1:eln +IMAGE=quay.io/centos-boot/fedora-tier-1-dev:eln # TODO: better detect this, e.g. look for an empty device DEV=/dev/vda