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 ;
@@ -36,6 +36,9 @@ use crate::lsm::lsm_label;
3636use crate :: task:: Task ;
3737use crate :: utils:: run_in_host_mountns;
3838
39+ /// The path we use to access files on the host
40+ pub ( crate ) const HOST_RUNDIR : & str = "/run/host" ;
41+
3942/// The default "stateroot" or "osname"; see https://github.com/ostreedev/ostree/issues/2794
4043const STATEROOT_DEFAULT : & str = "default" ;
4144/// The toplevel boot directory
@@ -171,6 +174,8 @@ pub(crate) struct SourceInfo {
171174 pub ( crate ) commit : String ,
172175 /// Whether or not SELinux appears to be enabled in the source commit
173176 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 ,
174179}
175180
176181// Shared read-only global state
@@ -303,11 +308,13 @@ impl SourceInfo {
303308 let root = root. downcast_ref :: < ostree:: RepoFile > ( ) . unwrap ( ) ;
304309 let xattrs = root. xattrs ( cancellable) ?;
305310 let selinux = crate :: lsm:: xattrs_have_selinux ( & xattrs) ;
311+ let from_ostree_repo = false ;
306312 Ok ( Self {
307313 imageref,
308314 digest,
309315 commit,
310316 selinux,
317+ from_ostree_repo,
311318 } )
312319 }
313320}
@@ -382,6 +389,14 @@ pub(crate) mod config {
382389 }
383390}
384391
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+
385400#[ context( "Creating ostree deployment" ) ]
386401async fn initialize_ostree_root_from_self (
387402 state : & State ,
@@ -407,12 +422,12 @@ async fn initialize_ostree_root_from_self(
407422 name : imgref. to_string ( ) ,
408423 } ;
409424 ostree_container:: OstreeImageReference {
410- sigverify : target_sigverify,
425+ sigverify : target_sigverify. clone ( ) ,
411426 imgref,
412427 }
413428 } else {
414429 ostree_container:: OstreeImageReference {
415- sigverify : target_sigverify,
430+ sigverify : target_sigverify. clone ( ) ,
416431 imgref : state. source . imageref . clone ( ) ,
417432 }
418433 } ;
@@ -442,49 +457,72 @@ async fn initialize_ostree_root_from_self(
442457
443458 let sysroot = ostree:: Sysroot :: new ( Some ( & gio:: File :: for_path ( rootfs) ) ) ;
444459 sysroot. load ( cancellable) ?;
460+ let dest_repo = & sysroot. repo ( ) . unwrap ( ) ;
445461
446462 // 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 ( ) ;
475464
476465 let kargs = root_setup
477466 . kargs
478467 . iter ( )
479468 . map ( |v| v. as_str ( ) )
480469 . 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+ } ;
481478 #[ allow( clippy:: needless_update) ]
482- let options = ostree_container:: deploy:: DeployOpts {
479+ let mut options = ostree_container:: deploy:: DeployOpts {
483480 kargs : Some ( kargs. as_slice ( ) ) ,
484- target_imgref : Some ( & target_imgref) ,
485481 proxy_cfg : Some ( proxy_cfg) ,
486482 ..Default :: default ( )
487483 } ;
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+
488526 println ! ( "Creating initial deployment" ) ;
489527 let state =
490528 ostree_container:: deploy:: deploy ( & sysroot, stateroot, & src_imageref, Some ( options) ) . await ?;
@@ -811,11 +849,16 @@ fn installation_complete() {
811849 println ! ( "Installation complete!" ) ;
812850}
813851
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+ }
818860
861+ async fn block_install_impl ( block_opts : InstallBlockDeviceOpts , state : Arc < State > ) -> Result < ( ) > {
819862 // This is all blocking stuff
820863 let mut rootfs = {
821864 let state = state. clone ( ) ;
@@ -841,6 +884,18 @@ pub(crate) async fn install(opts: InstallOpts) -> Result<()> {
841884 Ok ( ( ) )
842885}
843886
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+
844899#[ context( "Verifying empty rootfs" ) ]
845900fn require_empty_rootdir ( rootfs_fd : & Dir ) -> Result < ( ) > {
846901 for e in rootfs_fd. entries ( ) ? {
0 commit comments