Skip to content

Conversation

@jmarrero
Copy link
Contributor

@jmarrero jmarrero commented Sep 9, 2025

Compiles and at least does not fail a bootc switch... and can see the image in the container storage we own.

[core@cosa-devsh ~]$ sudo podman --storage-opt=additionalimagestore=/usr/lib/bootc/storage images
REPOSITORY                       TAG         IMAGE ID      CREATED       SIZE
quay.io/jmarrero_rh/soft-reboot  1           97f84fcb062e  25 hours ago  1.83 GB

This was drafted with the help of Claude Code.

@bootc-bot bootc-bot bot requested a review from cgwalters September 9, 2025 17:28
Copy link
Collaborator

@cgwalters cgwalters left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this!

/// Use podman/skopeo to pull image to additionalimagestore, then read from container storage.
/// This provides a unified approach that leverages existing container tooling.
#[clap(long)]
pub(crate) unified: bool,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this should be a CLI flag that operates just once; it should be something like bootc image --set-unified or so and act persistently.

Also we should support setting this at install time so that it happens from the very start.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(hmm my bad I thought we discussed this but I failed to update the issue #20 or something maybe?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh man yeah, we talked about saving the config on the origin file IIRC, I forgot.

use bootc_utils::CommandRunExt;

// Use podman pull with additionalimagestore pointing to bootc storage
let bootc_storage_path = "/usr/lib/bootc/storage";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use podstorage.rs instead please

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To elaborate on this, an important aspect here is currently the GC of the bootc/storage instance is rooted in the set of LBIs. That will need to be extended to include the host image.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another big task related to this - we'll eventually really want to use the podman HTTP APIs so we can properly monitor progress. Right now we are very crudely relying on doing this synchronously to the existing tty and reusing the podman CLI tty output. But that can't really work if we ever need to render our own progress APIs.

https://lib.rs/crates/bollard might be a good choice for this?

match prepare_for_pull_unified(repo, imgref, target_imgref, store).await? {
PreparedPullResult::AlreadyPresent(existing) => {
// Log that the image was already present (Debug level since it's not actionable)
const IMAGE_ALREADY_PRESENT_ID: &str = "5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that if we go this route, we should also not log to the journal in the ostree pull path because otherwise we're double logging.

let fetched = if opts.unified {
crate::deploy::pull_unified(repo, imgref, None, opts.quiet, prog.clone(), sysroot).await?
} else {
crate::deploy::pull(repo, imgref, None, opts.quiet, prog.clone()).await?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relates to #1599 (comment)

Basically how about changing this code to take a Storage which would hold the persistent flag, and then crate::deploy::pull would itself query that flag and change its behavior.

That would also implicitly then fix the install path to behave the same.

@jlebon
Copy link
Contributor

jlebon commented Oct 7, 2025

Do we get reflinks when importing from the alternate storage into the ostree repo?

@cgwalters
Copy link
Collaborator

Do we get reflinks when importing from the alternate storage into the ostree repo?

#20 links to containers/container-libs#144

@jlebon
Copy link
Contributor

jlebon commented Oct 7, 2025

Do we get reflinks when importing from the alternate storage into the ostree repo?

#20 links to containers/container-libs#144

Hmm, that's about copying between two container storages, but I was asking about the ostree import. But #20 does say:

From there, we do a reflink/hardlink copy into the ostree store (i.e. This would duplicate metadata, but not data on disk. Reflinks should always work.

Which kinda answers the question.

Basically without reflinks into the ostree storage, IMO this makes it a lot less obvious that this new option is objectively better and it instead becomes a discussion of trade-offs.

@jmarrero jmarrero force-pushed the unified-storage-wip branch from 1baf1e8 to 9c3ef81 Compare October 9, 2025 18:15
@jmarrero jmarrero changed the title WIP: Add --unified to use our container-storage for host images WIP: Use our container-storage for host images if the refspec exists on it Oct 9, 2025
@jmarrero jmarrero changed the title WIP: Use our container-storage for host images if the refspec exists on it WIP: Use our container-storage for host images if the refspec exists Oct 9, 2025
@jmarrero jmarrero force-pushed the unified-storage-wip branch 2 times, most recently from e891e6c to be75055 Compare October 15, 2025 17:57
@github-actions github-actions bot added the area/install Issues related to `bootc install` label Oct 15, 2025
@jmarrero jmarrero force-pushed the unified-storage-wip branch from 291fbd7 to fe10204 Compare November 11, 2025 19:53
@jmarrero jmarrero force-pushed the unified-storage-wip branch 3 times, most recently from 06be8fb to b801a17 Compare November 21, 2025 20:50
@github-actions github-actions bot added the area/system-reinstall-bootc Issues related to system-reinstall-botoc label Nov 21, 2025
@jmarrero jmarrero force-pushed the unified-storage-wip branch from b801a17 to 68b1ba6 Compare November 21, 2025 20:56
@jmarrero jmarrero force-pushed the unified-storage-wip branch 2 times, most recently from 4f06129 to ee300e3 Compare December 2, 2025 19:18
Add an experimental --experimental-unified-storage flag to bootc install
that uses bootc's container storage (/usr/lib/bootc/storage) to pull
images first, then imports from there. This is the same approach used
for logically bound images (LBIs).

Background:
The unified storage approach allows bootc to share container images with
podman's storage, reducing disk space and enabling offline installs when
images are pre-pulled to the host's container storage.

Changes:
- Add --experimental-unified-storage CLI flag to install subcommands
- Add sysroot_path parameter to prepare_for_pull_unified() and pull_unified()
  to handle the different mount points during install vs upgrade/switch
- Handle localhost images specially by exporting from ostree to container
  storage first (these can't be pulled from a registry)
- Skip pull in prepare_for_pull_unified() if image already exists in
  bootc storage
- Add TMT test for install with unified storage flag
- Add TMT test for switching to unified storage on running system
- Add integration test for system-reinstall-bootc with unified storage

The sysroot_path fix is needed because during install the target disk
is mounted at a specific path (e.g., /var/mnt), not /sysroot. Skopeo
needs the actual filesystem path to find the bootc storage.

Relates: bootc-dev#20

Assisted-by: Claude Code (Sonnet 4.5)
@jmarrero jmarrero force-pushed the unified-storage-wip branch from ee300e3 to 50c4f70 Compare December 2, 2025 19:28
@jmarrero jmarrero changed the title WIP: Use our container-storage for host images if the refspec exists lib: Add experimental unified storage support for install Dec 2, 2025
@jmarrero
Copy link
Contributor Author

jmarrero commented Dec 2, 2025

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces experimental support for unified storage, allowing bootc to pull images into its own container storage before importing them. This is a significant feature that touches installation, upgrade, and switch paths. The changes include new CLI options, a new image set-unified command, and the core logic for the unified pull mechanism.

The implementation is comprehensive and includes new integration tests. My review has identified a few areas for improvement:

  • A bug in the image reference formatting for unified storage checks during installation.
  • Inconsistent error handling when checking for images in the unified store.
  • A potential panic due to an .unwrap() call on a Result.

Addressing these points will improve the robustness and maintainability of this new feature.

let booted = host.status.booted.as_ref().unwrap();
let booted_image = booted.image.as_ref().unwrap();
let source = ImageReference {
transport: Transport::try_from(booted_image.image.transport.as_str()).unwrap(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using .unwrap() here can cause a panic if try_from fails. It's safer to use the ? operator to propagate the error, which will be converted into an anyhow::Error.

Suggested change
transport: Transport::try_from(booted_image.image.transport.as_str()).unwrap(),
transport: Transport::try_from(booted_image.image.transport.as_str())?,

// Auto-detect: check if image exists in bootc storage (same as upgrade/switch)
let imgstore = storage.get_ensure_imgstore()?;
imgstore
.exists(&format!("{spec_imgref:#}"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There's a bug here. format!("{spec_imgref:#}") is used to create the image reference string. This uses the Display implementation of ImageReference, which includes signature information (e.g., ostree-unverified-registry:quay.io/...). However, the container storage APIs expect a reference like transport:name or just name for the registry transport. The correct way to format this is using crate::utils::imageref_to_container_ref(), as done in cli.rs.

Additionally, the logic to detect whether to use unified storage is duplicated across cli.rs (in upgrade and switch_ostree) and here in install.rs. This should be refactored into a single helper function to avoid bugs like this and improve maintainability.

Suggested change
.exists(&format!("{spec_imgref:#}"))
.exists(&crate::utils::imageref_to_container_ref(&spec_imgref))


// Check if image already exists in bootc storage - if so, skip the pull
// This is important for localhost images which can't be pulled from a registry
let image_exists = imgstore.exists(&image_ref_str).await.unwrap_or(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error from imgstore.exists() is silently ignored here by using unwrap_or(false). In other places where this check is performed (e.g., cli.rs and install.rs), a warning is logged. This inconsistency can hide potential issues. The error should be propagated or at least logged with a warning for consistency.

    let image_exists = match imgstore.exists(&image_ref_str).await {
        Ok(v) => v,
        Err(e) => {
            tracing::warn!("Failed to check for existing image in bootc storage: {e}");
            false
        }
    };

@cgwalters
Copy link
Collaborator

On the progress status side maybe we can use https://lib.rs/crates/bollard to talk to podman and I think it should help us get data out of the events?

);

// Check if this is a localhost image with registry transport - these images
// were built locally and don't exist in any remote registry. We need to
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we're special casing this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install Issues related to `bootc install` area/system-reinstall-bootc Issues related to system-reinstall-botoc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants