Skip to content
Draft
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
13 changes: 13 additions & 0 deletions clippy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,16 @@ disallowed-methods = [
# https://github.com/rust-lang/rust-clippy/issues/13434#issuecomment-2484292914
{ path = "str::len", reason = "use <str>.as_bytes().len() instead" }
]

# anstream's print macros aren't covered by clippy::print_stdout/print_stderr,
# which crates/lib denies. Only crates/lib denies this lint, and it's the
# only user of these macros.
disallowed-macros = [
{ path = "anstream::print", reason = "use ProgressWriter::message() or an explicit writer" },
{ path = "anstream::println", reason = "use ProgressWriter::message() or an explicit writer" },
{ path = "anstream::eprint", reason = "use ProgressWriter::message() or an explicit writer" },
{ path = "anstream::eprintln", reason = "use ProgressWriter::message() or an explicit writer" },
]

# Printing from tests is fine; see the print_stdout deny in crates/lib
allow-print-in-tests = true
3 changes: 3 additions & 0 deletions crates/lib/src/bootc_composefs/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2120,6 +2120,7 @@ pub(crate) async fn setup_composefs_boot(
crate::bootloader::install_via_zipl(
&root_setup.device_info.require_single_root()?,
boot_uuid,
&state.prog,
)?;
} else if matches!(
postfetch.detected_bootloader,
Expand All @@ -2141,6 +2142,7 @@ pub(crate) async fn setup_composefs_boot(
&state.config_opts,
Some(chroot_target),
Some(bind_boot_path.as_path()),
&state.prog,
)?;

// FIXME: Remove this hack once we have support in bootupd
Expand Down Expand Up @@ -2192,6 +2194,7 @@ pub(crate) async fn setup_composefs_boot(
&mounted_root,
&state.config_opts,
get_secureboot_keys(mounted_root.dir(), BOOTC_AUTOENROLL_PATH)?,
&state.prog,
)
})?;
}
Expand Down
3 changes: 2 additions & 1 deletion crates/lib/src/bootc_composefs/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use crate::{
TYPE1_ENT_PATH, TYPE1_ENT_PATH_STAGED, USER_CFG_STAGED,
},
parsers::bls_config::{BLSConfigType, EFIKey, parse_bls_config},
progress_jsonl::ProgressWriter,
spec::{BootEntry, BootloaderKind, DeploymentEntry},
status::Slot,
store::{BootedComposefs, Storage},
Expand Down Expand Up @@ -247,7 +248,7 @@ pub(crate) async fn delete_composefs_deployment(

// Unqueue rollback. This makes it easier to delete boot entries later on
if matches!(depl_to_del.ty, Some(Slot::Rollback)) && host.status.rollback_queued {
composefs_rollback(storage, booted_cfs).await?;
composefs_rollback(storage, booted_cfs, &ProgressWriter::default()).await?;
}

let kind = if depl_to_del.pinned {
Expand Down
6 changes: 3 additions & 3 deletions crates/lib/src/bootc_composefs/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
//! composefs-rs (`composefs::progress`) reports progress via a synchronous,
//! `Send + Sync` callback trait invoked directly from whatever task is
//! driving the pull. That's a poor fit for [`crate::progress_jsonl::ProgressWriter`],
//! whose API is `async`. We bridge the two by handing composefs-rs a trivial
//! whose writes can block on a slow reader. We bridge the two by handing composefs-rs a trivial
//! reporter that forwards every [`ProgressEvent`] over an unbounded channel,
//! and processing that channel from a concurrently spawned Tokio task which
//! owns the `indicatif` state and the `ProgressWriter`. This mirrors the
Expand Down Expand Up @@ -254,9 +254,9 @@ async fn drive_progress(
subtasks,
};
if required {
prog.send(event).await;
prog.send(event);
} else if any_activity {
prog.send_lossy(event).await;
prog.send_lossy(event);
}
}

Expand Down
8 changes: 5 additions & 3 deletions crates/lib/src/bootc_composefs/rollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::composefs_consts::{
COMPOSEFS_STAGED_DEPLOYMENT_FNAME, COMPOSEFS_TRANSIENT_STATE_DIR, TYPE1_ENT_PATH_STAGED,
};
use crate::deploy::ROLLBACK_JOURNAL_ID;
use crate::progress_jsonl::ProgressWriter;
use crate::spec::{Bootloader, BootloaderKind, Host};
use crate::store::{BootedComposefs, Storage};
use crate::{
Expand Down Expand Up @@ -215,6 +216,7 @@ fn rollback_composefs_entries(host: &Host, boot_dir: &Dir, bootloader: Bootloade
pub(crate) async fn composefs_rollback(
storage: &Storage,
booted_cfs: &BootedComposefs,
prog: &ProgressWriter,
) -> Result<()> {
const COMPOSEFS_ROLLBACK_JOURNAL_ID: &str = "6f5e4d3c2b1a0f9e8d7c6b5a4e3d2c1b0";

Expand All @@ -237,7 +239,7 @@ pub(crate) async fn composefs_rollback(

let reverting = new_spec.boot_order == BootOrder::Default;
if reverting {
println!("notice: Reverting queued rollback state");
prog.info("notice: Reverting queued rollback state");
}

let rollback_status = host
Expand Down Expand Up @@ -269,9 +271,9 @@ pub(crate) async fn composefs_rollback(
}

if reverting {
println!("Next boot: current deployment");
prog.info("Next boot: current deployment");
} else {
println!("Next boot: rollback deployment");
prog.info("Next boot: rollback deployment");
}

Ok(())
Expand Down
12 changes: 7 additions & 5 deletions crates/lib/src/bootc_composefs/soft_reboot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
status::{build_composefs_karg, get_composefs_status},
},
cli::SoftRebootMode,
progress_jsonl::ProgressWriter,
store::{BootedComposefs, Storage},
};
use anyhow::{Context, Result};
Expand All @@ -23,7 +24,7 @@ use std::{fs::create_dir_all, os::unix::process::CommandExt, path::PathBuf, proc
const NEXTROOT: &str = "/run/nextroot";

#[context("Resetting soft reboot state")]
pub(crate) fn reset_soft_reboot() -> Result<()> {
pub(crate) fn reset_soft_reboot(prog: &ProgressWriter) -> Result<()> {
// NOTE: By default bootc runs in an unshared mount namespace;
// this sets up our /runto actually be the same as the host/run
// so the umount (at the end of this function) actually affects the host
Expand All @@ -40,7 +41,7 @@ pub(crate) fn reset_soft_reboot() -> Result<()> {

let Some(nextroot) = nextroot else {
tracing::debug!("Nextroot does not exist");
println!("No deployment staged for soft rebooting");
prog.info("No deployment staged for soft rebooting");
return Ok(());
};

Expand All @@ -50,13 +51,13 @@ pub(crate) fn reset_soft_reboot() -> Result<()> {

if !nextroot_mounted {
tracing::debug!("Nextroot is not a mountpoint");
println!("No deployment staged for soft rebooting");
prog.info("No deployment staged for soft rebooting");
return Ok(());
}

unmount(NEXTROOT, UnmountFlags::DETACH).context("Unmounting nextroot")?;

println!("Cleared soft reboot queued state");
prog.info("Cleared soft reboot queued state");

Ok(())
}
Expand All @@ -70,6 +71,7 @@ pub(crate) async fn prepare_soft_reboot_composefs(
deployment_id: Option<&str>,
soft_reboot_mode: SoftRebootMode,
reboot: bool,
prog: &ProgressWriter,
) -> Result<()> {
if !systemd_has_soft_reboot() {
anyhow::bail!("System does not support soft reboots")
Expand Down Expand Up @@ -133,7 +135,7 @@ pub(crate) async fn prepare_soft_reboot_composefs(

setup_root(args)?;

println!("Soft reboot setup complete");
prog.info("Soft reboot setup complete");

if reboot {
// Replacing the current process should be fine as we restart userspace anyway
Expand Down
15 changes: 11 additions & 4 deletions crates/lib/src/bootc_composefs/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use crate::bootc_composefs::status::{
ComposefsCmdline, StagedDeployment, get_sorted_type1_boot_entries,
};
use crate::parsers::bls_config::{BLSConfigType, EFIKey};
use crate::progress_jsonl::ProgressWriter;
use crate::store::{BootedComposefs, Storage};
use crate::{
composefs_consts::{
Expand Down Expand Up @@ -328,10 +329,13 @@ pub(crate) async fn write_composefs_state(
Ok(())
}

pub(crate) fn composefs_usr_overlay(access_mode: FilesystemOverlayAccessMode) -> Result<()> {
pub(crate) fn composefs_usr_overlay(
access_mode: FilesystemOverlayAccessMode,
prog: &ProgressWriter,
) -> Result<()> {
let status = get_composefs_usr_overlay_status()?;
if status.is_some() {
println!("An overlayfs is already mounted on /usr");
prog.info("An overlayfs is already mounted on /usr");
return Ok(());
}

Expand All @@ -345,8 +349,11 @@ pub(crate) fn composefs_usr_overlay(access_mode: FilesystemOverlayAccessMode) ->
let overlay_fd = overlay_transient(usr.as_fd(), "transient", mount_attr_flags)?;
mount_at_wrapper(overlay_fd, &usr, ".").context("Attaching /usr overlay")?;

println!("A {} overlayfs is now mounted on /usr", access_mode);
println!("All changes there will be discarded on reboot.");
prog.info(format!(
"A {} overlayfs is now mounted on /usr",
access_mode
));
prog.info("All changes there will be discarded on reboot.");

Ok(())
}
Expand Down
8 changes: 6 additions & 2 deletions crates/lib/src/bootc_composefs/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ pub(crate) async fn switch_composefs(
};

if new_spec == host.spec {
println!("Image specification is unchanged.");
do_upgrade_opts
.prog
.info("Image specification is unchanged.");
if opts.apply && host.status.staged.is_some() {
crate::reboot::reboot()?;
}
Expand Down Expand Up @@ -106,7 +108,9 @@ pub(crate) async fn switch_composefs(

match action {
UpdateAction::Skip => {
println!("No changes in image: {target_imgref:#}");
do_upgrade_opts
.prog
.info(format!("No changes in image: {target_imgref:#}"));
return Ok(());
}

Expand Down
18 changes: 13 additions & 5 deletions crates/lib/src/bootc_composefs/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ async fn apply_upgrade(
Some(depl_id),
soft_reboot_mode,
opts.apply,
&opts.prog,
)
.await;
};
Expand Down Expand Up @@ -423,8 +424,9 @@ pub(crate) async fn apply_upgrade_from_downloaded(

// Staged deployment exists, but it will be finalized
if !staged.download_only {
println!("Staged deployment is present and not in download only mode.");
println!("Use `bootc update --apply` to apply the update.");
let prog = &do_upgrade_opts.prog;
prog.info("Staged deployment is present and not in download only mode.");
prog.info("Use `bootc update --apply` to apply the update.");
return Ok(());
}

Expand Down Expand Up @@ -541,7 +543,9 @@ pub(crate) async fn upgrade_composefs(
return crate::reboot::reboot();
}

println!("Update already staged. To apply update run `bootc update --apply`");
do_upgrade_opts
.prog
.info("Update already staged. To apply update run `bootc update --apply`");

return Ok(());
}
Expand All @@ -566,7 +570,9 @@ pub(crate) async fn upgrade_composefs(

match action {
UpdateAction::Skip => {
println!("No changes in staged image: {booted_imgref:#}");
do_upgrade_opts
.prog
.info(format!("No changes in staged image: {booted_imgref:#}"));
return Ok(());
}

Expand Down Expand Up @@ -598,7 +604,9 @@ pub(crate) async fn upgrade_composefs(

match action {
UpdateAction::Skip => {
println!("No changes in: {booted_imgref:#}");
do_upgrade_opts
.prog
.info(format!("No changes in: {booted_imgref:#}"));
return Ok(());
}

Expand Down
19 changes: 13 additions & 6 deletions crates/lib/src/bootloader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use fn_error_context::context;
use bootc_mount as mount;

use crate::bootc_composefs::boot::{MountedImageRoot, SecurebootKeys};
use crate::progress_jsonl::ProgressWriter;
use crate::utils;

/// The name of the mountpoint for efi (as a subdirectory of /boot, or at the toplevel)
Expand Down Expand Up @@ -151,6 +152,7 @@ pub(crate) fn install_via_bootupd(
configopts: &crate::install::InstallConfigOpts,
chroot_target: Option<&Utf8Path>,
bind_boot_path: Option<&Utf8Path>,
prog: &ProgressWriter,
) -> Result<()> {
let verbose = std::env::var_os("BOOTC_BOOTLOADER_DEBUG").map(|_| "-vvvv");
// bootc defaults to only targeting the platform boot method.
Expand All @@ -167,7 +169,7 @@ pub(crate) fn install_via_bootupd(
"/"
};

println!("Installing bootloader via bootupd");
prog.info("Installing bootloader via bootupd");

// Build the bootupctl arguments
let mut bootupd_args: Vec<&str> = vec!["backend", "install"];
Expand Down Expand Up @@ -268,8 +270,9 @@ pub(crate) fn install_systemd_boot(
prepared_root: &MountedImageRoot,
configopts: &crate::install::InstallConfigOpts,
autoenroll: Option<SecurebootKeys>,
prog: &ProgressWriter,
) -> Result<()> {
println!("Installing bootloader via systemd-boot");
prog.info("Installing bootloader via systemd-boot");

// We use the --root of the mounted target root, so we have the right /etc/os-release.
let root_path = prepared_root
Expand Down Expand Up @@ -347,11 +350,11 @@ pub(crate) fn install_systemd_boot(
}
dir.copy(filename, &keys_dir, filename)
.with_context(|| format!("Copying secure boot key {filename:?}"))?;
println!(
prog.info(format!(
"Wrote Secure Boot key: {}/{}",
keys_path.display(),
filename.as_str()
);
));
}
if keys.is_empty() {
tracing::debug!("No Secure Boot keys provided for systemd-boot enrollment");
Expand Down Expand Up @@ -390,7 +393,11 @@ fn parse_systemd_version(output: &str) -> Result<u32> {
}

#[context("Installing bootloader using zipl")]
pub(crate) fn install_via_zipl(device: &bootc_blockdev::Device, boot_uuid: &str) -> Result<()> {
pub(crate) fn install_via_zipl(
device: &bootc_blockdev::Device,
boot_uuid: &str,
prog: &ProgressWriter,
) -> Result<()> {
// Identify the target boot partition from UUID
let fs = mount::inspect_filesystem_by_uuid(boot_uuid)?;
let boot_dir = Utf8Path::new(&fs.target);
Expand Down Expand Up @@ -452,7 +459,7 @@ pub(crate) fn install_via_zipl(device: &bootc_blockdev::Device, boot_uuid: &str)
let ramdisk = boot_dir.join(initrd).canonicalize_utf8()?;

// Execute the zipl command to install bootloader
println!("Running zipl on {device_path}");
prog.info(format!("Running zipl on {device_path}"));
Command::new("zipl")
.args(["--target", boot_dir.as_str()])
.args(["--image", image.as_str()])
Expand Down
Loading