-
Notifications
You must be signed in to change notification settings - Fork 156
lib: Add experimental unified storage support for install #1601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
cgwalters
left a comment
There was a problem hiding this 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!
crates/lib/src/cli.rs
Outdated
| /// 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, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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.
crates/lib/src/podman.rs
Outdated
| use bootc_utils::CommandRunExt; | ||
|
|
||
| // Use podman pull with additionalimagestore pointing to bootc storage | ||
| let bootc_storage_path = "/usr/lib/bootc/storage"; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
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? |
There was a problem hiding this comment.
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.
|
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:
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. |
1baf1e8 to
9c3ef81
Compare
e891e6c to
be75055
Compare
291fbd7 to
fe10204
Compare
06be8fb to
b801a17
Compare
b801a17 to
68b1ba6
Compare
ee300e3 to
50c4f70
Compare
|
/gemini review |
There was a problem hiding this 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 aResult.
Addressing these points will improve the robustness and maintainability of this new feature.
|
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? |
3803e4c to
bb9883e
Compare
bb9883e to
04620ac
Compare
|
/gemini review |
There was a problem hiding this 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 in bootc, a significant and well-implemented feature. The changes are comprehensive, adding the --experimental-unified-storage flag to install and switch commands, auto-detection for upgrade, and a new bootc image set-unified command for onboarding existing systems. The implementation correctly handles different sysroot paths and edge cases like localhost images. The inclusion of integration and TMT tests demonstrates a thorough approach to quality assurance. My review includes a few minor suggestions to improve code style and readability.
04620ac to
7651032
Compare
|
/gemini review |
There was a problem hiding this 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 unified storage support for bootc install and related commands. The changes are extensive and well-thought-out, adding a new --experimental-unified-storage flag and the bootc image set-unified command. The implementation correctly handles different scenarios, such as install versus upgrade, and the special case of images originating from containers-storage. The addition of comprehensive integration and TMT tests is commendable. I've identified one high-severity logical issue in the implementation of bootc image set-unified where it could operate on a staged image instead of the booted one. I've also noted a correct and important bug fix in the image pruning logic. Overall, this is a solid contribution that adds a valuable feature.
cgwalters
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! A first pass review here, this is looking quite plausible!
crates/lib/src/cli.rs
Outdated
| /// When enabled, this uses bootc's container storage (/usr/lib/bootc/storage) to pull | ||
| /// the image first, then imports it from there. This is the same approach used for | ||
| /// logically bound images. | ||
| #[clap(long = "experimental-unified-storage")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be hide = true
crates/lib/src/deploy.rs
Outdated
| pub(crate) async fn should_use_unified_storage( | ||
| store: &Storage, | ||
| imgref: &ImageReference, | ||
| explicit_flag: Option<bool>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems strange to me; nothing AFAICS passes Some(false). And if Some(true) is passed the caller will just get back true. So why even call this?
| async fn image_exists_in_host_storage(image: &str) -> Result<bool> { | ||
| use tokio::process::Command as AsyncCommand; | ||
| let mut cmd = AsyncCommand::new("podman"); | ||
| cmd.args(["image", "exists", image]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've never been a fan of using exit codes to communicate things like this. Not a blocker but we should definitely try to cut over to using bollard or so.
crates/lib/src/image.rs
Outdated
| // local container storage. The image only exists in ostree now, so we need | ||
| // to export from ostree to bootc storage. | ||
| // Case 2: Otherwise, pull from the specified transport (usually a remote registry). | ||
| let is_containers_storage = imgref.transport == "containers-storage"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a Transport enum for this
crates/lib/src/utils.rs
Outdated
|
|
||
| /// Converts an ImageReference to a container reference string suitable for use with container storage APIs. | ||
| /// For registry transport, returns just the image name. For other transports, prepends the transport. | ||
| pub(crate) fn imageref_to_container_ref(imgref: &crate::spec::ImageReference) -> String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems cleaner to have this as a method impl ImageReference { fn to_short_container_ref() ?
crates/lib/src/image.rs
Outdated
| // Check if the image already exists in the default containers-storage. | ||
| // This can happen if someone did a local build (e.g., podman build) and | ||
| // we don't want to overwrite it with an export from ostree. | ||
| ensure_floating_c_storage_initialized(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can put this global init somewhere farther up?
crates/lib/src/image.rs
Outdated
| // We need to export from ostree to default containers-storage (/var/lib/containers) | ||
| tracing::info!("Image not found in containers-storage; exporting from ostree"); | ||
| let booted = host.status.booted.as_ref().unwrap(); | ||
| let booted_image = booted.image.as_ref().unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I think we can avoid these unwraps by using the first arg from crate::status::get_status_require_booted(ostree)?; above
| }; | ||
|
|
||
| let mut opts = ostree_ext::container::store::ExportToOCIOpts::default(); | ||
| opts.progress_to_stdout = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a // TODO: bridge to progress API here
| // Note if we ever add any other options here, | ||
| #[arg(long)] | ||
| pub(crate) composefs_backend: bool, | ||
| #[arg(long = "experimental-unified-storage")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto re hide = true
| let sysroot = crate::cli::get_storage().await?; | ||
| let ostree = sysroot.get_ostree()?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this stuff should be passed down from the caller, that's how most of the other logic works
7651032 to
ddbba51
Compare
|
/gemini review |
There was a problem hiding this 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 in bootc install, which allows sharing container images with podman's storage to reduce disk usage and enable offline installations. The changes include a new --experimental-unified-storage flag, modifications to upgrade and switch to auto-detect and use unified storage, and special handling for localhost images. New integration and TMT tests are also added to cover these new code paths.
My review focuses on correctness and maintainability. I've identified a couple of areas for improvement:
- An inconsistency in the image pulling strategy for unified storage, which could lead to unnecessary network operations.
- A small opportunity to simplify code by removing a redundant check, improving readability and reflecting the guarantees provided by other functions.
Overall, the changes are well-structured and the addition of tests is great. Addressing these points will improve the robustness and maintainability of the new feature.
| let booted_entry = host | ||
| .status | ||
| .booted | ||
| .as_ref() | ||
| .ok_or_else(|| anyhow::anyhow!("No booted deployment found"))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The get_status_require_booted function guarantees that host.status.booted is Some. Therefore, using ok_or_else here is unnecessary and can be simplified. Using expect() would be more idiomatic and clearly state the assumption that this should never be None.
| let booted_entry = host | |
| .status | |
| .booted | |
| .as_ref() | |
| .ok_or_else(|| anyhow::anyhow!("No booted deployment found"))?; | |
| let booted_entry = host | |
| .status | |
| .booted | |
| .as_ref() | |
| .expect("No booted deployment found; this should be guaranteed by get_status_require_booted"); |
54ef798 to
ba8e4ef
Compare
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 better integration with podman. 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 container-storage transport - 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 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) Signed-off-by: Joseph Marrero Corchado <[email protected]>
ba8e4ef to
7f11db8
Compare
lib: Add experimental unified storage support for install
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:
to handle the different mount points during install vs upgrade/switch
storage first (these can't be pulled from a registry)
bootc 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: #20
Assisted-by: Claude Code (Sonnet 4.5 & Opus 4.5)