Skip to content

switch: Add --target-imgref to Support a separate update image reference - #2603

Open
HarshwardhanPatil07 wants to merge 8 commits into
bootc-dev:mainfrom
HarshwardhanPatil07:fix/switch-target-imgref
Open

HarshwardhanPatil07 wants to merge 8 commits into
bootc-dev:mainfrom
HarshwardhanPatil07:fix/switch-target-imgref

Conversation

@HarshwardhanPatil07

Copy link
Copy Markdown
Member

Adds --target-imgref to bootc switch for OSTree and composefs, allowing an image to be downloaded from a temporary source while keeping a different registry for future updates.

Manually verified composefs UKI switching, repeated switches, and reboot with the previous deployment available for rollback. Verified OSTree download-only staging and both references in its .origin file.

Fixes #2464

Copilot AI balanced review requested due to automatic review settings October 30, 2026 09:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@github-actions github-actions Bot added area/install Issues related to `bootc install` area/ostree Issues related to ostree area/documentation Updates to the documentation labels Oct 30, 2026
@bootc-bot
bootc-bot Bot requested a review from henrywang October 30, 2026 09:36
@HarshwardhanPatil07
HarshwardhanPatil07 force-pushed the fix/switch-target-imgref branch 2 times, most recently from 75ea0d9 to 8055a2f Compare October 30, 2026 09:41
@HarshwardhanPatil07 HarshwardhanPatil07 changed the title switch: Add --target-imgref for offline image delivery switch: Add --target-imgref to Support a separate update image reference Oct 30, 2026
@cgwalters
cgwalters requested a balanced review from Copilot October 30, 2026 18:41
Comment thread crates/lib/src/cli.rs Resolved
Comment thread crates/lib/src/cli.rs Resolved

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment thread crates/lib/src/cli.rs Resolved
Comment thread crates/lib/src/cli.rs Resolved
Comment thread crates/lib/src/cli.rs Resolved
Comment thread crates/lib/src/deploy.rs Resolved
@HarshwardhanPatil07
HarshwardhanPatil07 force-pushed the fix/switch-target-imgref branch 2 times, most recently from a63c7f4 to b00d6b9 Compare October 31, 2026 13:42

@Johan-Liebert1 Johan-Liebert1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not a full review yet

.booted
.as_ref()
.context("No booted deployment")?;
if booted.require_composefs()?.verity != self.deployment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

when will this not be true? afaics, we're only ever setting OriginChange::deployment to the booted depl verity

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

it is always true when we create the pending change. The check is for when we read it after a reboot: a download-only origin change can remain on disk for deployment A, while the user boots rollback deployment B. In that case, we should ignore A’s pending change rather than show it as staged for B.

Should i add a comment there to make i more clear?

