1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00

Clean up staging flow

Add a helper `stage()` which takes all the data we need,
and use it in both the `upgrade` and `switch` paths.  This drops
out an "internal error" message and avoids the "utils" code growth.

Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
Colin Walters
2022-12-05 17:14:00 -05:00
parent 54decd5858
commit 131a34522b
2 changed files with 27 additions and 38 deletions

View File

@@ -13,12 +13,11 @@ use ostree_ext::container as ostree_container;
use ostree_ext::container::SignatureSource;
use ostree_ext::keyfileext::KeyFileExt;
use ostree_ext::ostree;
use ostree_ext::sysroot::SysrootLock;
use std::ffi::OsString;
use std::os::unix::process::CommandExt;
use tokio::sync::mpsc::Receiver;
use crate::utils::{get_image_origin, print_staged};
/// Perform an upgrade operation
#[derive(Debug, Parser)]
pub(crate) struct UpgradeOpts {
@@ -240,16 +239,37 @@ pub(crate) async fn print_deprecated_warning(msg: &str) {
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
}
/// Stage (queue deployment of) a fetched container image.
async fn stage(
sysroot: &SysrootLock,
stateroot: &str,
imgref: &ostree_container::OstreeImageReference,
image: Box<LayeredImageState>,
origin: &glib::KeyFile,
) -> Result<()> {
let cancellable = gio::Cancellable::NONE;
let stateroot = Some(stateroot);
let merge_deployment = sysroot.merge_deployment(stateroot);
let _new_deployment = sysroot.stage_tree_with_options(
stateroot,
image.merge_commit.as_str(),
Some(origin),
merge_deployment.as_ref(),
&Default::default(),
cancellable,
)?;
println!("Queued for next boot: {imgref}");
Ok(())
}
/// Implementation of the `bootc upgrade` CLI command.
async fn upgrade(opts: UpgradeOpts) -> Result<()> {
ensure_self_unshared_mount_namespace().await?;
let cancellable = gio::Cancellable::NONE;
let sysroot = &get_locked_sysroot().await?;
let repo = &sysroot.repo().unwrap();
let booted_deployment = &sysroot.require_booted_deployment()?;
let status = crate::status::DeploymentStatus::from_deployment(booted_deployment, true)?;
let osname = booted_deployment.osname().unwrap();
let osname_v = Some(osname.as_str());
let origin = booted_deployment
.origin()
.ok_or_else(|| anyhow::anyhow!("Deployment is missing an origin"))?;
@@ -272,17 +292,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
return Ok(());
}
let merge_deployment = sysroot.merge_deployment(osname_v);
let new_deployment = sysroot.stage_tree_with_options(
osname_v,
fetched.merge_commit.as_str(),
Some(&origin),
merge_deployment.as_ref(),
&Default::default(),
cancellable,
)?;
print_staged(&new_deployment)?;
stage(sysroot, &osname, &imgref, fetched, &origin).await?;
if let Some(path) = opts.touch_if_changed {
std::fs::write(&path, "").with_context(|| format!("Writing {path}"))?;
@@ -297,10 +307,9 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
let cancellable = gio::Cancellable::NONE;
let sysroot = get_locked_sysroot().await?;
let booted_deployment = &sysroot.require_booted_deployment()?;
let (origin, booted_image) = get_image_origin(booted_deployment)?;
let (origin, booted_image) = crate::utils::get_image_origin(booted_deployment)?;
let booted_refspec = origin.optional_string("origin", "refspec")?;
let osname = booted_deployment.osname().unwrap();
let osname_v = Some(osname.as_str());
let repo = &sysroot.repo().unwrap();
let transport = ostree_container::Transport::try_from(opts.transport.as_str())?;
@@ -318,7 +327,6 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
let target = ostree_container::OstreeImageReference { sigverify, imgref };
let fetched = pull(repo, &target, opts.quiet).await?;
let merge_deployment = sysroot.merge_deployment(osname_v);
if !opts.retain {
// By default, we prune the previous ostree ref or container image
@@ -338,16 +346,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
ostree_container::deploy::ORIGIN_CONTAINER,
target.to_string().as_str(),
);
let new_deployment = sysroot.stage_tree_with_options(
osname_v,
fetched.merge_commit.as_str(),
Some(&origin),
merge_deployment.as_ref(),
&Default::default(),
cancellable,
)?;
print_staged(&new_deployment)?;
stage(&sysroot, &osname, &target, fetched, &origin).await?;
Ok(())
}

View File

@@ -37,16 +37,6 @@ pub(crate) fn origin_has_rpmostree_stuff(kf: &glib::KeyFile) -> bool {
false
}
/// Print the deployment we staged.
pub(crate) fn print_staged(deployment: &ostree::Deployment) -> Result<()> {
let (_origin, imgref) = get_image_origin(deployment)?;
let imgref = imgref.ok_or_else(|| {
anyhow::anyhow!("Internal error: expected a container deployment to be staged")
})?;
println!("Queued for next boot: {imgref}");
Ok(())
}
/// Implement the `Serialize` trait for types that are `Display`.
/// https://stackoverflow.com/questions/58103801/serialize-using-the-display-trait
pub(crate) fn ser_with_display<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>