Skip to content

Commit b901498

Browse files
joelcapitaojbtrystram
authored andcommitted
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: #1710 Signed-off-by: Joel Capitao <jcapitao@redhat.com> Co-authored-by: Jean-Baptiste Trystram <jbtrystram@redhat.com> Assisted-by: Claude (Sonnet 4)
1 parent c68e2b4 commit b901498

6 files changed

Lines changed: 141 additions & 2 deletions

File tree

crates/lib/src/install.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,21 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result
795795
crate::lsm::ensure_dir_labeled(rootfs_dir, "boot", None, 0o755.into(), sepolicy)?;
796796
}
797797

798-
for (k, v) in DEFAULT_REPO_CONFIG.iter() {
798+
// Build the list of ostree repo config options: defaults + install config
799+
let ostree_opts = state
800+
.install_config
801+
.as_ref()
802+
.and_then(|c| c.ostree.as_ref())
803+
.into_iter()
804+
.flat_map(|o| o.to_config_tuples());
805+
806+
let repo_config: Vec<_> = DEFAULT_REPO_CONFIG
807+
.iter()
808+
.copied()
809+
.chain(ostree_opts)
810+
.collect();
811+
812+
for (k, v) in repo_config.iter() {
799813
Command::new("ostree")
800814
.args(["config", "--repo", "ostree/repo", "set", k, v])
801815
.cwd_dir(rootfs_dir.try_clone()?)

crates/lib/src/install/config.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ pub(crate) struct BasicFilesystems {
5858
// pub(crate) esp: Option<FilesystemCustomization>,
5959
}
6060

61+
/// Configuration for ostree repository
62+
pub(crate) type OstreeRepoOpts = ostree_ext::repo_options::RepoOptions;
63+
6164
/// The serialized [install] section
6265
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6366
#[serde(rename = "install", rename_all = "kebab-case", deny_unknown_fields)]
@@ -73,6 +76,8 @@ pub(crate) struct InstallConfiguration {
7376
pub(crate) kargs: Option<Vec<String>>,
7477
/// Supported architectures for this configuration
7578
pub(crate) match_architectures: Option<Vec<String>>,
79+
/// Ostree repository configuration
80+
pub(crate) ostree: Option<OstreeRepoOpts>,
7681
}
7782

7883
fn merge_basic<T>(s: &mut Option<T>, o: Option<T>, _env: &EnvProperties) {
@@ -119,6 +124,17 @@ impl Mergeable for BasicFilesystems {
119124
}
120125
}
121126

127+
impl Mergeable for OstreeRepoOpts {
128+
/// Apply any values in other, overriding any existing values in `self`.
129+
fn merge(&mut self, other: Self, env: &EnvProperties) {
130+
merge_basic(
131+
&mut self.bls_append_except_default,
132+
other.bls_append_except_default,
133+
env,
134+
)
135+
}
136+
}
137+
122138
impl Mergeable for InstallConfiguration {
123139
/// Apply any values in other, overriding any existing values in `self`.
124140
fn merge(&mut self, other: Self, env: &EnvProperties) {
@@ -133,6 +149,7 @@ impl Mergeable for InstallConfiguration {
133149
#[cfg(feature = "install-to-disk")]
134150
merge_basic(&mut self.block, other.block, env);
135151
self.filesystem.merge(other.filesystem, env);
152+
self.ostree.merge(other.ostree, env);
136153
if let Some(other_kargs) = other.kargs {
137154
self.kargs
138155
.get_or_insert_with(Default::default)
@@ -572,4 +589,54 @@ root-fs-type = "xfs"
572589
)
573590
);
574591
}
592+
593+
#[test]
594+
fn test_parse_ostree() {
595+
let env = EnvProperties {
596+
sys_arch: "x86_64".to_string(),
597+
};
598+
599+
// Table-driven test cases for parsing bls-append-except-default
600+
let parse_cases = [
601+
("console=ttyS0", "console=ttyS0"),
602+
("console=ttyS0,115200n8", "console=ttyS0,115200n8"),
603+
("rd.lvm.lv=vg/root", "rd.lvm.lv=vg/root"),
604+
];
605+
for (input, expected) in parse_cases {
606+
let toml_str = format!(
607+
r#"[install.ostree]
608+
bls-append-except-default = "{input}"
609+
"#
610+
);
611+
let c: InstallConfigurationToplevel = toml::from_str(&toml_str).unwrap();
612+
assert_eq!(
613+
c.install
614+
.unwrap()
615+
.ostree
616+
.unwrap()
617+
.bls_append_except_default
618+
.unwrap(),
619+
expected
620+
);
621+
}
622+
623+
// Test merging: other config should override original
624+
let mut install: InstallConfiguration = toml::from_str(
625+
r#"[ostree]
626+
bls-append-except-default = "console=ttyS0"
627+
"#,
628+
)
629+
.unwrap();
630+
let other = InstallConfiguration {
631+
ostree: Some(OstreeRepoOpts {
632+
bls_append_except_default: Some("console=tty0".to_string()),
633+
}),
634+
..Default::default()
635+
};
636+
install.merge(other, &env);
637+
assert_eq!(
638+
install.ostree.unwrap().bls_append_except_default.unwrap(),
639+
"console=tty0"
640+
);
641+
}
575642
}

crates/ostree-ext/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub mod ostree_prepareroot;
4747
pub mod refescape;
4848
#[doc(hidden)]
4949
pub mod repair;
50+
pub mod repo_options;
5051
pub mod sysroot;
5152
pub mod tar;
5253
pub mod tokio_util;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//! Configuration options for an ostree repository
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
/// Configuration options for an ostree repository.
6+
///
7+
/// This struct represents configurable options for an ostree repository
8+
/// that can be set via the `ostree config set` command.
9+
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
10+
#[serde(rename_all = "kebab-case", default)]
11+
pub struct RepoOptions {
12+
/// Boot Loader Spec entries that should append arguments only for non-default entries.
13+
///
14+
/// Corresponds to the `sysroot.bls-append-except-default` ostree config key.
15+
#[serde(skip_serializing_if = "Option::is_none")]
16+
pub bls_append_except_default: Option<String>,
17+
}
18+
19+
impl RepoOptions {
20+
/// Returns an iterator of (key, value) tuples for ostree repo configuration.
21+
///
22+
/// Each tuple represents an ostree config key and its value, suitable for
23+
/// passing to `ostree config set`.
24+
pub fn to_config_tuples(&self) -> impl Iterator<Item = (&'static str, &str)> {
25+
self.bls_append_except_default
26+
.as_ref()
27+
.map(|v| ("sysroot.bls-append-except-default", v.as_str()))
28+
.into_iter()
29+
}
30+
}

crates/tests-integration/src/container.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,16 @@ pub(crate) fn test_bootc_install_config() -> Result<()> {
102102
}
103103

104104
pub(crate) fn test_bootc_install_config_all() -> Result<()> {
105+
#[derive(Deserialize)]
106+
#[serde(rename_all = "kebab-case")]
107+
struct TestOstreeConfig {
108+
bls_append_except_default: Option<String>,
109+
}
110+
105111
#[derive(Deserialize)]
106112
struct TestInstallConfig {
107113
kargs: Vec<String>,
114+
ostree: Option<TestOstreeConfig>,
108115
}
109116

110117
let config_d = std::path::Path::new("/run/bootc/install/");
@@ -113,6 +120,8 @@ pub(crate) fn test_bootc_install_config_all() -> Result<()> {
113120
let content = indoc! {r#"
114121
[install]
115122
kargs = ["karg1=1", "karg2=2"]
123+
[install.ostree]
124+
bls-append-except-default = "grub_users=\"\""
116125
"#};
117126
std::fs::write(&test_toml_path, content)?;
118127
defer! {
@@ -124,6 +133,13 @@ pub(crate) fn test_bootc_install_config_all() -> Result<()> {
124133
let config: TestInstallConfig =
125134
serde_json::from_str(&config).context("Parsing install config")?;
126135
assert_eq! {config.kargs, vec!["karg1=1".to_string(), "karg2=2".to_string(), "localtestkarg=somevalue".to_string(), "otherlocalkarg=42".to_string()]};
136+
assert_eq!(
137+
config
138+
.ostree
139+
.as_ref()
140+
.and_then(|o| o.bls_append_except_default.as_deref()),
141+
Some("grub_users=\"\"")
142+
);
127143
Ok(())
128144
}
129145

docs/src/man/bootc-install-config.5.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ that can be overridden in a derived container image.
1616

1717
This is the only defined toplevel table.
1818

19-
The `install` section supports two subfields:
19+
The `install` section supports these subfields:
2020

2121
- `block`: An array of supported `to-disk` backends enabled by this base container image;
2222
if not specified, this will just be `direct`. The only other supported value is `tpm2-luks`.
2323
The first value specified will be the default. To enable both, use `block = ["direct", "tpm2-luks"]`.
2424
- `filesystem`: See below.
2525
- `kargs`: An array of strings; this will be appended to the set of kernel arguments.
2626
- `match_architectures`: An array of strings; this filters the install config.
27+
- `ostree`: See below.
2728

2829
# filesystem
2930

@@ -37,13 +38,23 @@ There is one valid field:
3738

3839
`type`: This can be any basic Linux filesystem with a `mkfs.$fstype`. For example, `ext4`, `xfs`, etc.
3940

41+
# ostree
42+
43+
Configuration options for the ostree repository. There is one valid field:
44+
45+
- `bls-append-except-default`: A string of kernel arguments that will be appended to
46+
Boot Loader Spec entries, except for the default entry. This is useful for configuring
47+
arguments that should only apply to non-default deployments.
48+
4049
# Examples
4150

4251
```toml
4352
[install.filesystem.root]
4453
type = "xfs"
4554
[install]
4655
kargs = ["nosmt", "console=tty0"]
56+
[install.ostree]
57+
bls-append-except-default = 'grub_users=""'
4758
```
4859

4960
# SEE ALSO

0 commit comments

Comments
 (0)