Skip to content

Commit 5f01e0d

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 42d816c commit 5f01e0d

File tree

3 files changed

+291
-95
lines changed

3 files changed

+291
-95
lines changed

crates/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;
@@ -20,19 +21,29 @@ use ostree_container::store::PrepareResult;
2021
use ostree_ext::composefs::fsverity;
2122
use ostree_ext::composefs::fsverity::FsVerityHashValue;
2223
use ostree_ext::container as ostree_container;
23-
use ostree_ext::container_utils::ostree_booted;
24+
use ostree_ext::container_utils::{composefs_booted, ostree_booted};
2425
use ostree_ext::keyfileext::KeyFileExt;
2526
use ostree_ext::ostree;
2627
use schemars::schema_for;
2728
use serde::{Deserialize, Serialize};
2829

2930
use crate::deploy::RequiredHostSpec;
31+
use crate::install::{
32+
open_composefs_repo, setup_composefs_bls_boot, setup_composefs_uki_boot, write_composefs_state,
33+
BootType, BootSetupType,
34+
};
3035
use crate::lints;
3136
use crate::progress_jsonl::{ProgressWriter, RawProgressFd};
3237
use crate::spec::Host;
3338
use crate::spec::ImageReference;
39+
use crate::status::composefs_deployment_status;
3440
use crate::utils::sigpolicy_from_opt;
3541

42+
use ostree_ext::composefs_boot::BootOps;
43+
use ostree_ext::composefs_oci::{
44+
image::create_filesystem as create_composefs_filesystem, pull as composefs_oci_pull,
45+
};
46+
3647
/// Shared progress options
3748
#[derive(Debug, Parser, PartialEq, Eq)]
3849
pub(crate) struct ProgressOptions {
@@ -757,6 +768,74 @@ fn prepare_for_write() -> Result<()> {
757768
Ok(())
758769
}
759770

771+
#[context("Upgrading composefs")]
772+
async fn upgrade_composefs(_opts: UpgradeOpts) -> Result<()> {
773+
// TODO: IMPORTANT Have all the checks here that `bootc upgrade` has for an ostree booted system
774+
775+
let host = composefs_deployment_status()
776+
.await
777+
.context("Getting composefs deployment status")?;
778+
779+
// TODO: IMPORTANT We need to check if any deployment is staged and get the image from that
780+
let imgref = host
781+
.spec
782+
.image
783+
.as_ref()
784+
.ok_or_else(|| anyhow::anyhow!("No image source specified"))?;
785+
786+
let booted_image = host
787+
.status
788+
.booted
789+
.ok_or(anyhow::anyhow!("Could not find booted image"))?
790+
.image
791+
.ok_or(anyhow::anyhow!("Could not find booted image"))?;
792+
793+
tracing::debug!("booted_image: {booted_image:#?}");
794+
tracing::debug!("imgref: {imgref:#?}");
795+
796+
let digest = booted_image
797+
.digest()
798+
.context("Getting digest for booted image")?;
799+
800+
let rootfs_dir = cap_std::fs::Dir::open_ambient_dir("/sysroot", cap_std::ambient_authority())?;
801+
802+
let repo = open_composefs_repo(&rootfs_dir).context("Opening compoesfs repo")?;
803+
804+
let (id, verity) = composefs_oci_pull(
805+
&Arc::new(repo),
806+
&format!("{}:{}", imgref.transport, imgref.image),
807+
None,
808+
)
809+
.await
810+
.context("Pulling composefs repo")?;
811+
812+
tracing::debug!(
813+
"id = {id}, verity = {verity}",
814+
id = hex::encode(id),
815+
verity = verity.to_hex()
816+
);
817+
818+
let repo = open_composefs_repo(&rootfs_dir)?;
819+
let mut fs = create_composefs_filesystem(&repo, digest.digest(), None)
820+
.context("Failed to create composefs filesystem")?;
821+
822+
let entries = fs.transform_for_boot(&repo)?;
823+
let id = fs.commit_image(&repo, None)?;
824+
825+
let Some(entry) = entries.into_iter().next() else {
826+
anyhow::bail!("No boot entries!");
827+
};
828+
829+
match BootType::from(&entry) {
830+
BootType::Bls => setup_composefs_bls_boot(BootSetupType::Upgrade, repo, &id, entry),
831+
BootType::Uki => setup_composefs_uki_boot(BootSetupType::Upgrade, repo, &id, entry),
832+
}?;
833+
834+
write_composefs_state(&Utf8PathBuf::from("/sysroot"), id, imgref)?;
835+
836+
Ok(())
837+
}
838+
760839
/// Implementation of the `bootc upgrade` CLI command.
761840
#[context("Upgrading")]
762841
async fn upgrade(opts: UpgradeOpts) -> Result<()> {
@@ -1096,7 +1175,13 @@ impl Opt {
10961175
async fn run_from_opt(opt: Opt) -> Result<()> {
10971176
let root = &Dir::open_ambient_dir("/", cap_std::ambient_authority())?;
10981177
match opt {
1099-
Opt::Upgrade(opts) => upgrade(opts).await,
1178+
Opt::Upgrade(opts) => {
1179+
if composefs_booted()? {
1180+
upgrade_composefs(opts).await
1181+
} else {
1182+
upgrade(opts).await
1183+
}
1184+
}
11001185
Opt::Switch(opts) => switch(opts).await,
11011186
Opt::Rollback(opts) => rollback(opts).await,
11021187
Opt::Edit(opts) => edit(opts).await,

0 commit comments

Comments
 (0)