@@ -6,6 +6,7 @@ use std::ffi::{CString, OsStr, OsString};
66use std:: io:: Seek ;
77use std:: os:: unix:: process:: CommandExt ;
88use std:: process:: Command ;
9+ use std:: sync:: Arc ;
910
1011use anyhow:: { ensure, Context , Result } ;
1112use camino:: Utf8PathBuf ;
@@ -20,19 +21,29 @@ use ostree_container::store::PrepareResult;
2021use ostree_ext:: composefs:: fsverity;
2122use ostree_ext:: composefs:: fsverity:: FsVerityHashValue ;
2223use ostree_ext:: container as ostree_container;
23- use ostree_ext:: container_utils:: ostree_booted;
24+ use ostree_ext:: container_utils:: { composefs_booted , ostree_booted} ;
2425use ostree_ext:: keyfileext:: KeyFileExt ;
2526use ostree_ext:: ostree;
2627use schemars:: schema_for;
2728use serde:: { Deserialize , Serialize } ;
2829
2930use 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+ } ;
3035use crate :: lints;
3136use crate :: progress_jsonl:: { ProgressWriter , RawProgressFd } ;
3237use crate :: spec:: Host ;
3338use crate :: spec:: ImageReference ;
39+ use crate :: status:: composefs_deployment_status;
3440use 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 ) ]
3849pub ( 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" ) ]
762841async fn upgrade ( opts : UpgradeOpts ) -> Result < ( ) > {
@@ -1096,7 +1175,13 @@ impl Opt {
10961175async 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