@@ -35,6 +35,7 @@ use ostree_ext::container as ostree_container;
35
35
use ostree_ext:: oci_spec;
36
36
use ostree_ext:: ostree;
37
37
use ostree_ext:: prelude:: Cast ;
38
+ use ostree_ext:: sysroot:: SysrootLock ;
38
39
use rustix:: fs:: { FileTypeExt , MetadataExt as _} ;
39
40
use serde:: { Deserialize , Serialize } ;
40
41
@@ -160,6 +161,11 @@ pub(crate) struct InstallConfigOpts {
160
161
#[ clap( long) ]
161
162
#[ serde( default ) ]
162
163
pub ( crate ) generic_image : bool ,
164
+
165
+ /// Do not pull any "logically bound" images at install time.
166
+ #[ clap( long, hide = true ) ]
167
+ #[ serde( default ) ]
168
+ pub ( crate ) skip_bound_images : bool ,
163
169
}
164
170
165
171
#[ derive( Debug , Clone , clap:: Parser , Serialize , Deserialize , PartialEq , Eq ) ]
@@ -1219,23 +1225,21 @@ async fn prepare_install(
1219
1225
Ok ( state)
1220
1226
}
1221
1227
1222
- async fn install_to_filesystem_impl ( state : & State , rootfs : & mut RootSetup ) -> Result < ( ) > {
1223
- if matches ! ( state. selinux_state, SELinuxFinalState :: ForceTargetDisabled ) {
1224
- rootfs. kargs . push ( "selinux=0" . to_string ( ) ) ;
1225
- }
1226
-
1227
- // We verify this upfront because it's currently required by bootupd
1228
- let boot_uuid = rootfs
1229
- . get_boot_uuid ( ) ?
1230
- . or ( rootfs. rootfs_uuid . as_deref ( ) )
1231
- . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
1232
- tracing:: debug!( "boot uuid={boot_uuid}" ) ;
1233
-
1234
- // Initialize the ostree sysroot (repo, stateroot, etc.)
1235
- let sysroot = initialize_ostree_root ( state, rootfs) . await ?;
1228
+ /// Given a baseline root filesystem with an ostree sysroot initialized:
1229
+ /// - install the container to that root
1230
+ /// - install the bootloader
1231
+ /// - Other post operations, such as pulling bound images
1232
+ async fn install_with_sysroot (
1233
+ state : & State ,
1234
+ rootfs : & RootSetup ,
1235
+ sysroot : & ostree:: Sysroot ,
1236
+ boot_uuid : & str ,
1237
+ ) -> Result < ( ) > {
1238
+ let sysroot = SysrootLock :: new_from_sysroot ( & sysroot) . await ?;
1236
1239
// And actually set up the container in that root, returning a deployment and
1237
1240
// the aleph state (see below).
1238
1241
let ( deployment, aleph) = install_container ( state, rootfs, & sysroot) . await ?;
1242
+ let stateroot = deployment. osname ( ) ;
1239
1243
// Write the aleph data that captures the system state at the time of provisioning for aid in future debugging.
1240
1244
rootfs
1241
1245
. rootfs_fd
@@ -1244,6 +1248,7 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1244
1248
anyhow:: Ok ( ( ) )
1245
1249
} )
1246
1250
. context ( "Writing aleph version" ) ?;
1251
+
1247
1252
if cfg ! ( target_arch = "s390x" ) {
1248
1253
// TODO: Integrate s390x support into install_via_bootupd
1249
1254
crate :: bootloader:: install_via_zipl ( & rootfs. device_info , boot_uuid) ?;
@@ -1254,12 +1259,62 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1254
1259
& state. config_opts ,
1255
1260
) ?;
1256
1261
}
1262
+ tracing:: debug!( "Installed bootloader" ) ;
1257
1263
1258
- // After this point, we need to drop all open references to the filesystem
1259
- drop ( deployment) ;
1260
- drop ( sysroot) ;
1264
+ tracing:: debug!( "Perfoming post-deployment operations" ) ;
1265
+ let deployment_root = crate :: utils:: deployment_fd ( & sysroot, & deployment) ?;
1266
+ let bound_images = if state. config_opts . skip_bound_images {
1267
+ Vec :: new ( )
1268
+ } else {
1269
+ crate :: boundimage:: query_bound_images ( & deployment_root) ?
1270
+ } ;
1271
+ if !bound_images. is_empty ( ) {
1272
+ // TODO: We only do this dance to initialize `/var` at install time if
1273
+ // there are bound images today; it minimizes side effects.
1274
+ // However going forward we really do need to handle a separate /var partition...
1275
+ // and to do that we may in the general case need to run the `var.mount`
1276
+ // target from the new root.
1277
+ let varpath = format ! ( "ostree/deploy/{stateroot}/var" ) ;
1278
+ let var = rootfs
1279
+ . rootfs_fd
1280
+ . open_dir ( & varpath)
1281
+ . with_context ( || format ! ( "Opening {varpath}" ) ) ?;
1282
+ Task :: new ( "Mounting deployment /var" , "mount" )
1283
+ . args ( [ "--bind" , "." , "/var" ] )
1284
+ . cwd ( & var) ?
1285
+ . run ( ) ?;
1286
+ // podman needs this
1287
+ Task :: new ( "Initializing /var/tmp" , "systemd-tmpfiles" )
1288
+ . args ( [ "--create" , "--boot" , "--prefix=/var/tmp" ] )
1289
+ . verbose ( )
1290
+ . run ( ) ?;
1291
+ crate :: boundimage:: pull_images ( & deployment_root, bound_images) ?;
1292
+ }
1261
1293
1262
- tracing:: debug!( "Installed bootloader" ) ;
1294
+ Ok ( ( ) )
1295
+ }
1296
+
1297
+ async fn install_to_filesystem_impl ( state : & State , rootfs : & mut RootSetup ) -> Result < ( ) > {
1298
+ if matches ! ( state. selinux_state, SELinuxFinalState :: ForceTargetDisabled ) {
1299
+ rootfs. kargs . push ( "selinux=0" . to_string ( ) ) ;
1300
+ }
1301
+ // Drop exclusive ownership since we're done with mutation
1302
+ let rootfs = & * rootfs;
1303
+
1304
+ // We verify this upfront because it's currently required by bootupd
1305
+ let boot_uuid = rootfs
1306
+ . get_boot_uuid ( ) ?
1307
+ . or ( rootfs. rootfs_uuid . as_deref ( ) )
1308
+ . ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
1309
+ tracing:: debug!( "boot uuid={boot_uuid}" ) ;
1310
+
1311
+ // Initialize the ostree sysroot (repo, stateroot, etc.)
1312
+ {
1313
+ let sysroot = initialize_ostree_root ( state, rootfs) . await ?;
1314
+ install_with_sysroot ( state, rootfs, & sysroot, & boot_uuid) . await ?;
1315
+ // We must drop the sysroot here in order to close any open file
1316
+ // descriptors.
1317
+ }
1263
1318
1264
1319
// Finalize mounted filesystems
1265
1320
if !rootfs. skip_finalize {
0 commit comments