Skip to content

Commit

Permalink
Add RequiredHostSpec
Browse files Browse the repository at this point in the history
We want to gracefully handle the case where there's no booted/staged
image - i.e. when there's no spec.

However we only support deploying a container image.  So add
a `RequiredHostSpec` that is like `HostSpec` but without the
`Option`.

This drops out a few unnecessary `Option`-juggling in the deploy
code.

Prep for adding configmaps to the spec.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Oct 15, 2023
1 parent 1cf2496 commit 5fab418
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 30 deletions.
15 changes: 7 additions & 8 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::io::Seek;
use std::os::unix::process::CommandExt;
use std::process::Command;

use crate::deploy::RequiredHostSpec;
use crate::spec::Host;
use crate::spec::ImageReference;

Expand Down Expand Up @@ -290,6 +291,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
"Booted deployment contains local rpm-ostree modifications; cannot upgrade via bootc"
));
}
let spec = RequiredHostSpec::from_spec(&host.spec)?;
let booted_image = status
.booted
.map(|b| b.query_image(repo))
Expand Down Expand Up @@ -334,7 +336,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
println!("Staged update present, not changed.");
} else {
let osname = booted_deployment.osname();
crate::deploy::stage(sysroot, &osname, &fetched, &host.spec).await?;
crate::deploy::stage(sysroot, &osname, &fetched, &spec).await?;
changed = true;
if let Some(prev) = booted_image.as_ref() {
let diff = ostree_container::ManifestDiff::new(&prev.manifest, &fetched.manifest);
Expand Down Expand Up @@ -386,6 +388,7 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
if new_spec == host.spec {
anyhow::bail!("No changes in current host spec");
}
let new_spec = RequiredHostSpec::from_spec(&new_spec)?;

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

Expand Down Expand Up @@ -429,17 +432,13 @@ async fn edit(opts: EditOpts) -> Result<()> {
if new_host.spec == host.spec {
anyhow::bail!("No changes in current host spec");
}
let new_image = new_host
.spec
.image
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Unable to transition to unset image"))?;
let fetched = pull(repo, new_image, opts.quiet).await?;
let new_spec = RequiredHostSpec::from_spec(&new_host.spec)?;
let fetched = pull(repo, &new_spec.image, opts.quiet).await?;

// TODO gc old layers here

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

Ok(())
}
Expand Down
55 changes: 33 additions & 22 deletions lib/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,31 @@ use ostree_ext::ostree::Deployment;
use ostree_ext::sysroot::SysrootLock;

use crate::spec::HostSpec;
use crate::spec::ImageReference;

// TODO use https://github.com/ostreedev/ostree-rs-ext/pull/493/commits/afc1837ff383681b947de30c0cefc70080a4f87a
const BASE_IMAGE_PREFIX: &str = "ostree/container/baseimage/bootc";

/// Set on an ostree commit if this is a derived commit
const BOOTC_DERIVED_KEY: &str = "bootc.derived";

/// Variant of HostSpec but required to be filled out
pub(crate) struct RequiredHostSpec<'a> {
pub(crate) image: &'a ImageReference,
}

impl<'a> RequiredHostSpec<'a> {
/// Given a (borrowed) host specification, "unwrap" its internal
/// options, giving a spec that is required to have a base container image.
pub(crate) fn from_spec(spec: &'a HostSpec) -> Result<Self> {
let image = spec
.image
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Missing image in specification"))?;
Ok(Self { image })
}
}

pub(crate) async fn cleanup(sysroot: &SysrootLock) -> Result<()> {
let repo = sysroot.repo();
let sysroot = sysroot.sysroot.clone();
Expand Down Expand Up @@ -96,21 +114,16 @@ pub(crate) async fn stage(
sysroot: &SysrootLock,
stateroot: &str,
image: &LayeredImageState,
spec: &HostSpec,
spec: &RequiredHostSpec<'_>,
) -> Result<()> {
let merge_deployment = sysroot.merge_deployment(Some(stateroot));
let origin = glib::KeyFile::new();
let ostree_imgref = spec
.image
.as_ref()
.map(|imgref| OstreeImageReference::from(imgref.clone()));
if let Some(imgref) = ostree_imgref.as_ref() {
origin.set_string(
"origin",
ostree_container::deploy::ORIGIN_CONTAINER,
imgref.to_string().as_str(),
);
}
let imgref = OstreeImageReference::from(spec.image.clone());
origin.set_string(
"origin",
ostree_container::deploy::ORIGIN_CONTAINER,
imgref.to_string().as_str(),
);
crate::deploy::deploy(
sysroot,
merge_deployment.as_ref(),
Expand All @@ -120,17 +133,15 @@ pub(crate) async fn stage(
)
.await?;
crate::deploy::cleanup(sysroot).await?;
if let Some(imgref) = ostree_imgref.as_ref() {
println!("Queued for next boot: {imgref}");
if let Some(version) = image
.configuration
.as_ref()
.and_then(ostree_container::version_for_config)
{
println!(" Version: {version}");
}
println!(" Digest: {}", image.manifest_digest);
println!("Queued for next boot: {imgref}");
if let Some(version) = image
.configuration
.as_ref()
.and_then(ostree_container::version_for_config)
{
println!(" Version: {version}");
}
println!(" Digest: {}", image.manifest_digest);
ostree_container::deploy::remove_undeployed_images(sysroot).context("Pruning images")?;

Ok(())
Expand Down

0 comments on commit 5fab418

Please sign in to comment.