Skip to content

Commit 4383a35

Browse files
install/composefs: Implement bootc upgrade
* Implement `bootc upgrade` command for a composefs-native booted system * Refactor UKI and BLS boot entry writing functions to work for upgrade * Prevent using global `/dev/disk/by-partuuid` to get UUID for ESP * Refactor out code for populating `/sysroot/state` Signed-off-by: Pragyan Poudyal <[email protected]>
1 parent 8d9b923 commit 4383a35

File tree

3 files changed

+291
-95
lines changed

3 files changed

+291
-95
lines changed

lib/src/cli.rs

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::ffi::{CString, OsStr, OsString};
66
use std::io::Seek;
77
use std::os::unix::process::CommandExt;
88
use std::process::Command;
9+
use std::sync::Arc;
910

1011
use anyhow::{ensure, Context, Result};
1112
use camino::Utf8PathBuf;
@@ -19,19 +20,29 @@ use ostree::gio;
1920
use ostree_container::store::PrepareResult;
2021
use ostree_ext::composefs::fsverity::{self, FsVerityHashValue};
2122
use ostree_ext::container as ostree_container;
22-
use ostree_ext::container_utils::ostree_booted;
23+
use ostree_ext::container_utils::{composefs_booted, ostree_booted};
2324
use ostree_ext::keyfileext::KeyFileExt;
2425
use ostree_ext::ostree;
2526
use schemars::schema_for;
2627
use serde::{Deserialize, Serialize};
2728

2829
use crate::deploy::RequiredHostSpec;
30+
use crate::install::{
31+
open_composefs_repo, setup_composefs_bls_boot, setup_composefs_uki_boot, write_composefs_state,
32+
BootType, BootSetupType,
33+
};
2934
use crate::lints;
3035
use crate::progress_jsonl::{ProgressWriter, RawProgressFd};
3136
use crate::spec::Host;
3237
use crate::spec::ImageReference;
38+
use crate::status::composefs_deployment_status;
3339
use crate::utils::sigpolicy_from_opt;
3440

41+
use ostree_ext::composefs_boot::BootOps;
42+
use ostree_ext::composefs_oci::{
43+
image::create_filesystem as create_composefs_filesystem, pull as composefs_oci_pull,
44+
};
45+
3546
/// Shared progress options
3647
#[derive(Debug, Parser, PartialEq, Eq)]
3748
pub(crate) struct ProgressOptions {
@@ -747,6 +758,74 @@ fn prepare_for_write() -> Result<()> {
747758
Ok(())
748759
}
749760

761+
#[context("Upgrading composefs")]
762+
async fn upgrade_composefs(_opts: UpgradeOpts) -> Result<()> {
763+
// TODO: IMPORTANT Have all the checks here that `bootc upgrade` has for an ostree booted system
764+
765+
let host = composefs_deployment_status()
766+
.await
767+
.context("Getting composefs deployment status")?;
768+
769+
// TODO: IMPORTANT We need to check if any deployment is staged and get the image from that
770+
let imgref = host
771+
.spec
772+
.image
773+
.as_ref()
774+
.ok_or_else(|| anyhow::anyhow!("No image source specified"))?;
775+
776+
let booted_image = host
777+
.status
778+
.booted
779+
.ok_or(anyhow::anyhow!("Could not find booted image"))?
780+
.image
781+
.ok_or(anyhow::anyhow!("Could not find booted image"))?;
782+
783+
tracing::debug!("booted_image: {booted_image:#?}");
784+
tracing::debug!("imgref: {imgref:#?}");
785+
786+
let digest = booted_image
787+
.digest()
788+
.context("Getting digest for booted image")?;
789+
790+
let rootfs_dir = cap_std::fs::Dir::open_ambient_dir("/sysroot", cap_std::ambient_authority())?;
791+
792+
let repo = open_composefs_repo(&rootfs_dir).context("Opening compoesfs repo")?;
793+
794+
let (id, verity) = composefs_oci_pull(
795+
&Arc::new(repo),
796+
&format!("{}:{}", imgref.transport, imgref.image),
797+
None,
798+
)
799+
.await
800+
.context("Pulling composefs repo")?;
801+
802+
tracing::debug!(
803+
"id = {id}, verity = {verity}",
804+
id = hex::encode(id),
805+
verity = verity.to_hex()
806+
);
807+
808+
let repo = open_composefs_repo(&rootfs_dir)?;
809+
let mut fs = create_composefs_filesystem(&repo, digest.digest(), None)
810+
.context("Failed to create composefs filesystem")?;
811+
812+
let entries = fs.transform_for_boot(&repo)?;
813+
let id = fs.commit_image(&repo, None)?;
814+
815+
let Some(entry) = entries.into_iter().next() else {
816+
anyhow::bail!("No boot entries!");
817+
};
818+
819+
match BootType::from(&entry) {
820+
BootType::Bls => setup_composefs_bls_boot(BootSetupType::Upgrade, repo, &id, entry),
821+
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade, repo, &id, entry),
822+
}?;
823+
824+
write_composefs_state(&Utf8PathBuf::from("/sysroot"), id, imgref)?;
825+
826+
Ok(())
827+
}
828+
750829
/// Implementation of the `bootc upgrade` CLI command.
751830
#[context("Upgrading")]
752831
async fn upgrade(opts: UpgradeOpts) -> Result<()> {
@@ -1084,7 +1163,13 @@ impl Opt {
10841163
async fn run_from_opt(opt: Opt) -> Result<()> {
10851164
let root = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
10861165
match opt {
1087-
Opt::Upgrade(opts) => upgrade(opts).await,
1166+
Opt::Upgrade(opts) => {
1167+
if composefs_booted()? {
1168+
upgrade_composefs(opts).await
1169+
} else {
1170+
upgrade(opts).await
1171+
}
1172+
}
10881173
Opt::Switch(opts) => switch(opts).await,
10891174
Opt::Rollback(opts) => rollback(opts).await,
10901175
Opt::Edit(opts) => edit(opts).await,

0 commit comments

Comments
 (0)