6
6
7
7
// This sub-module is the "basic" installer that handles creating basic block device
8
8
// and filesystem setup.
9
- mod baseline;
9
+ pub ( crate ) mod baseline;
10
10
11
11
use std:: io:: BufWriter ;
12
12
use std:: io:: Write ;
@@ -36,6 +36,9 @@ use crate::lsm::lsm_label;
36
36
use crate :: task:: Task ;
37
37
use crate :: utils:: run_in_host_mountns;
38
38
39
+ /// The path we use to access files on the host
40
+ pub ( crate ) const HOST_RUNDIR : & str = "/run/host" ;
41
+
39
42
/// The default "stateroot" or "osname"; see https://github.com/ostreedev/ostree/issues/2794
40
43
const STATEROOT_DEFAULT : & str = "default" ;
41
44
/// The toplevel boot directory
@@ -171,6 +174,8 @@ pub(crate) struct SourceInfo {
171
174
pub ( crate ) commit : String ,
172
175
/// Whether or not SELinux appears to be enabled in the source commit
173
176
pub ( crate ) selinux : bool ,
177
+ /// If we should find the image in sysroot/repo, not in containers/storage
178
+ pub ( crate ) from_ostree_repo : bool ,
174
179
}
175
180
176
181
// Shared read-only global state
@@ -303,11 +308,13 @@ impl SourceInfo {
303
308
let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
304
309
let xattrs = root. xattrs ( cancellable) ?;
305
310
let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
311
+ let from_ostree_repo = false ;
306
312
Ok ( Self {
307
313
imageref,
308
314
digest,
309
315
commit,
310
316
selinux,
317
+ from_ostree_repo,
311
318
} )
312
319
}
313
320
}
@@ -382,6 +389,14 @@ pub(crate) mod config {
382
389
}
383
390
}
384
391
392
+ pub ( crate ) fn import_config_from_host ( ) -> ostree_container:: store:: ImageProxyConfig {
393
+ let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
394
+ ostree_container:: store:: ImageProxyConfig {
395
+ skopeo_cmd : Some ( skopeo_cmd) ,
396
+ ..Default :: default ( )
397
+ }
398
+ }
399
+
385
400
#[ context( "Creating ostree deployment" ) ]
386
401
async fn initialize_ostree_root_from_self (
387
402
state : & State ,
@@ -407,12 +422,12 @@ async fn initialize_ostree_root_from_self(
407
422
name : imgref. to_string ( ) ,
408
423
} ;
409
424
ostree_container:: OstreeImageReference {
410
- sigverify : target_sigverify,
425
+ sigverify : target_sigverify. clone ( ) ,
411
426
imgref,
412
427
}
413
428
} else {
414
429
ostree_container:: OstreeImageReference {
415
- sigverify : target_sigverify,
430
+ sigverify : target_sigverify. clone ( ) ,
416
431
imgref : state. source . imageref . clone ( ) ,
417
432
}
418
433
} ;
@@ -442,49 +457,72 @@ async fn initialize_ostree_root_from_self(
442
457
443
458
let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
444
459
sysroot. load ( cancellable) ?;
460
+ let dest_repo = & sysroot. repo ( ) . unwrap ( ) ;
445
461
446
462
// We need to fetch the container image from the root mount namespace
447
- let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
448
- let proxy_cfg = ostree_container:: store:: ImageProxyConfig {
449
- skopeo_cmd : Some ( skopeo_cmd) ,
450
- ..Default :: default ( )
451
- } ;
452
-
453
- let mut temporary_dir = None ;
454
- let src_imageref = if skopeo_supports_containers_storage ( ) ? {
455
- // We always use exactly the digest of the running image to ensure predictability.
456
- let spec =
457
- crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
458
- ostree_container:: ImageReference {
459
- transport : ostree_container:: Transport :: ContainerStorage ,
460
- name : spec,
461
- }
462
- } else {
463
- let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
464
- let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
465
- let r = copy_to_oci ( & state. source . imageref , path) ?;
466
- temporary_dir = Some ( td) ;
467
- r
468
- } ;
469
- let src_imageref = ostree_container:: OstreeImageReference {
470
- // There are no signatures to verify since we're fetching the already
471
- // pulled container.
472
- sigverify : ostree_container:: SignatureSource :: ContainerPolicyAllowInsecure ,
473
- imgref : src_imageref,
474
- } ;
463
+ let proxy_cfg = import_config_from_host ( ) ;
475
464
476
465
let kargs = root_setup
477
466
. kargs
478
467
. iter ( )
479
468
. map ( |v| v. as_str ( ) )
480
469
. collect :: < Vec < _ > > ( ) ;
470
+
471
+ // Default image reference pulls from the running container image.
472
+ let mut src_imageref = ostree_container:: OstreeImageReference {
473
+ // There are no signatures to verify since we're fetching the already
474
+ // pulled container.
475
+ sigverify : SignatureSource :: ContainerPolicyAllowInsecure ,
476
+ imgref : state. source . imageref . clone ( ) ,
477
+ } ;
481
478
#[ allow( clippy:: needless_update) ]
482
- let options = ostree_container:: deploy:: DeployOpts {
479
+ let mut options = ostree_container:: deploy:: DeployOpts {
483
480
kargs : Some ( kargs. as_slice ( ) ) ,
484
- target_imgref : Some ( & target_imgref) ,
485
481
proxy_cfg : Some ( proxy_cfg) ,
486
482
..Default :: default ( )
487
483
} ;
484
+
485
+ let mut temporary_dir = None ;
486
+ if state. source . from_ostree_repo {
487
+ let root = Dir :: open_ambient_dir ( "/" , cap_std:: ambient_authority ( ) ) ?;
488
+ let host_repo = {
489
+ let repodir = root
490
+ . open_dir ( "sysroot/repo" )
491
+ . context ( "Opening sysroot/repo" ) ?;
492
+ ostree:: Repo :: open_at_dir ( & repodir, "." ) ?
493
+ } ;
494
+ ostree_container:: store:: copy_as (
495
+ & host_repo,
496
+ & state. source . imageref ,
497
+ & dest_repo,
498
+ & target_imgref. imgref ,
499
+ )
500
+ . await
501
+ . context ( "Copying image from host repo" ) ?;
502
+ // We already copied the image, so src == target
503
+ src_imageref = target_imgref. clone ( ) ;
504
+ options. target_imgref = None ;
505
+ } else {
506
+ if skopeo_supports_containers_storage ( ) ? {
507
+ // We always use exactly the digest of the running image to ensure predictability.
508
+ let spec =
509
+ crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
510
+ ostree_container:: ImageReference {
511
+ transport : ostree_container:: Transport :: ContainerStorage ,
512
+ name : spec,
513
+ }
514
+ } else {
515
+ let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
516
+ let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
517
+ let r = copy_to_oci ( & state. source . imageref , path) ?;
518
+ temporary_dir = Some ( td) ;
519
+ r
520
+ } ;
521
+ // In this case the deploy code is pulling the container, so set it up to
522
+ // generate a target image reference.
523
+ options. target_imgref = Some ( & target_imgref) ;
524
+ }
525
+
488
526
println ! ( "Creating initial deployment" ) ;
489
527
let state =
490
528
ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
@@ -811,11 +849,16 @@ fn installation_complete() {
811
849
println ! ( "Installation complete!" ) ;
812
850
}
813
851
814
- /// Implementation of the `bootc install` CLI command.
815
- pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
816
- let block_opts = opts. block_opts ;
817
- let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
852
+ pub ( crate ) async fn install_takeover (
853
+ opts : InstallBlockDeviceOpts ,
854
+ state : Arc < State > ,
855
+ ) -> Result < ( ) > {
856
+ // The takeover code should have unset this
857
+ assert ! ( !opts. takeover) ;
858
+ block_install_impl ( opts, state) . await
859
+ }
818
860
861
+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
819
862
// This is all blocking stuff
820
863
let mut rootfs = {
821
864
let state = state. clone ( ) ;
@@ -841,6 +884,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
841
884
Ok ( ( ) )
842
885
}
843
886
887
+ /// Implementation of the `bootc install` CLI command.
888
+ pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
889
+ let block_opts = opts. block_opts ;
890
+ let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
891
+ if block_opts. takeover {
892
+ tracing:: debug!( "Performing takeover installation from host" ) ;
893
+ return crate :: systemtakeover:: run_from_host ( block_opts, state) . await ;
894
+ }
895
+
896
+ block_install_impl ( block_opts, state) . await
897
+ }
898
+
844
899
#[ context( "Verifying empty rootfs" ) ]
845
900
fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
846
901
for e in rootfs_fd. entries ( ) ? {
0 commit comments