Skip to content

Commit

Permalink
cli: support the stateroot option also on switch
Browse files Browse the repository at this point in the history
draft, still working out the details and testing, this doesn't work yet

# Background

<hash> added the `stateroot` option to the `install` subcommand

# Issue

The `stateroot` option is not available on the `switch` subcommand

# Solution

Add the `stateroot` option to the `switch` subcommand

# Implementation

* If the stateroot is different than the current, we should allow using
  the same image as the currently booted one
* Stateroot has to be explicitly created (`init_osname` binding) if it
  doesn't exist. If it does, we still call `init_osname` and simply
  ignore the error (TODO: only ignore non-already-exists errors)

Signed-off-by: Omer Tuchfeld <[email protected]>
  • Loading branch information
omertuc committed Sep 10, 2024
1 parent 1fd6c69 commit 198aa06
Showing 1 changed file with 30 additions and 3 deletions.
33 changes: 30 additions & 3 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,9 @@ pub(crate) struct SwitchOpts {

/// Target image to use for the next boot.
pub(crate) target: String,

#[clap(long)]
pub(crate) stateroot: Option<String>,
}

/// Options controlling rollback
Expand Down Expand Up @@ -687,18 +690,43 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
let (booted_deployment, _deployments, host) =
crate::status::get_status_require_booted(sysroot)?;

let (stateroot, is_same_stateroot) = {
let booted_osname = booted_deployment.osname();
let stateroot = opts
.stateroot
.as_deref()
.unwrap_or_else(|| booted_osname.as_str());

(stateroot.to_owned(), stateroot == booted_osname)
};

let new_spec = {
let mut new_spec = host.spec.clone();
new_spec.image = Some(target.clone());
new_spec
};

if new_spec == host.spec {
println!("Image specification is unchanged.");
if new_spec == host.spec && is_same_stateroot {
// TODO: Should we confuse users with terms like "stateroot"?
println!(
"The currently running deployment in stateroot {stateroot} is already using this image"
);
return Ok(());
}
let new_spec = RequiredHostSpec::from_spec(&new_spec)?;

if !is_same_stateroot {
let sysroot = ostree::Sysroot::new_default();
let init_result = sysroot.init_osname(&stateroot, cancellable);
match init_result {
Ok(_) => {}
Err(err) => {
// TODO: Only ignore non already-exists errors
println!("Ignoring error creating new stateroot: {err}");
}
}
}

let fetched = crate::deploy::pull(repo, &target, None, opts.quiet).await?;

if !opts.retain {
Expand All @@ -712,7 +740,6 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
}
}

let stateroot = booted_deployment.osname();
crate::deploy::stage(sysroot, &stateroot, &fetched, &new_spec).await?;

if opts.apply {
Expand Down

0 comments on commit 198aa06

Please sign in to comment.