Skip to content
Open
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
36 changes: 10 additions & 26 deletions crates/lib/src/bootc_composefs/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ use crate::bootc_composefs::status::get_sorted_uki_boot_entries;
use crate::composefs_consts::{TYPE1_ENT_PATH, TYPE1_ENT_PATH_STAGED};
use crate::parsers::bls_config::{BLSConfig, BLSConfigType};
use crate::parsers::grub_menuconfig::MenuEntry;
use crate::spec::ImageReference;
use crate::task::Task;
use crate::{
composefs_consts::{
Expand Down Expand Up @@ -353,14 +352,11 @@ pub(crate) fn setup_composefs_bls_boot(
// root_setup.kargs has [root=UUID=<UUID>, "rw"]
let mut cmdline_options = String::from(root_setup.kargs.join(" "));

match &state.composefs_options {
Some(opt) if opt.insecure => {
cmdline_options.push_str(&format!(" {COMPOSEFS_CMDLINE}=?{id_hex}"));
}
None | Some(..) => {
cmdline_options.push_str(&format!(" {COMPOSEFS_CMDLINE}={id_hex}"));
}
};
if state.composefs_options.insecure {
cmdline_options.push_str(&format!(" {COMPOSEFS_CMDLINE}=?{id_hex}"));
} else {
cmdline_options.push_str(&format!(" {COMPOSEFS_CMDLINE}={id_hex}"));
}

// Locate ESP partition device
let esp_part = root_setup
Expand All @@ -375,11 +371,7 @@ pub(crate) fn setup_composefs_bls_boot(
esp_part.node.clone(),
cmdline_options,
fs,
state
.composefs_options
.as_ref()
.map(|opts| opts.bootloader.clone())
.unwrap_or(Bootloader::default()),
state.composefs_options.bootloader.clone(),
)
}

Expand Down Expand Up @@ -828,10 +820,6 @@ pub(crate) fn setup_composefs_uki_boot(
}
}

let Some(cfs_opts) = &state.composefs_options else {
anyhow::bail!("ComposeFS options not found");
};

let esp_part = root_setup
.device_info
.partitions
Expand All @@ -842,9 +830,9 @@ pub(crate) fn setup_composefs_uki_boot(
(
root_setup.physical_root_path.clone(),
esp_part.node.clone(),
cfs_opts.bootloader.clone(),
cfs_opts.insecure,
cfs_opts.uki_addon.as_ref(),
state.composefs_options.bootloader.clone(),
state.composefs_options.insecure,
state.composefs_options.uki_addon.as_ref(),
)
}

Expand Down Expand Up @@ -992,11 +980,7 @@ pub(crate) fn setup_composefs_boot(
write_composefs_state(
&root_setup.physical_root_path,
id,
&ImageReference {
image: state.source.imageref.name.clone(),
transport: state.source.imageref.transport.to_string(),
signature: None,
},
&crate::spec::ImageReference::from(state.target_imgref.clone()),
false,
boot_type,
boot_digest,
Expand Down
2 changes: 1 addition & 1 deletion crates/lib/src/bootc_composefs/finalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) async fn get_etc_diff() -> Result<()> {
Ok(())
}

pub(crate) async fn composefs_native_finalize() -> Result<()> {
pub(crate) async fn composefs_backend_finalize() -> Result<()> {
let host = composefs_deployment_status().await?;

let booted_composefs = host.require_composefs_booted()?;
Expand Down
1 change: 1 addition & 0 deletions crates/lib/src/bootc_composefs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub(crate) mod boot;
pub(crate) mod finalize;
pub(crate) mod repo;
pub(crate) mod rollback;
pub(crate) mod service;
pub(crate) mod state;
pub(crate) mod status;
pub(crate) mod switch;
Expand Down
2 changes: 1 addition & 1 deletion crates/lib/src/bootc_composefs/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub(crate) async fn pull_composefs_repo(
.await
.context("Pulling composefs repo")?;

tracing::info!("id: {}, verity: {}", hex::encode(id), verity.to_hex());
tracing::info!("ID: {}, Verity: {}", hex::encode(id), verity.to_hex());

let repo = open_composefs_repo(&rootfs_dir)?;
let mut fs = create_composefs_filesystem(&repo, &hex::encode(id), None)
Expand Down
22 changes: 22 additions & 0 deletions crates/lib/src/bootc_composefs/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use anyhow::{Context, Result};
use fn_error_context::context;
use std::process::Command;

use crate::composefs_consts::COMPOSEFS_FINALIZE_STAGED_SERVICE;

/// Starts the finaize staged service which will "unstage" the deployment
/// This is called before an upgrade or switch operation, as these create a staged
/// deployment
#[context("Starting finalize staged service")]
pub(crate) fn start_finalize_stated_svc() -> Result<()> {
let cmd_status = Command::new("systemctl")
.args(["start", "--quiet", COMPOSEFS_FINALIZE_STAGED_SERVICE])
.status()
.context("Starting finalize service")?;

if !cmd_status.success() {
anyhow::bail!("systemctl exited with status {cmd_status}")
}

Ok(())
}
4 changes: 3 additions & 1 deletion crates/lib/src/bootc_composefs/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ pub(crate) fn write_composefs_state(
boot_type: BootType,
boot_digest: Option<String>,
) -> Result<()> {
let state_path = root_path.join(format!("{STATE_DIR_RELATIVE}/{}", deployment_id.to_hex()));
let state_path = root_path
.join(STATE_DIR_RELATIVE)
.join(deployment_id.to_hex());

create_dir_all(state_path.join("etc"))?;

Expand Down
3 changes: 3 additions & 0 deletions crates/lib/src/bootc_composefs/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
bootc_composefs::{
boot::{setup_composefs_bls_boot, setup_composefs_uki_boot, BootSetupType, BootType},
repo::pull_composefs_repo,
service::start_finalize_stated_svc,
state::write_composefs_state,
status::composefs_deployment_status,
},
Expand Down Expand Up @@ -36,6 +37,8 @@ pub(crate) async fn switch_composefs(opts: SwitchOpts) -> Result<()> {
anyhow::bail!("Target image is undefined")
};

start_finalize_stated_svc()?;

let (repo, entries, id, fs) =
pull_composefs_repo(&target_imgref.transport, &target_imgref.image).await?;

Expand Down
5 changes: 3 additions & 2 deletions crates/lib/src/bootc_composefs/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
bootc_composefs::{
boot::{setup_composefs_bls_boot, setup_composefs_uki_boot, BootSetupType, BootType},
repo::pull_composefs_repo,
service::start_finalize_stated_svc,
state::write_composefs_state,
status::composefs_deployment_status,
},
Expand All @@ -14,12 +15,12 @@ use crate::{

#[context("Upgrading composefs")]
pub(crate) async fn upgrade_composefs(_opts: UpgradeOpts) -> Result<()> {
// TODO: IMPORTANT Have all the checks here that `bootc upgrade` has for an ostree booted system

let host = composefs_deployment_status()
.await
.context("Getting composefs deployment status")?;

start_finalize_stated_svc()?;

// TODO: IMPORTANT We need to check if any deployment is staged and get the image from that
let imgref = host
.spec
Expand Down
4 changes: 2 additions & 2 deletions crates/lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use serde::{Deserialize, Serialize};

#[cfg(feature = "composefs-backend")]
use crate::bootc_composefs::{
finalize::{composefs_native_finalize, get_etc_diff},
finalize::{composefs_backend_finalize, get_etc_diff},
rollback::composefs_rollback,
state::composefs_usr_overlay,
status::composefs_booted,
Expand Down Expand Up @@ -1544,7 +1544,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
},

#[cfg(feature = "composefs-backend")]
Opt::ComposefsFinalizeStaged => composefs_native_finalize().await,
Opt::ComposefsFinalizeStaged => composefs_backend_finalize().await,

#[cfg(feature = "composefs-backend")]
Opt::ConfigDiff => get_etc_diff().await,
Expand Down
6 changes: 4 additions & 2 deletions crates/lib/src/composefs_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ pub(crate) const COMPOSEFS_TRANSIENT_STATE_DIR: &str = "/run/composefs";
/// File created in /run/composefs to record a staged-deployment
pub(crate) const COMPOSEFS_STAGED_DEPLOYMENT_FNAME: &str = "staged-deployment";

/// Absolute path to composefs-native state directory
/// Absolute path to composefs-backend state directory
pub(crate) const STATE_DIR_ABS: &str = "/sysroot/state/deploy";
/// Relative path to composefs-native state directory. Relative to /sysroot
/// Relative path to composefs-backend state directory. Relative to /sysroot
pub(crate) const STATE_DIR_RELATIVE: &str = "state/deploy";
/// Relative path to the shared 'var' directory. Relative to /sysroot
pub(crate) const SHARED_VAR_PATH: &str = "state/os/default/var";
Expand All @@ -36,3 +36,5 @@ pub(crate) const USER_CFG_STAGED: &str = "user.cfg.staged";
/// This is relative to the boot/efi directory
pub(crate) const TYPE1_ENT_PATH: &str = "loader/entries";
pub(crate) const TYPE1_ENT_PATH_STAGED: &str = "loader/entries.staged";

pub(crate) const COMPOSEFS_FINALIZE_STAGED_SERVICE: &str = "composefs-finalize-staged.service";
65 changes: 40 additions & 25 deletions crates/lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,21 @@ pub(crate) struct InstallConfigOpts {

#[derive(Debug, Clone, clap::Parser, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct InstallComposefsOpts {
/// If true, composefs backend is used, else ostree backend is used
#[clap(long, default_value_t)]
#[serde(default)]
pub(crate) composefs_backend: bool,

/// Make fs-verity validation optional in case the filesystem doesn't support it
#[clap(long, default_value_t)]
#[serde(default)]
pub(crate) insecure: bool,

/// The bootloader to use.
/// Currently supported:
///
/// - systemd-boot
/// - grub
#[clap(long, default_value_t)]
#[serde(default)]
pub(crate) bootloader: Bootloader,
Expand Down Expand Up @@ -288,11 +299,6 @@ pub(crate) struct InstallToDiskOpts {
#[serde(default)]
pub(crate) via_loopback: bool,

#[clap(long)]
#[serde(default)]
#[cfg(feature = "composefs-backend")]
pub(crate) composefs_native: bool,

#[clap(flatten)]
#[serde(flatten)]
#[cfg(feature = "composefs-backend")]
Expand Down Expand Up @@ -372,6 +378,10 @@ pub(crate) struct InstallToFilesystemOpts {

#[clap(flatten)]
pub(crate) config_opts: InstallConfigOpts,

#[cfg(feature = "composefs-backend")]
#[clap(flatten)]
pub(crate) compoesfs_opts: InstallComposefsOpts,
}

#[derive(Debug, Clone, clap::Parser, PartialEq, Eq)]
Expand Down Expand Up @@ -403,6 +413,10 @@ pub(crate) struct InstallToExistingRootOpts {
/// via e.g. `-v /:/target`.
#[clap(default_value = ALONGSIDE_ROOT_MOUNT)]
pub(crate) root_path: Utf8PathBuf,

#[cfg(feature = "composefs-backend")]
#[clap(flatten)]
pub(crate) composefs_opts: InstallComposefsOpts,
}

/// Global state captured from the container.
Expand Down Expand Up @@ -438,9 +452,9 @@ pub(crate) struct State {
pub(crate) container_root: Dir,
pub(crate) tempdir: TempDir,

// If Some, then --composefs_native is passed
// If Some, then --composefs-backend is passed
#[cfg(feature = "composefs-backend")]
pub(crate) composefs_options: Option<InstallComposefsOpts>,
pub(crate) composefs_options: InstallComposefsOpts,
}

impl State {
Expand Down Expand Up @@ -570,10 +584,10 @@ impl FromStr for MountSpec {
#[cfg(all(feature = "install-to-disk", feature = "composefs-backend"))]
impl InstallToDiskOpts {
pub(crate) fn validate(&self) -> Result<()> {
if !self.composefs_native {
// Reject using --insecure without --composefs
if !self.composefs_opts.composefs_backend {
// Reject using --insecure without --composefs-backend
if self.composefs_opts.insecure != false {
anyhow::bail!("--insecure must not be provided without --composefs");
anyhow::bail!("--insecure must not be provided without --composefs-backend");
}
}

Expand Down Expand Up @@ -1226,7 +1240,7 @@ async fn prepare_install(
config_opts: InstallConfigOpts,
source_opts: InstallSourceOpts,
target_opts: InstallTargetOpts,
_composefs_opts: Option<InstallComposefsOpts>,
#[cfg(feature = "composefs-backend")] composefs_options: InstallComposefsOpts,
) -> Result<Arc<State>> {
tracing::trace!("Preparing install");
let rootfs = cap_std::fs::Dir::open_ambient_dir("/", cap_std::ambient_authority())
Expand Down Expand Up @@ -1372,7 +1386,7 @@ async fn prepare_install(
tempdir,
host_is_container,
#[cfg(feature = "composefs-backend")]
composefs_options: _composefs_opts,
composefs_options,
});

Ok(state)
Expand Down Expand Up @@ -1537,7 +1551,7 @@ async fn install_to_filesystem_impl(
}

#[cfg(feature = "composefs-backend")]
if state.composefs_options.is_some() {
if state.composefs_options.composefs_backend {
// Load a fd for the mounted target physical root

let (id, verity) = initialize_composefs_repository(state, rootfs).await?;
Expand Down Expand Up @@ -1614,21 +1628,12 @@ pub(crate) async fn install_to_disk(mut opts: InstallToDiskOpts) -> Result<()> {
anyhow::bail!("Not a block device: {}", block_opts.device);
}

#[cfg(feature = "composefs-backend")]
let composefs_arg = if opts.composefs_native {
Some(opts.composefs_opts)
} else {
None
};

#[cfg(not(feature = "composefs-backend"))]
let composefs_arg = None;

let state = prepare_install(
opts.config_opts,
opts.source_opts,
opts.target_opts,
composefs_arg,
#[cfg(feature = "composefs-backend")]
opts.composefs_opts,
)
.await?;

Expand Down Expand Up @@ -1861,7 +1866,15 @@ pub(crate) async fn install_to_filesystem(
// IMPORTANT: and hence anything that is done before MUST BE IDEMPOTENT.
// IMPORTANT: In practice, we should only be gathering information before this point,
// IMPORTANT: and not performing any mutations at all.
let state = prepare_install(opts.config_opts, opts.source_opts, opts.target_opts, None).await?;
let state = prepare_install(
opts.config_opts,
opts.source_opts,
opts.target_opts,
#[cfg(feature = "composefs-backend")]
opts.compoesfs_opts,
)
.await?;

// And the last bit of state here is the fsopts, which we also destructure now.
let mut fsopts = opts.filesystem_opts;

Expand Down Expand Up @@ -2129,6 +2142,8 @@ pub(crate) async fn install_to_existing_root(opts: InstallToExistingRootOpts) ->
source_opts: opts.source_opts,
target_opts: opts.target_opts,
config_opts: opts.config_opts,
#[cfg(feature = "composefs-backend")]
compoesfs_opts: opts.composefs_opts,
};

install_to_filesystem(opts, true, cleanup).await
Expand Down
2 changes: 1 addition & 1 deletion tmt/tests/examples/bootc-uki/install-grub.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ podman run \
--security-opt label=type:unconfined_t \
"${IMAGE}" \
bootc install to-disk \
--composefs-native \
--composefs-backend \
--boot=uki \
--source-imgref="containers-storage:${IMAGE}" \
--target-imgref="${IMAGE}" \
Expand Down
2 changes: 1 addition & 1 deletion tmt/tests/examples/bootc-uki/install-systemd-boot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ podman run \
--security-opt label=type:unconfined_t \
"${IMAGE}" \
bootc install to-disk \
--composefs-native \
--composefs-backend \
--boot=uki \
--source-imgref="containers-storage:${IMAGE}" \
--target-imgref="${IMAGE}" \
Expand Down