opts,
UkiAddonCliOpts::Add { .. } | UkiAddonCliOpts::Remove { .. }
) {
anyhow::ensure!(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why not? We allow it when we have a staged deployment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This guard applies only while an origin-only change is pending, addon changes with a real staged deployment still work.

Comment thread crates/lib/src/spec.rs Resolved
@Johan-Liebert1

Copy link
Copy Markdown
Member

Also the first two commits need proper messages and not just wip

Johan-Liebert1 and others added 2 commits November 3, 2026 14:45
Allow switch to accept an update origin separate from the image fetched
now. Pass the target through OSTree staging and composefs switch so
later updates can follow the recorded reference.

Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
Co-authored-by: HarshwardhanPatil07 <harshpat@redhat.com>
Keep the pulled image name alongside a staged deployment when switch
chooses a different update origin. This prepares the staged state to
distinguish the delivery source from the recorded origin.

Signed-off-by: Pragyan Poudyal <pragyanpoudyal41999@gmail.com>
Co-authored-by: HarshwardhanPatil07 <harshpat@redhat.com>
Offline delivery should accept the same registry names users pass to
install. Normalize target references before fetching, reject incompatible
options, and avoid advertising enforced verification on an unsupported
composefs path.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
A cached import must retain the reference used by the deployment origin
so cleanup does not discard its image metadata. Handle this in the
importer, respecting set_no_imgref, so direct and unified pulls share
the same behavior. Reuse the existing pull preparation helper.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
The update origin cannot identify which offline delivery was staged.
Record the pull source in each deployment origin and compare both
references before fetching, preserving download-only locks on repeats.
Route OSTree imports through the source while retaining the target.

Cover offline repeats, source replacement, activation, and provenance
after reboot on both backends.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Recording an origin is only useful if later updates actually use it.
Extend the reboot test to check unchanged content and a newer image at
the recorded registry after completing an offline delivery.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
Explain how to obtain an image from a temporary source while retaining
the normal update origin. Document repeat behavior, activation, and
user-visible restrictions with local-storage and registry examples.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
A redirected deployment records its update origin while containers-storage
keeps the delivery name. Detect the stored host image by its OCI config
ID and retain that ID during cleanup, so later updates keep using unified
storage without requiring another explicit opt-in.

Use the existing deployment metadata for both backends without adding
persistent state or changing image aliases.

Assisted-by: AI
Signed-off-by: HarshwardhanPatil07 <harshpat@redhat.com>
location = "localhost:5555"
insecure = true
' | save /etc/containers/registries.conf.d/target-imgref-test.conf
podman run -d --name $registry -p 127.0.0.1:5555:5000 docker.io/library/registry:2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this necessary for testing? We'd want to limit internet access in our tests to as little as possible to prevent flakes. We could just have another containers-storage:<image> as the target imgref

Comment thread crates/lib/src/spec.rs
}

/// Parse a transport-prefixed reference, defaulting bare image names to the registry.
pub(crate) fn parse_image_reference(value: &str) -> Result<containers_image_proxy::ImageReference> {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why do we need this function? Is there some case where containers_image_proxy::ImageReference::try_from fails?

continue;
}

if let Some(id) = deployment.container_image_id(storage)? {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should do this below where we read the origin. We can just check if the origin contains our new key, if it does use that as the image name else use the default one

);
let mut config = tini::Ini::new()
.section("origin")
// The composefs pull path does not yet enforce the spec signature mode.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's not remove the TODO from here

Comment on lines 258 to +259
target_imgref: &ImageReference,
source_imgref: Option<&ImageReference>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

probably worth switching the variable names here

Comment thread crates/lib/src/cli.rs
current_origin: Option<&ImageReference>,
previous_source: Option<&str>,
) -> Result<bool> {
let Some(current_origin) = current_origin else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't the current_origin always exist?

Comment thread crates/lib/src/cli.rs
Comment on lines +1731 to +1734
source: &ImageReference,
target: Option<&ImageReference>,
current_origin: Option<&ImageReference>,
previous_source: Option<&str>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These variables are poorly named, not entirely obvious what previous_source is. Renaming or at least a doc comment on the function would help. Also, why we can accept ImageReference for previous_source right to keep it all consistent?

Comment thread crates/lib/src/cli.rs
mod tests {
use super::*;

#[test]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These should all be tmt integration tests imo

Comment thread crates/lib/src/deploy.rs
/// Detect a deployment's stored image even when its pull source and origin differ.
pub(crate) async fn deployment_uses_unified_storage(
store: &Storage,
deployment: Option<&crate::spec::BootEntry>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Having an Option here doesn't make sense

Comment thread crates/lib/src/deploy.rs
return Ok(false);
};
let Some(id) = deployment.container_image_id(store)? else {
return Ok(false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't this be an error if we fail to find an image associated with a deployment or am I missing something?

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment thread crates/lib/src/cli.rs
Comment on lines +1884 to +1888
|| crate::deploy::deployment_uses_unified_storage(
storage,
host.status.staged.as_ref().or(host.status.booted.as_ref()),
)
.await?
Comment thread crates/lib/src/spec.rs
// is named after a transport. Use oci:./5000/os for an OCI relative path.
let registry_port = value.split_once('/').is_some_and(|(authority, _)| {
authority
.rsplit_once(':')

This branch has not been deployed

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

Labels

area/documentation Updates to the documentation area/install Issues related to `bootc install` area/ostree Issues related to ostree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add --target-imgref option to bootc switch

4 participants