From 76d7f305305b6524e7416325847cd3a334b243b8 Mon Sep 17 00:00:00 2001 From: jbtrystram Date: Tue, 3 Feb 2026 23:25:25 +0100 Subject: [PATCH 1/2] install/bootloader: make --write-uuid optional Allow skiping the boot uuid stamp file writing in bootupd. When creating a golden image, we expect the UUIDS to be randomized at first boot, so always writing the stamp is odd. At least for Fedora CoreOS the stamp being already there at first boot short-circuit the partitions uuid randomization process. So let's make it optionnal. It will default to `false`, preserving existing behaviour when not specified. ref https://github.com/coreos/fedora-coreos-config/pull/3898 Assisted-by: OpenCode (Opus 4.5) Signed-off-by: jbtrystram --- crates/lib/src/bootloader.rs | 7 ++++++- crates/lib/src/install.rs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/crates/lib/src/bootloader.rs b/crates/lib/src/bootloader.rs index be1d5882b..22593d192 100644 --- a/crates/lib/src/bootloader.rs +++ b/crates/lib/src/bootloader.rs @@ -105,7 +105,12 @@ pub(crate) fn install_via_bootupd( println!("Installing bootloader via bootupd"); // Build the bootupctl arguments - let mut bootupd_args: Vec<&str> = vec!["backend", "install", "--write-uuid"]; + let mut bootupd_args: Vec<&str> = vec!["backend", "install"]; + if configopts.skip_boot_uuid_stamp { + bootupd_args.push("--with-static-configs") + } else { + bootupd_args.push("--write-uuid"); + } if let Some(v) = verbose { bootupd_args.push(v); } diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index 3536c14cb..612caab5b 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -368,6 +368,11 @@ pub(crate) struct InstallConfigOpts { /// The stateroot name to use. Defaults to `default`. #[clap(long)] pub(crate) stateroot: Option, + + /// Don't pass --write-uuid to bootupd during bootloader installation. + #[clap(long)] + #[serde(default)] + pub(crate) skip_boot_uuid_stamp: bool, } #[derive(Debug, Default, Clone, clap::Parser, Serialize, Deserialize, PartialEq, Eq)] From d411d0de71744acd5ba2127315f84ff0d2383f6f Mon Sep 17 00:00:00 2001 From: jbtrystram Date: Wed, 4 Feb 2026 00:03:00 +0100 Subject: [PATCH 2/2] install/config: wire up `skip_boot_uuid_stamp` Wiring-up this knob to the install config to allow it's use in bootc-image-builder. Assisted-by: OpenCode (Opus 4.5) Signed-off-by: jbtrystram --- crates/lib/src/install.rs | 11 ++++- crates/lib/src/install/config.rs | 58 ++++++++++++++++++++++++++ docs/src/man/bootc-install-config.5.md | 3 ++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/crates/lib/src/install.rs b/crates/lib/src/install.rs index 612caab5b..0e0ee0ab7 100644 --- a/crates/lib/src/install.rs +++ b/crates/lib/src/install.rs @@ -1517,7 +1517,7 @@ async fn verify_target_fetch( /// Preparation for an install; validates and prepares some (thereafter immutable) global state. async fn prepare_install( - config_opts: InstallConfigOpts, + mut config_opts: InstallConfigOpts, source_opts: InstallSourceOpts, target_opts: InstallTargetOpts, mut composefs_options: InstallComposefsOpts, @@ -1642,8 +1642,15 @@ async fn prepare_install( } let install_config = config::load_config()?; - if install_config.is_some() { + if let Some(ref config) = install_config { tracing::debug!("Loaded install configuration"); + // Merge config file values into config_opts (CLI takes precedence) + // Only apply config file value if CLI didn't explicitly set it + if !config_opts.skip_boot_uuid_stamp { + if let Some(skip) = config.skip_boot_uuid_stamp { + config_opts.skip_boot_uuid_stamp = skip; + } + } } else { tracing::debug!("No install configuration found"); } diff --git a/crates/lib/src/install/config.rs b/crates/lib/src/install/config.rs index d62e51c88..dd63534b3 100644 --- a/crates/lib/src/install/config.rs +++ b/crates/lib/src/install/config.rs @@ -85,6 +85,10 @@ pub(crate) struct InstallConfiguration { pub(crate) root_mount_spec: Option, /// Mount specification for the /boot filesystem. pub(crate) boot_mount_spec: Option, + /// Wether to skip writing the boot partition UUID to the bootloader configuration. + /// When true, uses --with-static-configs instead of --write-uuid for bootupd. + /// Defaults to false if not specified (the boot UUID is written by default). + pub(crate) skip_boot_uuid_stamp: Option, } fn merge_basic(s: &mut Option, o: Option, _env: &EnvProperties) { @@ -160,6 +164,11 @@ impl Mergeable for InstallConfiguration { merge_basic(&mut self.stateroot, other.stateroot, env); merge_basic(&mut self.root_mount_spec, other.root_mount_spec, env); merge_basic(&mut self.boot_mount_spec, other.boot_mount_spec, env); + merge_basic( + &mut self.skip_boot_uuid_stamp, + other.skip_boot_uuid_stamp, + env, + ); if let Some(other_kargs) = other.kargs { self.kargs .get_or_insert_with(Default::default) @@ -731,4 +740,53 @@ boot-mount-spec = "" assert_eq!(install.root_mount_spec.as_deref().unwrap(), ""); assert_eq!(install.boot_mount_spec.as_deref().unwrap(), ""); } + + #[test] + fn test_parse_skip_boot_uuid_stamp() { + // Test parsing true + let c: InstallConfigurationToplevel = toml::from_str( + r#"[install] +skip-boot-uuid-stamp = true +"#, + ) + .unwrap(); + assert_eq!(c.install.unwrap().skip_boot_uuid_stamp.unwrap(), true); + + // Test parsing false + let c: InstallConfigurationToplevel = toml::from_str( + r#"[install] +skip-boot-uuid-stamp = false +"#, + ) + .unwrap(); + assert_eq!(c.install.unwrap().skip_boot_uuid_stamp.unwrap(), false); + + // Test default (not specified) is None + let c: InstallConfigurationToplevel = toml::from_str( + r#"[install] +root-fs-type = "xfs" +"#, + ) + .unwrap(); + assert!(c.install.unwrap().skip_boot_uuid_stamp.is_none()); + } + + #[test] + fn test_merge_skip_boot_uuid_stamp() { + let env = EnvProperties { + sys_arch: "x86_64".to_string(), + }; + let mut install: InstallConfiguration = toml::from_str( + r#"skip-boot-uuid-stamp = false +"#, + ) + .unwrap(); + let other = InstallConfiguration { + skip_boot_uuid_stamp: Some(true), + ..Default::default() + }; + install.merge(other, &env); + // skip_boot_uuid_stamp should be overridden to true + assert_eq!(install.skip_boot_uuid_stamp.unwrap(), true); + } } diff --git a/docs/src/man/bootc-install-config.5.md b/docs/src/man/bootc-install-config.5.md index 985892ebe..64b1c9afb 100644 --- a/docs/src/man/bootc-install-config.5.md +++ b/docs/src/man/bootc-install-config.5.md @@ -33,6 +33,9 @@ The `install` section supports these subfields: - `boot-mount-spec`: A string specifying the /boot filesystem mount specification. If not provided and /boot is a separate mount, its UUID will be used. An empty string signals to omit boot mount kargs entirely. +- `skip-boot-uuid-stamp`: A boolean that controls whether to skip writing partition UUIDs + to the bootloader configuration. When `true`, bootupd is invoked with `--with-static-configs` + instead of `--write-uuid`. Defaults to `false` (UUIDs are written by default). # filesystem