@@ -6,13 +6,15 @@ 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 } ;
11- use camino:: Utf8PathBuf ;
12+ use camino:: { Utf8Path , Utf8PathBuf } ;
1213use cap_std_ext:: cap_std;
1314use cap_std_ext:: cap_std:: fs:: Dir ;
1415use clap:: Parser ;
1516use clap:: ValueEnum ;
17+ use composefs_boot:: BootOps as _;
1618use etc_merge:: { compute_diff, print_diff} ;
1719use fn_error_context:: context;
1820use indoc:: indoc;
@@ -23,11 +25,13 @@ use ostree_ext::composefs::fsverity::FsVerityHashValue;
2325use ostree_ext:: composefs:: splitstream:: SplitStreamWriter ;
2426use ostree_ext:: container as ostree_container;
2527use ostree_ext:: container_utils:: ostree_booted;
28+ use ostree_ext:: containers_image_proxy:: ImageProxyConfig ;
2629use ostree_ext:: keyfileext:: KeyFileExt ;
2730use ostree_ext:: ostree;
2831use ostree_ext:: sysroot:: SysrootLock ;
2932use schemars:: schema_for;
3033use serde:: { Deserialize , Serialize } ;
34+ use tempfile:: tempdir_in;
3135
3236#[ cfg( feature = "composefs-backend" ) ]
3337use crate :: bootc_composefs:: {
@@ -40,9 +44,11 @@ use crate::bootc_composefs::{
4044} ;
4145use crate :: deploy:: RequiredHostSpec ;
4246use crate :: lints;
47+ use crate :: podstorage:: set_additional_image_store;
4348use crate :: progress_jsonl:: { ProgressWriter , RawProgressFd } ;
4449use crate :: spec:: Host ;
4550use crate :: spec:: ImageReference ;
51+ use crate :: store:: ComposefsRepository ;
4652use crate :: utils:: sigpolicy_from_opt;
4753
4854/// Shared progress options
@@ -315,6 +321,12 @@ pub(crate) enum ContainerOpts {
315321 #[ clap( long) ]
316322 no_truncate : bool ,
317323 } ,
324+ /// Output the bootable composefs digest.
325+ #[ clap( hide = true ) ]
326+ ComputeComposefsDigest {
327+ /// Identifier for image; if not provided, the running image will be used.
328+ image : Option < String > ,
329+ } ,
318330}
319331
320332/// Subcommands which operate on images.
@@ -1335,6 +1347,55 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
13351347 ) ?;
13361348 Ok ( ( ) )
13371349 }
1350+ ContainerOpts :: ComputeComposefsDigest { image } => {
1351+ // Allocate a tempdir
1352+ let td = tempdir_in ( "/var/tmp" ) ?;
1353+ let td = td. path ( ) ;
1354+ let td = & Dir :: open_ambient_dir ( td, cap_std:: ambient_authority ( ) ) ?;
1355+
1356+ td. create_dir ( "repo" ) ?;
1357+ let repo = td. open_dir ( "repo" ) ?;
1358+ let mut repo =
1359+ ComposefsRepository :: open_path ( & repo, "." ) . context ( "Init cfs repo" ) ?;
1360+ // We don't need to hard require verity on the *host* system, we're just computing a checksum here
1361+ repo. set_insecure ( true ) ;
1362+ let repo = & Arc :: new ( repo) ;
1363+
1364+ let mut proxycfg = ImageProxyConfig :: default ( ) ;
1365+
1366+ let image = if let Some ( image) = image {
1367+ image
1368+ } else {
1369+ let host_container_store = Utf8Path :: new ( "/run/host-container-storage" ) ;
1370+ // If no image is provided, assume that we're running in a container in privileged mode
1371+ // with access to the container storage.
1372+ let container_info = crate :: containerenv:: get_container_execution_info ( & root) ?;
1373+ let iid = container_info. imageid ;
1374+ tracing:: debug!( "Computing digest of {iid}" ) ;
1375+
1376+ if !host_container_store. try_exists ( ) ? {
1377+ anyhow:: bail!( "Must be readonly mount of host container store: {host_container_store}" ) ;
1378+ }
1379+ // And ensure we're finding the image in the host storage
1380+ let mut cmd = Command :: new ( "skopeo" ) ;
1381+ set_additional_image_store ( & mut cmd, "/run/host-container-storage" ) ;
1382+ proxycfg. skopeo_cmd = Some ( cmd) ;
1383+ iid
1384+ } ;
1385+
1386+ let imgref = format ! ( "containers-storage:{image}" ) ;
1387+ let ( imgid, verity) = composefs_oci:: pull ( repo, & imgref, None , Some ( proxycfg) )
1388+ . await
1389+ . context ( "Pulling image" ) ?;
1390+ let imgid = hex:: encode ( imgid) ;
1391+ let mut fs = composefs_oci:: image:: create_filesystem ( repo, & imgid, Some ( & verity) )
1392+ . context ( "Populating fs" ) ?;
1393+ fs. transform_for_boot ( & repo) . context ( "Preparing for boot" ) ?;
1394+ let id = fs. compute_image_id ( ) ;
1395+ println ! ( "{}" , id. to_hex( ) ) ;
1396+
1397+ Ok ( ( ) )
1398+ }
13381399 } ,
13391400 Opt :: Image ( opts) => match opts {
13401401 ImageOpts :: List {
0 commit comments