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 ;
@@ -37,6 +37,9 @@ use crate::containerenv::ContainerExecutionInfo;
37
37
use crate :: task:: Task ;
38
38
use crate :: utils:: run_in_host_mountns;
39
39
40
+ /// The path we use to access files on the host
41
+ pub ( crate ) const HOST_RUNDIR : & str = "/run/host" ;
42
+
40
43
/// The default "stateroot" or "osname"; see https://github.com/ostreedev/ostree/issues/2794
41
44
const STATEROOT_DEFAULT : & str = "default" ;
42
45
/// The toplevel boot directory
@@ -196,6 +199,8 @@ pub(crate) struct SourceInfo {
196
199
pub ( crate ) commit : String ,
197
200
/// Whether or not SELinux appears to be enabled in the source commit
198
201
pub ( crate ) selinux : bool ,
202
+ /// If we should find the image in sysroot/repo, not in containers/storage
203
+ pub ( crate ) from_ostree_repo : bool ,
199
204
}
200
205
201
206
// Shared read-only global state
@@ -345,11 +350,13 @@ impl SourceInfo {
345
350
let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
346
351
let xattrs = root. xattrs ( cancellable) ?;
347
352
let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
353
+ let from_ostree_repo = false ;
348
354
Ok ( Self {
349
355
imageref,
350
356
digest,
351
357
commit,
352
358
selinux,
359
+ from_ostree_repo,
353
360
} )
354
361
}
355
362
}
@@ -424,6 +431,14 @@ pub(crate) mod config {
424
431
}
425
432
}
426
433
434
+ pub ( crate ) fn import_config_from_host ( ) -> ostree_container:: store:: ImageProxyConfig {
435
+ let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
436
+ ostree_container:: store:: ImageProxyConfig {
437
+ skopeo_cmd : Some ( skopeo_cmd) ,
438
+ ..Default :: default ( )
439
+ }
440
+ }
441
+
427
442
#[ context( "Creating ostree deployment" ) ]
428
443
async fn initialize_ostree_root_from_self (
429
444
state : & State ,
@@ -492,36 +507,10 @@ async fn initialize_ostree_root_from_self(
492
507
493
508
let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
494
509
sysroot. load ( cancellable) ?;
510
+ let dest_repo = & sysroot. repo ( ) ;
495
511
496
512
// We need to fetch the container image from the root mount namespace
497
- let skopeo_cmd = run_in_host_mountns ( "skopeo" ) ;
498
- let proxy_cfg = ostree_container:: store:: ImageProxyConfig {
499
- skopeo_cmd : Some ( skopeo_cmd) ,
500
- ..Default :: default ( )
501
- } ;
502
-
503
- let mut temporary_dir = None ;
504
- let src_imageref = if skopeo_supports_containers_storage ( ) ? {
505
- // We always use exactly the digest of the running image to ensure predictability.
506
- let spec =
507
- crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
508
- ostree_container:: ImageReference {
509
- transport : ostree_container:: Transport :: ContainerStorage ,
510
- name : spec,
511
- }
512
- } else {
513
- let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
514
- let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
515
- let r = copy_to_oci ( & state. source . imageref , path) ?;
516
- temporary_dir = Some ( td) ;
517
- r
518
- } ;
519
- let src_imageref = ostree_container:: OstreeImageReference {
520
- // There are no signatures to verify since we're fetching the already
521
- // pulled container.
522
- sigverify : ostree_container:: SignatureSource :: ContainerPolicyAllowInsecure ,
523
- imgref : src_imageref,
524
- } ;
513
+ let proxy_cfg = import_config_from_host ( ) ;
525
514
526
515
let kargs = root_setup
527
516
. kargs
@@ -532,6 +521,56 @@ async fn initialize_ostree_root_from_self(
532
521
options. kargs = Some ( kargs. as_slice ( ) ) ;
533
522
options. target_imgref = Some ( & target_imgref) ;
534
523
options. proxy_cfg = Some ( proxy_cfg) ;
524
+
525
+ // Default image reference pulls from the running container image.
526
+ let mut src_imageref = ostree_container:: OstreeImageReference {
527
+ // There are no signatures to verify since we're fetching the already
528
+ // pulled container.
529
+ sigverify : SignatureSource :: ContainerPolicyAllowInsecure ,
530
+ imgref : state. source . imageref . clone ( ) ,
531
+ } ;
532
+
533
+ let mut temporary_dir = None ;
534
+ if state. source . from_ostree_repo {
535
+ let root = Dir :: open_ambient_dir ( "/" , cap_std:: ambient_authority ( ) ) ?;
536
+ let host_repo = {
537
+ let repodir = root
538
+ . open_dir ( "sysroot/repo" )
539
+ . context ( "Opening sysroot/repo" ) ?;
540
+ ostree:: Repo :: open_at_dir ( repodir. as_fd ( ) , "." ) ?
541
+ } ;
542
+ ostree_container:: store:: copy_as (
543
+ & host_repo,
544
+ & state. source . imageref ,
545
+ & dest_repo,
546
+ & target_imgref. imgref ,
547
+ )
548
+ . await
549
+ . context ( "Copying image from host repo" ) ?;
550
+ // We already copied the image, so src == target
551
+ src_imageref = target_imgref. clone ( ) ;
552
+ options. target_imgref = None ;
553
+ } else {
554
+ if skopeo_supports_containers_storage ( ) ? {
555
+ // We always use exactly the digest of the running image to ensure predictability.
556
+ let spec =
557
+ crate :: utils:: digested_pullspec ( & state. source . imageref . name , & state. source . digest ) ;
558
+ ostree_container:: ImageReference {
559
+ transport : ostree_container:: Transport :: ContainerStorage ,
560
+ name : spec,
561
+ }
562
+ } else {
563
+ let td = tempfile:: tempdir_in ( "/var/tmp" ) ?;
564
+ let path: & Utf8Path = td. path ( ) . try_into ( ) . unwrap ( ) ;
565
+ let r = copy_to_oci ( & state. source . imageref , path) ?;
566
+ temporary_dir = Some ( td) ;
567
+ r
568
+ } ;
569
+ // In this case the deploy code is pulling the container, so set it up to
570
+ // generate a target image reference.
571
+ options. target_imgref = Some ( & target_imgref) ;
572
+ }
573
+
535
574
println ! ( "Creating initial deployment" ) ;
536
575
let state =
537
576
ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
@@ -884,11 +923,16 @@ fn installation_complete() {
884
923
println ! ( "Installation complete!" ) ;
885
924
}
886
925
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 ?;
926
+ pub ( crate ) async fn install_takeover (
927
+ opts : InstallBlockDeviceOpts ,
928
+ state : Arc < State > ,
929
+ ) -> Result < ( ) > {
930
+ // The takeover code should have unset this
931
+ assert ! ( !opts. takeover) ;
932
+ block_install_impl ( opts, state) . await
933
+ }
891
934
935
+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
892
936
// This is all blocking stuff
893
937
let mut rootfs = {
894
938
let state = state. clone ( ) ;
@@ -914,6 +958,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
914
958
Ok ( ( ) )
915
959
}
916
960
961
+ /// Implementation of the `bootc install` CLI command.
962
+ pub ( crate ) async fn install ( opts : InstallOpts ) -> Result < ( ) > {
963
+ let block_opts = opts. block_opts ;
964
+ let state = prepare_install ( opts. config_opts , opts. target_opts ) . await ?;
965
+ if block_opts. takeover {
966
+ tracing:: debug!( "Performing takeover installation from host" ) ;
967
+ return crate :: systemtakeover:: run_from_host ( block_opts, state) . await ;
968
+ }
969
+
970
+ block_install_impl ( block_opts, state) . await
971
+ }
972
+
917
973
#[ context( "Verifying empty rootfs" ) ]
918
974
fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
919
975
for e in rootfs_fd. entries ( ) ? {
0 commit comments