66
77// This sub-module is the "basic" installer that handles creating basic block device
88// and filesystem setup.
9- mod baseline;
9+ pub ( crate ) mod baseline;
1010
1111use std:: io:: BufWriter ;
1212use std:: io:: Write ;
@@ -37,6 +37,9 @@ use crate::containerenv::ContainerExecutionInfo;
3737use crate :: task:: Task ;
3838use crate :: utils:: run_in_host_mountns;
3939
40+ /// The path we use to access files on the host
41+ pub ( crate ) const HOST_RUNDIR : & str = "/run/host" ;
42+
4043/// The default "stateroot" or "osname"; see https://github.com/ostreedev/ostree/issues/2794
4144const STATEROOT_DEFAULT : & str = "default" ;
4245/// The toplevel boot directory
@@ -196,6 +199,8 @@ pub(crate) struct SourceInfo {
196199 pub ( crate ) commit : String ,
197200 /// Whether or not SELinux appears to be enabled in the source commit
198201 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 ,
199204}
200205
201206// Shared read-only global state
@@ -345,11 +350,13 @@ impl SourceInfo {
345350 let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
346351 let xattrs = root. xattrs ( cancellable) ?;
347352 let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
353+ let from_ostree_repo = false ;
348354 Ok ( Self {
349355 imageref,
350356 digest,
351357 commit,
352358 selinux,
359+ from_ostree_repo,
353360 } )
354361 }
355362}
@@ -424,6 +431,14 @@ pub(crate) mod config {
424431 }
425432}
426433
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+
427442#[ context( "Creating ostree deployment" ) ]
428443async fn initialize_ostree_root_from_self (
429444 state : & State ,
@@ -492,36 +507,10 @@ async fn initialize_ostree_root_from_self(
492507
493508 let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
494509 sysroot. load ( cancellable) ?;
510+ let dest_repo = & sysroot. repo ( ) ;
495511
496512 // 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 ( ) ;
525514
526515 let kargs = root_setup
527516 . kargs
@@ -532,6 +521,56 @@ async fn initialize_ostree_root_from_self(
532521 options. kargs = Some ( kargs. as_slice ( ) ) ;
533522 options. target_imgref = Some ( & target_imgref) ;
534523 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+
535574 println ! ( "Creating initial deployment" ) ;
536575 let state =
537576 ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
@@ -884,11 +923,16 @@ fn installation_complete() {
884923 println ! ( "Installation complete!" ) ;
885924}
886925
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+ }
891934
935+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
892936 // This is all blocking stuff
893937 let mut rootfs = {
894938 let state = state. clone ( ) ;
@@ -914,6 +958,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
914958 Ok ( ( ) )
915959}
916960
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+
917973#[ context( "Verifying empty rootfs" ) ]
918974fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
919975 for e in rootfs_fd. entries ( ) ? {
0 commit comments