@@ -564,26 +564,34 @@ pub(crate) fn print_configuration() -> Result<()> {
564
564
}
565
565
566
566
#[ context( "Creating ostree deployment" ) ]
567
- async fn initialize_ostree_root ( state : & State , root_setup : & RootSetup ) -> Result < Storage > {
567
+ async fn initialize_ostree_root ( state : & State , root_setup : & RootSetup ) -> Result < ( Storage , bool ) > {
568
568
let sepolicy = state. load_policy ( ) ?;
569
569
let sepolicy = sepolicy. as_ref ( ) ;
570
570
// Load a fd for the mounted target physical root
571
571
let rootfs_dir = & root_setup. rootfs_fd ;
572
572
let rootfs = root_setup. rootfs . as_path ( ) ;
573
573
let cancellable = gio:: Cancellable :: NONE ;
574
574
575
+ let stateroot = state. stateroot ( ) ;
576
+
577
+ let has_ostree = rootfs_dir. try_exists ( "ostree/repo" ) ?;
578
+ if !has_ostree {
579
+ Task :: new_and_run (
580
+ "Initializing ostree layout" ,
581
+ "ostree" ,
582
+ [ "admin" , "init-fs" , "--modern" , rootfs. as_str ( ) ] ,
583
+ ) ?;
584
+ } else {
585
+ println ! ( "Reusing extant ostree layout" ) ;
586
+ let path = "." . into ( ) ;
587
+ let _ = crate :: utils:: open_dir_remount_rw ( rootfs_dir, path)
588
+ . context ( "remounting sysroot as read-write" ) ?;
589
+ }
590
+
575
591
// Ensure that the physical root is labeled.
576
592
// Another implementation: https://github.com/coreos/coreos-assembler/blob/3cd3307904593b3a131b81567b13a4d0b6fe7c90/src/create_disk.sh#L295
577
593
crate :: lsm:: ensure_dir_labeled ( rootfs_dir, "" , Some ( "/" . into ( ) ) , 0o755 . into ( ) , sepolicy) ?;
578
594
579
- let stateroot = state. stateroot ( ) ;
580
-
581
- Task :: new_and_run (
582
- "Initializing ostree layout" ,
583
- "ostree" ,
584
- [ "admin" , "init-fs" , "--modern" , rootfs. as_str ( ) ] ,
585
- ) ?;
586
-
587
595
// And also label /boot AKA xbootldr, if it exists
588
596
let bootdir = rootfs. join ( "boot" ) ;
589
597
if bootdir. try_exists ( ) ? {
@@ -607,9 +615,14 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result
607
615
let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
608
616
sysroot. load ( cancellable) ?;
609
617
610
- sysroot
611
- . init_osname ( stateroot, cancellable)
612
- . context ( "initializing stateroot" ) ?;
618
+ let stateroot_exists = rootfs_dir. try_exists ( format ! ( "ostree/deploy/{stateroot}" ) ) ?;
619
+ if stateroot_exists {
620
+ anyhow:: bail!( "Cannot redeploy over extant stateroot {stateroot}" ) ;
621
+ } else {
622
+ sysroot
623
+ . init_osname ( stateroot, cancellable)
624
+ . context ( "initializing stateroot" ) ?;
625
+ }
613
626
614
627
let sysroot_dir = Dir :: reopen_dir ( & crate :: utils:: sysroot_fd ( & sysroot) ) ?;
615
628
@@ -637,14 +650,15 @@ async fn initialize_ostree_root(state: &State, root_setup: &RootSetup) -> Result
637
650
let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
638
651
sysroot. load ( cancellable) ?;
639
652
let sysroot = SysrootLock :: new_from_sysroot ( & sysroot) . await ?;
640
- Storage :: new ( sysroot, & temp_run)
653
+ Ok ( ( Storage :: new ( sysroot, & temp_run) ? , has_ostree ) )
641
654
}
642
655
643
656
#[ context( "Creating ostree deployment" ) ]
644
657
async fn install_container (
645
658
state : & State ,
646
659
root_setup : & RootSetup ,
647
660
sysroot : & ostree:: Sysroot ,
661
+ has_ostree : bool ,
648
662
) -> Result < ( ostree:: Deployment , InstallAleph ) > {
649
663
let sepolicy = state. load_policy ( ) ?;
650
664
let sepolicy = sepolicy. as_ref ( ) ;
@@ -730,6 +744,7 @@ async fn install_container(
730
744
options. kargs = Some ( kargs. as_slice ( ) ) ;
731
745
options. target_imgref = Some ( & state. target_imgref ) ;
732
746
options. proxy_cfg = proxy_cfg;
747
+ options. no_clean = has_ostree;
733
748
let imgstate = crate :: utils:: async_task_with_spinner (
734
749
"Deploying container image" ,
735
750
ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) ,
@@ -1272,10 +1287,11 @@ async fn install_with_sysroot(
1272
1287
sysroot : & Storage ,
1273
1288
boot_uuid : & str ,
1274
1289
bound_images : & [ crate :: boundimage:: ResolvedBoundImage ] ,
1290
+ has_ostree : bool ,
1275
1291
) -> Result < ( ) > {
1276
1292
// And actually set up the container in that root, returning a deployment and
1277
1293
// the aleph state (see below).
1278
- let ( _deployment, aleph) = install_container ( state, rootfs, & sysroot) . await ?;
1294
+ let ( _deployment, aleph) = install_container ( state, rootfs, & sysroot, has_ostree ) . await ?;
1279
1295
// Write the aleph data that captures the system state at the time of provisioning for aid in future debugging.
1280
1296
rootfs
1281
1297
. rootfs_fd
@@ -1336,6 +1352,19 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1336
1352
. ok_or_else ( || anyhow ! ( "No uuid for boot/root" ) ) ?;
1337
1353
tracing:: debug!( "boot uuid={boot_uuid}" ) ;
1338
1354
1355
+ // If we're doing an alongside install, then the /dev bootupd sees needs to be the host's.
1356
+ // What we probably really want to do here is tunnel in the host's /dev properly, but for now
1357
+ // just copy /dev/disk
1358
+ if rootfs. skip_finalize {
1359
+ if !Utf8Path :: new ( "/dev/disk" ) . try_exists ( ) ? {
1360
+ Task :: new_and_run (
1361
+ "Copying host /dev/disk" ,
1362
+ "cp" ,
1363
+ [ "-a" , "/proc/1/root/dev/disk" , "/dev/disk" ] ,
1364
+ ) ?;
1365
+ }
1366
+ }
1367
+
1339
1368
let bound_images = if state. config_opts . skip_bound_images {
1340
1369
Vec :: new ( )
1341
1370
} else {
@@ -1356,8 +1385,16 @@ async fn install_to_filesystem_impl(state: &State, rootfs: &mut RootSetup) -> Re
1356
1385
1357
1386
// Initialize the ostree sysroot (repo, stateroot, etc.)
1358
1387
{
1359
- let sysroot = initialize_ostree_root ( state, rootfs) . await ?;
1360
- install_with_sysroot ( state, rootfs, & sysroot, & boot_uuid, & bound_images) . await ?;
1388
+ let ( sysroot, has_ostree) = initialize_ostree_root ( state, rootfs) . await ?;
1389
+ install_with_sysroot (
1390
+ state,
1391
+ rootfs,
1392
+ & sysroot,
1393
+ & boot_uuid,
1394
+ & bound_images,
1395
+ has_ostree,
1396
+ )
1397
+ . await ?;
1361
1398
// We must drop the sysroot here in order to close any open file
1362
1399
// descriptors.
1363
1400
}
@@ -1498,7 +1535,8 @@ fn remove_all_in_dir_no_xdev(d: &Dir) -> Result<()> {
1498
1535
1499
1536
#[ context( "Removing boot directory content" ) ]
1500
1537
fn clean_boot_directories ( rootfs : & Dir ) -> Result < ( ) > {
1501
- let bootdir = rootfs. open_dir ( BOOT ) . context ( "Opening /boot" ) ?;
1538
+ let bootdir =
1539
+ crate :: utils:: open_dir_remount_rw ( rootfs, BOOT . into ( ) ) . context ( "Opening /boot" ) ?;
1502
1540
// This should not remove /boot/efi note.
1503
1541
remove_all_in_dir_no_xdev ( & bootdir) ?;
1504
1542
if ARCH_USES_EFI {
@@ -1589,12 +1627,35 @@ pub(crate) async fn install_to_filesystem(
1589
1627
if !st. is_dir ( ) {
1590
1628
anyhow:: bail!( "Not a directory: {root_path}" ) ;
1591
1629
}
1630
+
1631
+ let inspect = crate :: mount:: inspect_filesystem ( & fsopts. root_path ) ?;
1632
+
1633
+ let alternative_root = fsopts. root_path . join ( "sysroot" ) ;
1634
+ let root_path = match inspect. source . as_str ( ) {
1635
+ // Our target filesystem is an overlay, the true root is in `/sysroot`
1636
+ "overlay" => {
1637
+ tracing:: debug!(
1638
+ "Overlay filesystem detected, using {alternative_root} instead of {root_path} as target root"
1639
+ ) ;
1640
+ & alternative_root
1641
+ }
1642
+ _ => root_path,
1643
+ } ;
1592
1644
let rootfs_fd = Dir :: open_ambient_dir ( root_path, cap_std:: ambient_authority ( ) )
1593
1645
. with_context ( || format ! ( "Opening target root directory {root_path}" ) ) ?;
1646
+
1647
+ tracing:: debug!( "Root filesystem: {root_path}" ) ;
1648
+
1594
1649
if let Some ( false ) = ostree_ext:: mountutil:: is_mountpoint ( & rootfs_fd, "." ) ? {
1595
1650
anyhow:: bail!( "Not a mountpoint: {root_path}" ) ;
1596
1651
}
1597
1652
1653
+ let fsopts = {
1654
+ let mut fsopts = fsopts. clone ( ) ;
1655
+ fsopts. root_path = root_path. clone ( ) ;
1656
+ fsopts
1657
+ } ;
1658
+
1598
1659
// Gather global state, destructuring the provided options.
1599
1660
// IMPORTANT: We might re-execute the current process in this function (for SELinux among other things)
1600
1661
// IMPORTANT: and hence anything that is done before MUST BE IDEMPOTENT.
0 commit comments