@@ -21,17 +21,22 @@ use ostree_ext::composefs::fsverity;
21
21
use ostree_ext:: composefs:: fsverity:: FsVerityHashValue ;
22
22
use ostree_ext:: composefs:: splitstream:: SplitStreamWriter ;
23
23
use ostree_ext:: container as ostree_container;
24
- use ostree_ext:: container_utils:: ostree_booted;
24
+ use ostree_ext:: container_utils:: { composefs_booted , ostree_booted} ;
25
25
use ostree_ext:: keyfileext:: KeyFileExt ;
26
26
use ostree_ext:: ostree;
27
27
use schemars:: schema_for;
28
28
use serde:: { Deserialize , Serialize } ;
29
29
30
- use crate :: deploy:: RequiredHostSpec ;
30
+ use crate :: deploy:: { composefs_rollback, RequiredHostSpec } ;
31
+ use crate :: install:: {
32
+ pull_composefs_repo, setup_composefs_bls_boot, setup_composefs_uki_boot, write_composefs_state,
33
+ BootSetupType , BootType ,
34
+ } ;
31
35
use crate :: lints;
32
36
use crate :: progress_jsonl:: { ProgressWriter , RawProgressFd } ;
33
37
use crate :: spec:: Host ;
34
38
use crate :: spec:: ImageReference ;
39
+ use crate :: status:: composefs_deployment_status;
35
40
use crate :: utils:: sigpolicy_from_opt;
36
41
37
42
/// Shared progress options
@@ -778,6 +783,53 @@ fn prepare_for_write() -> Result<()> {
778
783
Ok ( ( ) )
779
784
}
780
785
786
+ #[ context( "Upgrading composefs" ) ]
787
+ async fn upgrade_composefs ( _opts : UpgradeOpts ) -> Result < ( ) > {
788
+ // TODO: IMPORTANT Have all the checks here that `bootc upgrade` has for an ostree booted system
789
+
790
+ let host = composefs_deployment_status ( )
791
+ . await
792
+ . context ( "Getting composefs deployment status" ) ?;
793
+
794
+ // TODO: IMPORTANT We need to check if any deployment is staged and get the image from that
795
+ let imgref = host
796
+ . spec
797
+ . image
798
+ . as_ref ( )
799
+ . ok_or_else ( || anyhow:: anyhow!( "No image source specified" ) ) ?;
800
+
801
+ // let booted_image = host
802
+ // .status
803
+ // .booted
804
+ // .ok_or(anyhow::anyhow!("Could not find booted image"))?
805
+ // .image
806
+ // .ok_or(anyhow::anyhow!("Could not find booted image"))?;
807
+
808
+ // tracing::debug!("booted_image: {booted_image:#?}");
809
+ // tracing::debug!("imgref: {imgref:#?}");
810
+
811
+ // let digest = booted_image
812
+ // .digest()
813
+ // .context("Getting digest for booted image")?;
814
+
815
+ let ( repo, entries, id) = pull_composefs_repo ( & imgref. transport , & imgref. image ) . await ?;
816
+
817
+ let Some ( entry) = entries. into_iter ( ) . next ( ) else {
818
+ anyhow:: bail!( "No boot entries!" ) ;
819
+ } ;
820
+
821
+ let boot_type = BootType :: from ( & entry) ;
822
+
823
+ match boot_type {
824
+ BootType :: Bls => setup_composefs_bls_boot ( BootSetupType :: Upgrade , repo, & id, entry) ,
825
+ BootType :: Uki => setup_composefs_uki_boot ( BootSetupType :: Upgrade , repo, & id, entry) ,
826
+ } ?;
827
+
828
+ write_composefs_state ( & Utf8PathBuf :: from ( "/sysroot" ) , id, imgref, true , boot_type) ?;
829
+
830
+ Ok ( ( ) )
831
+ }
832
+
781
833
/// Implementation of the `bootc upgrade` CLI command.
782
834
#[ context( "Upgrading" ) ]
783
835
async fn upgrade ( opts : UpgradeOpts ) -> Result < ( ) > {
@@ -891,9 +943,7 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> {
891
943
Ok ( ( ) )
892
944
}
893
945
894
- /// Implementation of the `bootc switch` CLI command.
895
- #[ context( "Switching" ) ]
896
- async fn switch ( opts : SwitchOpts ) -> Result < ( ) > {
946
+ fn imgref_for_switch ( opts : & SwitchOpts ) -> Result < ImageReference > {
897
947
let transport = ostree_container:: Transport :: try_from ( opts. transport . as_str ( ) ) ?;
898
948
let imgref = ostree_container:: ImageReference {
899
949
transport,
@@ -902,6 +952,63 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
902
952
let sigverify = sigpolicy_from_opt ( opts. enforce_container_sigpolicy ) ;
903
953
let target = ostree_container:: OstreeImageReference { sigverify, imgref } ;
904
954
let target = ImageReference :: from ( target) ;
955
+
956
+ return Ok ( target) ;
957
+ }
958
+
959
+ #[ context( "Composefs Switching" ) ]
960
+ async fn switch_composefs ( opts : SwitchOpts ) -> Result < ( ) > {
961
+ let target = imgref_for_switch ( & opts) ?;
962
+ // TODO: Handle in-place
963
+
964
+ let host = composefs_deployment_status ( )
965
+ . await
966
+ . context ( "Getting composefs deployment status" ) ?;
967
+
968
+ let new_spec = {
969
+ let mut new_spec = host. spec . clone ( ) ;
970
+ new_spec. image = Some ( target. clone ( ) ) ;
971
+ new_spec
972
+ } ;
973
+
974
+ if new_spec == host. spec {
975
+ println ! ( "Image specification is unchanged." ) ;
976
+ return Ok ( ( ) ) ;
977
+ }
978
+
979
+ let Some ( target_imgref) = new_spec. image else {
980
+ anyhow:: bail!( "Target image is undefined" )
981
+ } ;
982
+
983
+ let ( repo, entries, id) = pull_composefs_repo ( & "docker" . into ( ) , & target_imgref. image ) . await ?;
984
+
985
+ let Some ( entry) = entries. into_iter ( ) . next ( ) else {
986
+ anyhow:: bail!( "No boot entries!" ) ;
987
+ } ;
988
+
989
+ let boot_type = BootType :: from ( & entry) ;
990
+
991
+ match boot_type {
992
+ BootType :: Bls => setup_composefs_bls_boot ( BootSetupType :: Upgrade , repo, & id, entry) ,
993
+ BootType :: Uki => setup_composefs_uki_boot ( BootSetupType :: Upgrade , repo, & id, entry) ,
994
+ } ?;
995
+
996
+ write_composefs_state (
997
+ & Utf8PathBuf :: from ( "/sysroot" ) ,
998
+ id,
999
+ & target_imgref,
1000
+ true ,
1001
+ boot_type,
1002
+ ) ?;
1003
+
1004
+ Ok ( ( ) )
1005
+ }
1006
+
1007
+ /// Implementation of the `bootc switch` CLI command.
1008
+ #[ context( "Switching" ) ]
1009
+ async fn switch ( opts : SwitchOpts ) -> Result < ( ) > {
1010
+ let target = imgref_for_switch ( & opts) ?;
1011
+
905
1012
let prog: ProgressWriter = opts. progress . try_into ( ) ?;
906
1013
907
1014
// If we're doing an in-place mutation, we shortcut most of the rest of the work here
@@ -966,8 +1073,12 @@ async fn switch(opts: SwitchOpts) -> Result<()> {
966
1073
/// Implementation of the `bootc rollback` CLI command.
967
1074
#[ context( "Rollback" ) ]
968
1075
async fn rollback ( opts : RollbackOpts ) -> Result < ( ) > {
969
- let sysroot = & get_storage ( ) . await ?;
970
- crate :: deploy:: rollback ( sysroot) . await ?;
1076
+ if composefs_booted ( ) ? {
1077
+ composefs_rollback ( ) . await ?
1078
+ } else {
1079
+ let sysroot = & get_storage ( ) . await ?;
1080
+ crate :: deploy:: rollback ( sysroot) . await ?;
1081
+ } ;
971
1082
972
1083
if opts. apply {
973
1084
crate :: reboot:: reboot ( ) ?;
@@ -1117,8 +1228,20 @@ impl Opt {
1117
1228
async fn run_from_opt ( opt : Opt ) -> Result < ( ) > {
1118
1229
let root = & Dir :: open_ambient_dir ( "/" , cap_std:: ambient_authority ( ) ) ?;
1119
1230
match opt {
1120
- Opt :: Upgrade ( opts) => upgrade ( opts) . await ,
1121
- Opt :: Switch ( opts) => switch ( opts) . await ,
1231
+ Opt :: Upgrade ( opts) => {
1232
+ if composefs_booted ( ) ? {
1233
+ upgrade_composefs ( opts) . await
1234
+ } else {
1235
+ upgrade ( opts) . await
1236
+ }
1237
+ }
1238
+ Opt :: Switch ( opts) => {
1239
+ if composefs_booted ( ) ? {
1240
+ switch_composefs ( opts) . await
1241
+ } else {
1242
+ switch ( opts) . await
1243
+ }
1244
+ }
1122
1245
Opt :: Rollback ( opts) => rollback ( opts) . await ,
1123
1246
Opt :: Edit ( opts) => edit ( opts) . await ,
1124
1247
Opt :: UsrOverlay => usroverlay ( ) . await ,
@@ -1259,8 +1382,7 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
1259
1382
FsverityOpts :: Enable { path } => {
1260
1383
let fd =
1261
1384
std:: fs:: File :: open ( & path) . with_context ( || format ! ( "Reading {path}" ) ) ?;
1262
- // Note this is not robust to forks, we're not using the _maybe_copy variant
1263
- fsverity:: enable_verity_with_retry :: < fsverity:: Sha256HashValue > ( & fd) ?;
1385
+ fsverity:: enable_verity_raw :: < fsverity:: Sha256HashValue > ( & fd) ?;
1264
1386
Ok ( ( ) )
1265
1387
}
1266
1388
} ,
0 commit comments