@@ -381,6 +381,118 @@ pub(crate) async fn prepare_for_pull(
381381 Ok ( PreparedPullResult :: Ready ( Box :: new ( prepared_image) ) )
382382}
383383
384+ /// Unified approach: Use bootc's CStorage to pull the image, then prepare from containers-storage.
385+ /// This reuses the same infrastructure as LBIs.
386+ pub ( crate ) async fn prepare_for_pull_unified (
387+ repo : & ostree:: Repo ,
388+ imgref : & ImageReference ,
389+ target_imgref : Option < & OstreeImageReference > ,
390+ store : & Storage ,
391+ ) -> Result < PreparedPullResult > {
392+ // Get or initialize the bootc container storage (same as used for LBIs)
393+ let imgstore = store. get_ensure_imgstore ( ) ?;
394+
395+ let image_ref_str = format ! ( "{imgref:#}" ) ;
396+
397+ // Log the original transport being used for the pull
398+ tracing:: info!(
399+ "Unified pull: pulling from transport '{}' to bootc storage" ,
400+ & imgref. transport
401+ ) ;
402+
403+ // Pull the image to bootc storage using the same method as LBIs
404+ imgstore
405+ . pull ( & image_ref_str, crate :: podstorage:: PullMode :: Always )
406+ . await ?;
407+
408+ // Now create a containers-storage reference to read from bootc storage
409+ tracing:: info!( "Unified pull: now importing from containers-storage transport" ) ;
410+ let containers_storage_imgref = ImageReference {
411+ transport : "containers-storage" . to_string ( ) ,
412+ image : imgref. image . clone ( ) ,
413+ signature : imgref. signature . clone ( ) ,
414+ } ;
415+ let ostree_imgref = OstreeImageReference :: from ( containers_storage_imgref) ;
416+
417+ // Use the standard preparation flow but reading from containers-storage
418+ let mut imp = new_importer ( repo, & ostree_imgref) . await ?;
419+ if let Some ( target) = target_imgref {
420+ imp. set_target ( target) ;
421+ }
422+ let prep = match imp. prepare ( ) . await ? {
423+ PrepareResult :: AlreadyPresent ( c) => {
424+ println ! ( "No changes in {imgref:#} => {}" , c. manifest_digest) ;
425+ return Ok ( PreparedPullResult :: AlreadyPresent ( Box :: new ( ( * c) . into ( ) ) ) ) ;
426+ }
427+ PrepareResult :: Ready ( p) => p,
428+ } ;
429+ check_bootc_label ( & prep. config ) ;
430+ if let Some ( warning) = prep. deprecated_warning ( ) {
431+ ostree_ext:: cli:: print_deprecated_warning ( warning) . await ;
432+ }
433+ ostree_ext:: cli:: print_layer_status ( & prep) ;
434+ let layers_to_fetch = prep. layers_to_fetch ( ) . collect :: < Result < Vec < _ > > > ( ) ?;
435+
436+ // Log that we're importing a new image from containers-storage
437+ const PULLING_NEW_IMAGE_ID : & str = "6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0" ;
438+ tracing:: info!(
439+ message_id = PULLING_NEW_IMAGE_ID ,
440+ bootc. image. reference = & imgref. image,
441+ bootc. image. transport = "containers-storage" ,
442+ bootc. original_transport = & imgref. transport,
443+ bootc. status = "importing_from_storage" ,
444+ "Importing image from bootc storage: {}" ,
445+ ostree_imgref
446+ ) ;
447+
448+ let prepared_image = PreparedImportMeta {
449+ imp,
450+ n_layers_to_fetch : layers_to_fetch. len ( ) ,
451+ layers_total : prep. all_layers ( ) . count ( ) ,
452+ bytes_to_fetch : layers_to_fetch. iter ( ) . map ( |( l, _) | l. layer . size ( ) ) . sum ( ) ,
453+ bytes_total : prep. all_layers ( ) . map ( |l| l. layer . size ( ) ) . sum ( ) ,
454+ digest : prep. manifest_digest . clone ( ) ,
455+ prep,
456+ } ;
457+
458+ Ok ( PreparedPullResult :: Ready ( Box :: new ( prepared_image) ) )
459+ }
460+
461+ /// Unified pull: Use podman to pull to containers-storage, then read from there
462+ pub ( crate ) async fn pull_unified (
463+ repo : & ostree:: Repo ,
464+ imgref : & ImageReference ,
465+ target_imgref : Option < & OstreeImageReference > ,
466+ quiet : bool ,
467+ prog : ProgressWriter ,
468+ store : & Storage ,
469+ ) -> Result < Box < ImageState > > {
470+ match prepare_for_pull_unified ( repo, imgref, target_imgref, store) . await ? {
471+ PreparedPullResult :: AlreadyPresent ( existing) => {
472+ // Log that the image was already present (Debug level since it's not actionable)
473+ const IMAGE_ALREADY_PRESENT_ID : & str = "5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9" ;
474+ tracing:: debug!(
475+ message_id = IMAGE_ALREADY_PRESENT_ID ,
476+ bootc. image. reference = & imgref. image,
477+ bootc. image. transport = & imgref. transport,
478+ bootc. status = "already_present" ,
479+ "Image already present: {}" ,
480+ imgref
481+ ) ;
482+ Ok ( existing)
483+ }
484+ PreparedPullResult :: Ready ( prepared_image_meta) => {
485+ // To avoid duplicate success logs, pass a containers-storage imgref to the importer
486+ let cs_imgref = ImageReference {
487+ transport : "containers-storage" . to_string ( ) ,
488+ image : imgref. image . clone ( ) ,
489+ signature : imgref. signature . clone ( ) ,
490+ } ;
491+ pull_from_prepared ( & cs_imgref, quiet, prog, * prepared_image_meta) . await
492+ }
493+ }
494+ }
495+
384496#[ context( "Pulling" ) ]
385497pub ( crate ) async fn pull_from_prepared (
386498 imgref : & ImageReference ,
@@ -430,18 +542,21 @@ pub(crate) async fn pull_from_prepared(
430542 let imgref_canonicalized = imgref. clone ( ) . canonicalize ( ) ?;
431543 tracing:: debug!( "Canonicalized image reference: {imgref_canonicalized:#}" ) ;
432544
433- // Log successful import completion
434- const IMPORT_COMPLETE_JOURNAL_ID : & str = "4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8" ;
435-
436- tracing:: info!(
437- message_id = IMPORT_COMPLETE_JOURNAL_ID ,
438- bootc. image. reference = & imgref. image,
439- bootc. image. transport = & imgref. transport,
440- bootc. manifest_digest = import. manifest_digest. as_ref( ) ,
441- bootc. ostree_commit = & import. merge_commit,
442- "Successfully imported image: {}" ,
443- imgref
444- ) ;
545+ // Log successful import completion (skip if using unified storage to avoid double logging)
546+ let is_unified_path = imgref. transport == "containers-storage" ;
547+ if !is_unified_path {
548+ const IMPORT_COMPLETE_JOURNAL_ID : & str = "4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8" ;
549+
550+ tracing:: info!(
551+ message_id = IMPORT_COMPLETE_JOURNAL_ID ,
552+ bootc. image. reference = & imgref. image,
553+ bootc. image. transport = & imgref. transport,
554+ bootc. manifest_digest = import. manifest_digest. as_ref( ) ,
555+ bootc. ostree_commit = & import. merge_commit,
556+ "Successfully imported image: {}" ,
557+ imgref
558+ ) ;
559+ }
445560
446561 if let Some ( msg) =
447562 ostree_container:: store:: image_filtered_content_warning ( & import. filtered_files )
@@ -490,6 +605,9 @@ pub(crate) async fn pull(
490605 }
491606}
492607
608+ /// Pull selecting unified vs standard path based on persistent storage config.
609+ // pull_auto was reverted per request; keep explicit callers branching.
610+
493611pub ( crate ) async fn wipe_ostree ( sysroot : Sysroot ) -> Result < ( ) > {
494612 tokio:: task:: spawn_blocking ( move || {
495613 sysroot
0 commit comments