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 ;
@@ -35,6 +35,9 @@ use crate::containerenv::ContainerExecutionInfo;
35
35
use crate :: task:: Task ;
36
36
use crate :: utils:: run_in_host_mountns;
37
37
38
+ /// The path we use to access files on the host
39
+ pub ( crate ) const HOST_RUNDIR : & str = "/run/host" ;
40
+
38
41
/// The default "stateroot" or "osname"; see https://github.com/ostreedev/ostree/issues/2794
39
42
const STATEROOT_DEFAULT : & str = "default" ;
40
43
/// The toplevel boot directory
@@ -170,6 +173,8 @@ pub(crate) struct SourceInfo {
170
173
pub ( crate ) commit : String ,
171
174
/// Whether or not SELinux appears to be enabled in the source commit
172
175
pub ( crate ) selinux : bool ,
176
+ /// If we should find the image in sysroot/repo, not in containers/storage
177
+ pub ( crate ) from_ostree_repo : bool ,
173
178
}
174
179
175
180
// Shared read-only global state
@@ -319,11 +324,13 @@ impl SourceInfo {
319
324
let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
320
325
let xattrs = root. xattrs ( cancellable) ?;
321
326
let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
327
+ let from_ostree_repo = false ;
322
328
Ok ( Self {
323
329
imageref,
324
330
digest,
325
331
commit,
326
332
selinux,
333
+ from_ostree_repo,
327
334
} )
328
335
}
329
336
}
@@ -398,6 +405,14 @@ pub(crate) mod config {
398
405
}
399
406
}
400
407
408
+ pub ( crate ) fn import_config_from_host ( ) -> ostree_container:: store:: ImageProxyConfig {
409
+ let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
410
+ ostree_container:: store:: ImageProxyConfig {
411
+ skopeo_cmd : Some ( skopeo_cmd) ,
412
+ ..Default :: default ( )
413
+ }
414
+ }
415
+
401
416
#[ context( "Creating ostree deployment" ) ]
402
417
async fn initialize_ostree_root_from_self (
403
418
state : & State ,
@@ -456,49 +471,72 @@ async fn initialize_ostree_root_from_self(
456
471
457
472
let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
458
473
sysroot. load ( cancellable) ?;
474
+ let dest_repo = & sysroot. repo ( ) ;
459
475
460
476
// We need to fetch the container image from the root mount namespace
461
- let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
462
- let proxy_cfg = ostree_container:: store:: ImageProxyConfig {
463
- skopeo_cmd : Some ( skopeo_cmd) ,
464
- ..Default :: default ( )
465
- } ;
466
-
467
- let mut temporary_dir = None ;
468
- let src_imageref = if skopeo_supports_containers_storage ( ) ? {
469
- // We always use exactly the digest of the running image to ensure predictability.
470
- let spec =
471
- crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
472
- ostree_container:: ImageReference {
473
- transport : ostree_container:: Transport :: ContainerStorage ,
474
- name : spec,
475
- }
476
- } else {
477
- let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
478
- let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
479
- let r = copy_to_oci ( & state. source . imageref , path) ?;
480
- temporary_dir = Some ( td) ;
481
- r
482
- } ;
483
- let src_imageref = ostree_container:: OstreeImageReference {
484
- // There are no signatures to verify since we're fetching the already
485
- // pulled container.
486
- sigverify : ostree_container:: SignatureSource :: ContainerPolicyAllowInsecure ,
487
- imgref : src_imageref,
488
- } ;
477
+ let proxy_cfg = import_config_from_host ( ) ;
489
478
490
479
let kargs = root_setup
491
480
. kargs
492
481
. iter ( )
493
482
. map ( |v| v. as_str ( ) )
494
483
. collect :: < Vec < _ > > ( ) ;
484
+
485
+ // Default image reference pulls from the running container image.
486
+ let mut src_imageref = ostree_container:: OstreeImageReference {
487
+ // There are no signatures to verify since we're fetching the already
488
+ // pulled container.
489
+ sigverify : SignatureSource :: ContainerPolicyAllowInsecure ,
490
+ imgref : state. source . imageref . clone ( ) ,
491
+ } ;
495
492
#[ allow( clippy:: needless_update) ]
496
- let options = ostree_container:: deploy:: DeployOpts {
493
+ let mut options = ostree_container:: deploy:: DeployOpts {
497
494
kargs : Some ( kargs. as_slice ( ) ) ,
498
- target_imgref : Some ( & target_imgref) ,
499
495
proxy_cfg : Some ( proxy_cfg) ,
500
496
..Default :: default ( )
501
497
} ;
498
+
499
+ let mut temporary_dir = None ;
500
+ if state. source . from_ostree_repo {
501
+ let root = Dir :: open_ambient_dir ( "/" , cap_std:: ambient_authority ( ) ) ?;
502
+ let host_repo = {
503
+ let repodir = root
504
+ . open_dir ( "sysroot/repo" )
505
+ . context ( "Opening sysroot/repo" ) ?;
506
+ ostree:: Repo :: open_at_dir ( & repodir, "." ) ?
507
+ } ;
508
+ ostree_container:: store:: copy_as (
509
+ & host_repo,
510
+ & state. source . imageref ,
511
+ & dest_repo,
512
+ & target_imgref. imgref ,
513
+ )
514
+ . await
515
+ . context ( "Copying image from host repo" ) ?;
516
+ // We already copied the image, so src == target
517
+ src_imageref = target_imgref. clone ( ) ;
518
+ options. target_imgref = None ;
519
+ } else {
520
+ if skopeo_supports_containers_storage ( ) ? {
521
+ // We always use exactly the digest of the running image to ensure predictability.
522
+ let spec =
523
+ crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
524
+ ostree_container:: ImageReference {
525
+ transport : ostree_container:: Transport :: ContainerStorage ,
526
+ name : spec,
527
+ }
528
+ } else {
529
+ let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
530
+ let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
531
+ let r = copy_to_oci ( & state. source . imageref , path) ?;
532
+ temporary_dir = Some ( td) ;
533
+ r
534
+ } ;
535
+ // In this case the deploy code is pulling the container, so set it up to
536
+ // generate a target image reference.
537
+ options. target_imgref = Some ( & target_imgref) ;
538
+ }
539
+
502
540
println ! ( "Creating initial deployment" ) ;
503
541
let state =
504
542
ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
@@ -839,11 +877,16 @@ fn installation_complete() {
839
877
println ! ( "Installation complete!" ) ;
840
878
}
841
879
842
- /// Implementation of the `bootc install` CLI command.
843
- pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
844
- let block_opts = opts. block_opts ;
845
- let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
880
+ pub ( crate ) async fn install_takeover (
881
+ opts : InstallBlockDeviceOpts ,
882
+ state : Arc < State > ,
883
+ ) -> Result < ( ) > {
884
+ // The takeover code should have unset this
885
+ assert ! ( !opts. takeover) ;
886
+ block_install_impl ( opts, state) . await
887
+ }
846
888
889
+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
847
890
// This is all blocking stuff
848
891
let mut rootfs = {
849
892
let state = state. clone ( ) ;
@@ -869,6 +912,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
869
912
Ok ( ( ) )
870
913
}
871
914
915
+ /// Implementation of the `bootc install` CLI command.
916
+ pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
917
+ let block_opts = opts. block_opts ;
918
+ let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
919
+ if block_opts. takeover {
920
+ tracing:: debug!( "Performing takeover installation from host" ) ;
921
+ return crate :: systemtakeover:: run_from_host ( block_opts, state) . await ;
922
+ }
923
+
924
+ block_install_impl ( block_opts, state) . await
925
+ }
926
+
872
927
#[ context( "Verifying empty rootfs" ) ]
873
928
fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
874
929
for e in rootfs_fd. entries ( ) ? {
0 commit comments