@@ -11,7 +11,7 @@ pub(crate) mod config;
11
11
pub ( crate ) mod osconfig;
12
12
13
13
use std:: io:: Write ;
14
- use std:: os:: fd:: AsFd ;
14
+ use std:: os:: fd:: { AsFd , OwnedFd } ;
15
15
use std:: os:: unix:: process:: CommandExt ;
16
16
use std:: path:: Path ;
17
17
use std:: process:: Command ;
@@ -26,6 +26,7 @@ use camino::Utf8PathBuf;
26
26
use cap_std:: fs:: { Dir , MetadataExt } ;
27
27
use cap_std_ext:: cap_std;
28
28
use cap_std_ext:: cap_std:: fs_utf8:: DirEntry as DirEntryUtf8 ;
29
+ use cap_std_ext:: cmdext:: CapStdExtCommandExt ;
29
30
use cap_std_ext:: prelude:: CapStdExtDirExt ;
30
31
use chrono:: prelude:: * ;
31
32
use clap:: ValueEnum ;
@@ -1271,6 +1272,7 @@ async fn install_with_sysroot(
1271
1272
rootfs : & RootSetup ,
1272
1273
sysroot : & ostree:: Sysroot ,
1273
1274
boot_uuid : & str ,
1275
+ bound_images : & [ crate :: boundimage:: ResolvedBoundImage ] ,
1274
1276
) -> Result < ( ) > {
1275
1277
let sysroot = SysrootLock :: new_from_sysroot ( & sysroot) . await ?;
1276
1278
// And actually set up the container in that root, returning a deployment and
@@ -1299,33 +1301,51 @@ async fn install_with_sysroot(
1299
1301
tracing:: debug!( "Installed bootloader" ) ;
1300
1302
1301
1303
tracing:: debug!( "Perfoming post-deployment operations" ) ;
1302
- let deployment_root = crate :: utils:: deployment_fd ( & sysroot, & deployment) ?;
1303
- let bound_images = if state. config_opts . skip_bound_images {
1304
- Vec :: new ( )
1305
- } else {
1306
- crate :: boundimage:: query_bound_images ( & deployment_root) ?
1307
- } ;
1308
1304
if !bound_images. is_empty ( ) {
1305
+ // TODO: We shouldn't hardcode the overlay driver for source or
1306
+ // target, but we currently need to in order to reference the location.
1307
+ // For this one, containers-storage: is actually the *host*'s /var/lib/containers
1308
+ // which we are accessing directly.
1309
+ let storage_src = "containers-storage:" ;
1309
1310
// TODO: We only do this dance to initialize `/var` at install time if
1310
1311
// there are bound images today; it minimizes side effects.
1311
1312
// However going forward we really do need to handle a separate /var partition...
1312
1313
// and to do that we may in the general case need to run the `var.mount`
1313
1314
// target from the new root.
1315
+ // Probably the best fix is for us to switch bound images to use the bootc storage.
1314
1316
let varpath = format ! ( "ostree/deploy/{stateroot}/var" ) ;
1315
1317
let var = rootfs
1316
1318
. rootfs_fd
1317
1319
. open_dir ( & varpath)
1318
1320
. with_context ( || format ! ( "Opening {varpath}" ) ) ?;
1319
- Task :: new ( "Mounting deployment /var" , "mount" )
1320
- . args ( [ "--bind" , "." , "/var" ] )
1321
- . cwd ( & var) ?
1322
- . run ( ) ?;
1323
- // podman needs this
1324
- Task :: new ( "Initializing /var/tmp" , "systemd-tmpfiles" )
1325
- . args ( [ "--create" , "--boot" , "--prefix=/var/tmp" ] )
1326
- . verbose ( )
1327
- . run ( ) ?;
1328
- crate :: boundimage:: pull_images ( & deployment_root, bound_images) ?;
1321
+
1322
+ // The skopeo API expects absolute paths, so we make a temporary bind
1323
+ let tmp_dest_var_abs = tempfile:: tempdir ( ) ?;
1324
+ let tmp_dest_var_abs: & Utf8Path = tmp_dest_var_abs. path ( ) . try_into ( ) ?;
1325
+ let mut t = Task :: new ( "Mounting deployment /var" , "mount" )
1326
+ . args ( [ "--bind" , "/proc/self/fd/3" ] )
1327
+ . arg ( tmp_dest_var_abs) ;
1328
+ t. cmd . take_fd_n ( Arc :: new ( OwnedFd :: from ( var) ) , 3 ) ;
1329
+ t. run ( ) ?;
1330
+
1331
+ // And an ephemeral place for the transient state
1332
+ let tmp_runroot = tempfile:: tempdir ( ) ?;
1333
+ let tmp_runroot: & Utf8Path = tmp_runroot. path ( ) . try_into ( ) ?;
1334
+
1335
+ // The destination (target stateroot) + container storage dest
1336
+ let storage_dest = & format ! (
1337
+ "containers-storage:[overlay@{tmp_dest_var_abs}/lib/containers/storage+{tmp_runroot}]"
1338
+ ) ;
1339
+
1340
+ // Now copy each bound image from the host's container storage into the target.
1341
+ for image in bound_images {
1342
+ let image = image. image . as_str ( ) ;
1343
+ Task :: new ( format ! ( "Copying image to target: {}" , image) , "skopeo" )
1344
+ . arg ( "copy" )
1345
+ . arg ( format ! ( "{storage_src}{image}" ) )
1346
+ . arg ( format ! ( "{storage_dest}{image}" ) )
1347
+ . run ( ) ?;
1348
+ }
1329
1349
}
1330
1350
1331
1351
Ok ( ( ) )
@@ -1357,10 +1377,28 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1357
1377
. ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
1358
1378
tracing:: debug!( "boot uuid={boot_uuid}" ) ;
1359
1379
1380
+ let bound_images = if state. config_opts . skip_bound_images {
1381
+ Vec :: new ( )
1382
+ } else {
1383
+ crate :: boundimage:: query_bound_images ( & state. container_root ) ?
1384
+ } ;
1385
+ tracing:: debug!( "bound images={bound_images:?}" ) ;
1386
+
1387
+ // Verify each bound image is present in the container storage
1388
+ let bound_images = {
1389
+ let mut r = Vec :: with_capacity ( bound_images. len ( ) ) ;
1390
+ for image in bound_images {
1391
+ let resolved = crate :: boundimage:: ResolvedBoundImage :: from_image ( & image) . await ?;
1392
+ tracing:: debug!( "Resolved {}: {}" , resolved. image, resolved. digest) ;
1393
+ r. push ( resolved)
1394
+ }
1395
+ r
1396
+ } ;
1397
+
1360
1398
// Initialize the ostree sysroot (repo, stateroot, etc.)
1361
1399
{
1362
1400
let sysroot = initialize_ostree_root ( state, rootfs) . await ?;
1363
- install_with_sysroot ( state, rootfs, & sysroot, & boot_uuid) . await ?;
1401
+ install_with_sysroot ( state, rootfs, & sysroot, & boot_uuid, & bound_images ) . await ?;
1364
1402
// We must drop the sysroot here in order to close any open file
1365
1403
// descriptors.
1366
1404
}
0 commit comments