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
@@ -305,11 +310,13 @@ impl SourceInfo {
305
310
let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
306
311
let xattrs = root. xattrs ( cancellable) ?;
307
312
let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
313
+ let from_ostree_repo = false ;
308
314
Ok ( Self {
309
315
imageref,
310
316
digest,
311
317
commit,
312
318
selinux,
319
+ from_ostree_repo,
313
320
} )
314
321
}
315
322
}
@@ -384,6 +391,14 @@ pub(crate) mod config {
384
391
}
385
392
}
386
393
394
+ pub ( crate ) fn import_config_from_host ( ) -> ostree_container:: store:: ImageProxyConfig {
395
+ let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
396
+ ostree_container:: store:: ImageProxyConfig {
397
+ skopeo_cmd : Some ( skopeo_cmd) ,
398
+ ..Default :: default ( )
399
+ }
400
+ }
401
+
387
402
#[ context( "Creating ostree deployment" ) ]
388
403
async fn initialize_ostree_root_from_self (
389
404
state : & State ,
@@ -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 ?;
@@ -825,11 +863,16 @@ fn installation_complete() {
825
863
println ! ( "Installation complete!" ) ;
826
864
}
827
865
828
- /// Implementation of the `bootc install` CLI command.
829
- pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
830
- let block_opts = opts. block_opts ;
831
- let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
866
+ pub ( crate ) async fn install_takeover (
867
+ opts : InstallBlockDeviceOpts ,
868
+ state : Arc < State > ,
869
+ ) -> Result < ( ) > {
870
+ // The takeover code should have unset this
871
+ assert ! ( !opts. takeover) ;
872
+ block_install_impl ( opts, state) . await
873
+ }
832
874
875
+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
833
876
// This is all blocking stuff
834
877
let mut rootfs = {
835
878
let state = state. clone ( ) ;
@@ -855,6 +898,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
855
898
Ok ( ( ) )
856
899
}
857
900
901
+ /// Implementation of the `bootc install` CLI command.
902
+ pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
903
+ let block_opts = opts. block_opts ;
904
+ let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
905
+ if block_opts. takeover {
906
+ tracing:: debug!( "Performing takeover installation from host" ) ;
907
+ return crate :: systemtakeover:: run_from_host ( block_opts, state) . await ;
908
+ }
909
+
910
+ block_install_impl ( block_opts, state) . await
911
+ }
912
+
858
913
#[ context( "Verifying empty rootfs" ) ]
859
914
fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
860
915
for e in rootfs_fd. entries ( ) ? {
0 commit comments