Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions crates/lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::collections::HashMap;
use std::io::Write;
use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::str::FromStr;
Expand Down Expand Up @@ -453,6 +453,13 @@ pub(crate) struct InstallPrintConfigurationOpts {
/// Print configuration that is usually handled internally, like kargs.
#[clap(long)]
pub(crate) all: bool,

/// Set an alternative root filesystem.
///
/// This can be used as part of a multi-stage build operation to detect
/// the desired configuration before executing code from a target container image.
#[clap(long, default_value = "/")]
pub(crate) sysroot: PathBuf,
}

/// Global state captured from the container.
Expand Down Expand Up @@ -742,12 +749,19 @@ impl SourceInfo {
}

pub(crate) fn print_configuration(opts: InstallPrintConfigurationOpts) -> Result<()> {
let mut install_config = config::load_config()?.unwrap_or_default();
let stdout = std::io::stdout().lock();
print_configuration_to_writer(opts, stdout)
}

fn print_configuration_to_writer<W: Write>(
opts: InstallPrintConfigurationOpts,
writer: W,
) -> Result<()> {
let mut install_config = config::load_config_at(&opts.sysroot)?.unwrap_or_default();
if !opts.all {
install_config.filter_to_external();
}
let stdout = std::io::stdout().lock();
anyhow::Ok(install_config.to_canon_json_writer(stdout)?)
anyhow::Ok(install_config.to_canon_json_writer(writer)?)
}

#[context("Creating ostree deployment")]
Expand Down Expand Up @@ -2517,6 +2531,8 @@ pub(crate) async fn install_finalize(target: &Utf8Path) -> Result<()> {
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;

#[test]
fn install_opts_serializable() {
Expand Down Expand Up @@ -2721,4 +2737,46 @@ UUID=boot-uuid /boot ext4 defaults 0 0

Ok(())
}

#[test]
fn test_print_configuration_with_root_dir() -> Result<()> {
use crate::install::config::{
Filesystem, InstallConfiguration, InstallConfigurationToplevel,
};

let temp_dir = tempdir()?;
let root_path = temp_dir.path();

let config_dir = root_path.join("etc/bootc/install");
fs::create_dir_all(&config_dir)?;
let config_path = config_dir.join("10-install.toml");

let test_config = InstallConfigurationToplevel {
install: Some(InstallConfiguration {
root_fs_type: Some(Filesystem::Xfs),
kargs: Some(vec!["quiet".to_string(), "karg2=2".to_string()]),
..Default::default()
}),
};
let toml_content = toml::to_string(&test_config)?;
fs::write(config_path, toml_content)?;

let opts = InstallPrintConfigurationOpts {
sysroot: root_path.to_owned(),
all: true,
};

let mut buffer = Vec::new();
print_configuration_to_writer(opts, &mut buffer)?;

let output_json = String::from_utf8(buffer)?;
let output_config: crate::install::config::InstallConfiguration =
serde_json::from_str(&output_json)?;

let install_config = test_config.install.unwrap();
assert_eq!(install_config.kargs, output_config.kargs);
assert_eq!(install_config.root_fs_type, output_config.root_fs_type);

Ok(())
}
}
14 changes: 12 additions & 2 deletions crates/lib/src/install/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use anyhow::{Context, Result};
use clap::ValueEnum;
use fn_error_context::context;
use serde::{Deserialize, Serialize};
use std::path::Path;

#[cfg(feature = "install-to-disk")]
use super::baseline::BlockSetup;
Expand Down Expand Up @@ -191,11 +192,20 @@ impl InstallConfiguration {
#[context("Loading configuration")]
/// Load the install configuration, merging all found configuration files.
pub(crate) fn load_config() -> Result<Option<InstallConfiguration>> {
load_config_at("/")
}

pub(crate) fn load_config_at(root_dir: impl AsRef<Path>) -> Result<Option<InstallConfiguration>> {
let env = EnvProperties {
sys_arch: std::env::consts::ARCH.to_string(),
};
const SYSTEMD_CONVENTIONAL_BASES: &[&str] = &["/usr/lib", "/usr/local/lib", "/etc", "/run"];
let fragments = liboverdrop::scan(SYSTEMD_CONVENTIONAL_BASES, "bootc/install", &["toml"], true);
let root_dir = root_dir.as_ref();
const SYSTEMD_CONVENTIONAL_BASES: &[&str] = &["usr/lib", "usr/local/lib", "etc", "run"];
let systemd_conventional_bases = SYSTEMD_CONVENTIONAL_BASES
.iter()
.map(|v| root_dir.join(v))
.collect::<Vec<_>>();
let fragments = liboverdrop::scan(systemd_conventional_bases, "bootc/install", &["toml"], true);
let mut config: Option<InstallConfiguration> = None;
for (_name, path) in fragments {
let buf = std::fs::read_to_string(&path)?;
Expand Down
6 changes: 6 additions & 0 deletions docs/src/man/bootc-install-print-configuration.8.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ string-valued filesystem name suitable for passing to `mkfs.\$type`.

Print all configuration

**--sysroot**=*SYSROOT*

Set an alternative root filesystem

Default: /

<!-- END GENERATED OPTIONS -->

# VERSION
Expand Down
Loading