@@ -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 ;
@@ -19,19 +20,29 @@ use ostree::gio;
1920use ostree_container:: store:: PrepareResult ;
2021use ostree_ext:: composefs:: fsverity:: { self , FsVerityHashValue } ;
2122use ostree_ext:: container as ostree_container;
22- use ostree_ext:: container_utils:: ostree_booted;
23+ use ostree_ext:: container_utils:: { composefs_booted , ostree_booted} ;
2324use ostree_ext:: keyfileext:: KeyFileExt ;
2425use ostree_ext:: ostree;
2526use schemars:: schema_for;
2627use serde:: { Deserialize , Serialize } ;
2728
2829use 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+ } ;
2934use crate :: lints;
3035use crate :: progress_jsonl:: { ProgressWriter , RawProgressFd } ;
3136use crate :: spec:: Host ;
3237use crate :: spec:: ImageReference ;
38+ use crate :: status:: composefs_deployment_status;
3339use 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 ) ]
3748pub ( 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" ) ]
752831async fn upgrade ( opts : UpgradeOpts ) -> Result < ( ) > {
@@ -1084,7 +1163,13 @@ impl Opt {
10841163async 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