@@ -6,13 +6,15 @@ use std::ffi::{CString, OsStr, OsString};
6
6
use std:: io:: Seek ;
7
7
use std:: os:: unix:: process:: CommandExt ;
8
8
use std:: process:: Command ;
9
+ use std:: sync:: Arc ;
9
10
10
11
use anyhow:: { ensure, Context , Result } ;
11
- use camino:: Utf8PathBuf ;
12
+ use camino:: { Utf8Path , Utf8PathBuf } ;
12
13
use cap_std_ext:: cap_std;
13
14
use cap_std_ext:: cap_std:: fs:: Dir ;
14
15
use clap:: Parser ;
15
16
use clap:: ValueEnum ;
17
+ use composefs_boot:: BootOps as _;
16
18
use etc_merge:: { compute_diff, print_diff} ;
17
19
use fn_error_context:: context;
18
20
use indoc:: indoc;
@@ -23,11 +25,13 @@ use ostree_ext::composefs::fsverity::FsVerityHashValue;
23
25
use ostree_ext:: composefs:: splitstream:: SplitStreamWriter ;
24
26
use ostree_ext:: container as ostree_container;
25
27
use ostree_ext:: container_utils:: ostree_booted;
28
+ use ostree_ext:: containers_image_proxy:: ImageProxyConfig ;
26
29
use ostree_ext:: keyfileext:: KeyFileExt ;
27
30
use ostree_ext:: ostree;
28
31
use ostree_ext:: sysroot:: SysrootLock ;
29
32
use schemars:: schema_for;
30
33
use serde:: { Deserialize , Serialize } ;
34
+ use tempfile:: tempdir_in;
31
35
32
36
#[ cfg( feature = "composefs-backend" ) ]
33
37
use crate :: bootc_composefs:: {
@@ -40,9 +44,11 @@ use crate::bootc_composefs::{
40
44
} ;
41
45
use crate :: deploy:: RequiredHostSpec ;
42
46
use crate :: lints;
47
+ use crate :: podstorage:: set_additional_image_store;
43
48
use crate :: progress_jsonl:: { ProgressWriter , RawProgressFd } ;
44
49
use crate :: spec:: Host ;
45
50
use crate :: spec:: ImageReference ;
51
+ use crate :: store:: ComposefsRepository ;
46
52
use crate :: utils:: sigpolicy_from_opt;
47
53
48
54
/// Shared progress options
@@ -315,6 +321,12 @@ pub(crate) enum ContainerOpts {
315
321
#[ clap( long) ]
316
322
no_truncate : bool ,
317
323
} ,
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
+ } ,
318
330
}
319
331
320
332
/// Subcommands which operate on images.
@@ -1335,6 +1347,55 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
1335
1347
) ?;
1336
1348
Ok ( ( ) )
1337
1349
}
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
+ }
1338
1399
} ,
1339
1400
Opt :: Image ( opts) => match opts {
1340
1401
ImageOpts :: List {
0 commit comments