1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

install: support configuring sysroot.bls-append-except-default

Add a new [install.ostree] configuration section to allow setting the
ostree sysroot.bls-append-except-default option during installation.

Closes: https://github.com/bootc-dev/bootc/issues/1710

Signed-off-by: Joel Capitao <jcapitao@redhat.com>
Co-authored-by: Jean-Baptiste Trystram <jbtrystram@redhat.com>
Assisted-by: Claude (Sonnet 4)
This commit is contained in:
Joel Capitao
2026-01-06 18:42:50 +01:00
committed by Colin Walters
parent c68e2b4987
commit b901498d44
6 changed files with 141 additions and 2 deletions

View File

@@ -795,7 +795,21 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result
crate::lsm::ensure_dir_labeled(rootfs_dir, "boot", None, 0o755.into(), sepolicy)?;
}
for (k, v) in DEFAULT_REPO_CONFIG.iter() {
// Build the list of ostree repo config options: defaults + install config
let ostree_opts = state
.install_config
.as_ref()
.and_then(|c| c.ostree.as_ref())
.into_iter()
.flat_map(|o| o.to_config_tuples());
let repo_config: Vec<_> = DEFAULT_REPO_CONFIG
.iter()
.copied()
.chain(ostree_opts)
.collect();
for (k, v) in repo_config.iter() {
Command::new("ostree")
.args(["config", "--repo", "ostree/repo", "set", k, v])
.cwd_dir(rootfs_dir.try_clone()?)

View File

@@ -58,6 +58,9 @@ pub(crate) struct BasicFilesystems {
// pub(crate) esp: Option<FilesystemCustomization>,
}
/// Configuration for ostree repository
pub(crate) type OstreeRepoOpts = ostree_ext::repo_options::RepoOptions;
/// The serialized [install] section
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(rename = "install", rename_all = "kebab-case", deny_unknown_fields)]
@@ -73,6 +76,8 @@ pub(crate) struct InstallConfiguration {
pub(crate) kargs: Option<Vec<String>>,
/// Supported architectures for this configuration
pub(crate) match_architectures: Option<Vec<String>>,
/// Ostree repository configuration
pub(crate) ostree: Option<OstreeRepoOpts>,
}
fn merge_basic<T>(s: &mut Option<T>, o: Option<T>, _env: &EnvProperties) {
@@ -119,6 +124,17 @@ impl Mergeable for BasicFilesystems {
}
}
impl Mergeable for OstreeRepoOpts {
/// Apply any values in other, overriding any existing values in `self`.
fn merge(&mut self, other: Self, env: &EnvProperties) {
merge_basic(
&mut self.bls_append_except_default,
other.bls_append_except_default,
env,
)
}
}
impl Mergeable for InstallConfiguration {
/// Apply any values in other, overriding any existing values in `self`.
fn merge(&mut self, other: Self, env: &EnvProperties) {
@@ -133,6 +149,7 @@ impl Mergeable for InstallConfiguration {
#[cfg(feature = "install-to-disk")]
merge_basic(&mut self.block, other.block, env);
self.filesystem.merge(other.filesystem, env);
self.ostree.merge(other.ostree, env);
if let Some(other_kargs) = other.kargs {
self.kargs
.get_or_insert_with(Default::default)
@@ -572,4 +589,54 @@ root-fs-type = "xfs"
)
);
}
#[test]
fn test_parse_ostree() {
let env = EnvProperties {
sys_arch: "x86_64".to_string(),
};
// Table-driven test cases for parsing bls-append-except-default
let parse_cases = [
("console=ttyS0", "console=ttyS0"),
("console=ttyS0,115200n8", "console=ttyS0,115200n8"),
("rd.lvm.lv=vg/root", "rd.lvm.lv=vg/root"),
];
for (input, expected) in parse_cases {
let toml_str = format!(
r#"[install.ostree]
bls-append-except-default = "{input}"
"#
);
let c: InstallConfigurationToplevel = toml::from_str(&toml_str).unwrap();
assert_eq!(
c.install
.unwrap()
.ostree
.unwrap()
.bls_append_except_default
.unwrap(),
expected
);
}
// Test merging: other config should override original
let mut install: InstallConfiguration = toml::from_str(
r#"[ostree]
bls-append-except-default = "console=ttyS0"
"#,
)
.unwrap();
let other = InstallConfiguration {
ostree: Some(OstreeRepoOpts {
bls_append_except_default: Some("console=tty0".to_string()),
}),
..Default::default()
};
install.merge(other, &env);
assert_eq!(
install.ostree.unwrap().bls_append_except_default.unwrap(),
"console=tty0"
);
}
}

View File

@@ -47,6 +47,7 @@ pub mod ostree_prepareroot;
pub mod refescape;
#[doc(hidden)]
pub mod repair;
pub mod repo_options;
pub mod sysroot;
pub mod tar;
pub mod tokio_util;

View File

@@ -0,0 +1,30 @@
//! Configuration options for an ostree repository
use serde::{Deserialize, Serialize};
/// Configuration options for an ostree repository.
///
/// This struct represents configurable options for an ostree repository
/// that can be set via the `ostree config set` command.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case", default)]
pub struct RepoOptions {
/// Boot Loader Spec entries that should append arguments only for non-default entries.
///
/// Corresponds to the `sysroot.bls-append-except-default` ostree config key.
#[serde(skip_serializing_if = "Option::is_none")]
pub bls_append_except_default: Option<String>,
}
impl RepoOptions {
/// Returns an iterator of (key, value) tuples for ostree repo configuration.
///
/// Each tuple represents an ostree config key and its value, suitable for
/// passing to `ostree config set`.
pub fn to_config_tuples(&self) -> impl Iterator<Item = (&'static str, &str)> {
self.bls_append_except_default
.as_ref()
.map(|v| ("sysroot.bls-append-except-default", v.as_str()))
.into_iter()
}
}

View File

@@ -102,9 +102,16 @@ pub(crate) fn test_bootc_install_config() -> Result<()> {
}
pub(crate) fn test_bootc_install_config_all() -> Result<()> {
#[derive(Deserialize)]
#[serde(rename_all = "kebab-case")]
struct TestOstreeConfig {
bls_append_except_default: Option<String>,
}
#[derive(Deserialize)]
struct TestInstallConfig {
kargs: Vec<String>,
ostree: Option<TestOstreeConfig>,
}
let config_d = std::path::Path::new("/run/bootc/install/");
@@ -113,6 +120,8 @@ pub(crate) fn test_bootc_install_config_all() -> Result<()> {
let content = indoc! {r#"
[install]
kargs = ["karg1=1", "karg2=2"]
[install.ostree]
bls-append-except-default = "grub_users=\"\""
"#};
std::fs::write(&test_toml_path, content)?;
defer! {
@@ -124,6 +133,13 @@ pub(crate) fn test_bootc_install_config_all() -> Result<()> {
let config: TestInstallConfig =
serde_json::from_str(&config).context("Parsing install config")?;
assert_eq! {config.kargs, vec!["karg1=1".to_string(), "karg2=2".to_string(), "localtestkarg=somevalue".to_string(), "otherlocalkarg=42".to_string()]};
assert_eq!(
config
.ostree
.as_ref()
.and_then(|o| o.bls_append_except_default.as_deref()),
Some("grub_users=\"\"")
);
Ok(())
}