Skip to content

Commit bf04398

Browse files
committed
cli: add install print-configuration --root-dir
We would like to only inspect a container image with {bootc,}image-builder and not actually run the container. One reason is (too much?) paranoia, i.e. we want to eventually support bootc containers coming from the users that get passed into the service and not having to run anything on the container initially to generate the osbuild manifest minimizes the risk. So to still get the require parameters like preferred rootfs or kargs we would like to run our own bootc and then pass ``` bootc install print-configuration --root-dir /path/to/mounted/cnt ``` to generate the manifest. The actual build will still run the `boots install to-filesystem` from the container. But that step happens in an isolated instance that is destroyed after each build (we already do this for package based image builds as users can also inject custom content/rpms here). This PR implements this new "--root-dir" option. It also tweaks print_configuration to make it easier to test. With that we could drop parts of the tests for PR#1820 from the container.rs and move them in here.
1 parent 67a8df2 commit bf04398

File tree

2 files changed

+71
-5
lines changed

2 files changed

+71
-5
lines changed

crates/lib/src/install.rs

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,10 @@ pub(crate) struct InstallPrintConfigurationOpts {
444444
/// Print configuration that is usually handled internally, like kargs.
445445
#[clap(long)]
446446
pub(crate) all: bool,
447+
448+
/// Set an alternative rootdir
449+
#[clap(long, default_value = "/")]
450+
pub(crate) root_dir: Option<String>,
447451
}
448452

449453
/// Global state captured from the container.
@@ -732,12 +736,20 @@ impl SourceInfo {
732736
}
733737

734738
pub(crate) fn print_configuration(opts: InstallPrintConfigurationOpts) -> Result<()> {
735-
let mut install_config = config::load_config()?.unwrap_or_default();
739+
let stdout = std::io::stdout().lock();
740+
print_configuration_to_writer(opts, stdout)
741+
}
742+
743+
fn print_configuration_to_writer<W: Write>(
744+
opts: InstallPrintConfigurationOpts,
745+
writer: W,
746+
) -> Result<()> {
747+
let root_dir = opts.root_dir.unwrap_or("/".to_string());
748+
let mut install_config = config::load_config_at(&root_dir)?.unwrap_or_default();
736749
if !opts.all {
737750
install_config.filter_to_external();
738751
}
739-
let stdout = std::io::stdout().lock();
740-
anyhow::Ok(install_config.to_canon_json_writer(stdout)?)
752+
anyhow::Ok(install_config.to_canon_json_writer(writer)?)
741753
}
742754

743755
#[context("Creating ostree deployment")]
@@ -2455,6 +2467,8 @@ pub(crate) async fn install_finalize(target: &Utf8Path) -> Result<()> {
24552467
#[cfg(test)]
24562468
mod tests {
24572469
use super::*;
2470+
use std::fs;
2471+
use tempfile::tempdir;
24582472

24592473
#[test]
24602474
fn install_opts_serializable() {
@@ -2584,4 +2598,46 @@ UUID=boot-uuid /boot ext4 defaults 0 0
25842598

25852599
Ok(())
25862600
}
2601+
2602+
#[test]
2603+
fn test_print_configuration_with_root_dir() -> Result<()> {
2604+
use crate::install::config::{
2605+
Filesystem, InstallConfiguration, InstallConfigurationToplevel,
2606+
};
2607+
2608+
let temp_dir = tempdir()?;
2609+
let root_path = temp_dir.path();
2610+
2611+
let config_dir = root_path.join("etc/bootc/install");
2612+
fs::create_dir_all(&config_dir)?;
2613+
let config_path = config_dir.join("10-install.toml");
2614+
2615+
let test_config = InstallConfigurationToplevel {
2616+
install: Some(InstallConfiguration {
2617+
root_fs_type: Some(Filesystem::Xfs),
2618+
kargs: Some(vec!["quiet".to_string(), "karg2=2".to_string()]),
2619+
..Default::default()
2620+
}),
2621+
};
2622+
let toml_content = toml::to_string(&test_config)?;
2623+
fs::write(config_path, toml_content)?;
2624+
2625+
let opts = InstallPrintConfigurationOpts {
2626+
root_dir: Some(root_path.to_str().unwrap().to_string()),
2627+
all: true,
2628+
};
2629+
2630+
let mut buffer = Vec::new();
2631+
print_configuration_to_writer(opts, &mut buffer)?;
2632+
2633+
let output_json = String::from_utf8(buffer)?;
2634+
let output_config: crate::install::config::InstallConfiguration =
2635+
serde_json::from_str(&output_json)?;
2636+
2637+
let install_config = test_config.install.unwrap();
2638+
assert_eq!(install_config.kargs, output_config.kargs);
2639+
assert_eq!(install_config.root_fs_type, output_config.root_fs_type);
2640+
2641+
Ok(())
2642+
}
25872643
}

crates/lib/src/install/config.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use anyhow::{Context, Result};
66
use clap::ValueEnum;
77
use fn_error_context::context;
88
use serde::{Deserialize, Serialize};
9+
use std::path::Path;
910

1011
#[cfg(feature = "install-to-disk")]
1112
use super::baseline::BlockSetup;
@@ -191,11 +192,20 @@ impl InstallConfiguration {
191192
#[context("Loading configuration")]
192193
/// Load the install configuration, merging all found configuration files.
193194
pub(crate) fn load_config() -> Result<Option<InstallConfiguration>> {
195+
load_config_at("/")
196+
}
197+
198+
pub(crate) fn load_config_at(root_dir: impl AsRef<Path>) -> Result<Option<InstallConfiguration>> {
194199
let env = EnvProperties {
195200
sys_arch: std::env::consts::ARCH.to_string(),
196201
};
197-
const SYSTEMD_CONVENTIONAL_BASES: &[&str] = &["/usr/lib", "/usr/local/lib", "/etc", "/run"];
198-
let fragments = liboverdrop::scan(SYSTEMD_CONVENTIONAL_BASES, "bootc/install", &["toml"], true);
202+
let root_dir = root_dir.as_ref();
203+
const SYSTEMD_CONVENTIONAL_BASES: &[&str] = &["usr/lib", "usr/local/lib", "etc", "run"];
204+
let systemd_conventional_bases = SYSTEMD_CONVENTIONAL_BASES
205+
.iter()
206+
.map(|v| root_dir.join(v))
207+
.collect::<Vec<_>>();
208+
let fragments = liboverdrop::scan(systemd_conventional_bases, "bootc/install", &["toml"], true);
199209
let mut config: Option<InstallConfiguration> = None;
200210
for (_name, path) in fragments {
201211
let buf = std::fs::read_to_string(&path)?;

0 commit comments

Comments
 (0)