@@ -11,7 +11,7 @@ pub(crate) mod config;
1111pub ( crate ) mod osconfig;
1212
1313use std:: io:: Write ;
14- use std:: os:: fd:: AsFd ;
14+ use std:: os:: fd:: { AsFd , OwnedFd } ;
1515use std:: os:: unix:: process:: CommandExt ;
1616use std:: path:: Path ;
1717use std:: process:: Command ;
@@ -26,6 +26,7 @@ use camino::Utf8PathBuf;
2626use cap_std:: fs:: { Dir , MetadataExt } ;
2727use cap_std_ext:: cap_std;
2828use cap_std_ext:: cap_std:: fs_utf8:: DirEntry as DirEntryUtf8 ;
29+ use cap_std_ext:: cmdext:: CapStdExtCommandExt ;
2930use cap_std_ext:: prelude:: CapStdExtDirExt ;
3031use chrono:: prelude:: * ;
3132use clap:: ValueEnum ;
@@ -1271,6 +1272,7 @@ async fn install_with_sysroot(
12711272 rootfs : & RootSetup ,
12721273 sysroot : & ostree:: Sysroot ,
12731274 boot_uuid : & str ,
1275+ bound_images : & [ crate :: boundimage:: ResolvedBoundImage ] ,
12741276) -> Result < ( ) > {
12751277 let sysroot = SysrootLock :: new_from_sysroot ( & sysroot) . await ?;
12761278 // And actually set up the container in that root, returning a deployment and
@@ -1299,33 +1301,51 @@ async fn install_with_sysroot(
12991301 tracing:: debug!( "Installed bootloader" ) ;
13001302
13011303 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- } ;
13081304 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:" ;
13091310 // TODO: We only do this dance to initialize `/var` at install time if
13101311 // there are bound images today; it minimizes side effects.
13111312 // However going forward we really do need to handle a separate /var partition...
13121313 // and to do that we may in the general case need to run the `var.mount`
13131314 // target from the new root.
1315+ // Probably the best fix is for us to switch bound images to use the bootc storage.
13141316 let varpath = format ! ( "ostree/deploy/{stateroot}/var" ) ;
13151317 let var = rootfs
13161318 . rootfs_fd
13171319 . open_dir ( & varpath)
13181320 . 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+ }
13291349 }
13301350
13311351 Ok ( ( ) )
@@ -1357,10 +1377,28 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
13571377 . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
13581378 tracing:: debug!( "boot uuid={boot_uuid}" ) ;
13591379
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+
13601398 // Initialize the ostree sysroot (repo, stateroot, etc.)
13611399 {
13621400 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 ?;
13641402 // We must drop the sysroot here in order to close any open file
13651403 // descriptors.
13661404 }
0 commit comments