-
Notifications
You must be signed in to change notification settings - Fork 154
Description
(Note: filing this as a discussion starting point; it was Assisted-by: Sonnet 4.5 and definitely contains a bit of slop)
Summary
Add a --once flag to bootc switch that allows temporarily switching to a different image source while retaining the original registry reference for future updates. This enables devices to alternate between offline and online update modes without losing their registry configuration.
The feature includes built-in idempotency checking, making it safe for edge-triggered automation (such as USB insertion events) to repeatedly invoke the command without creating redundant staged deployments when already at the desired state.
Motivation
Some devices need to support alternating between offline and online updates - receiving updates via local media when disconnected from the registry, while resuming registry-based updates when connectivity is available. Currently, when using bootc switch --transport oci /var/mnt/usb/myos.oci to load an update from local media (USB, SCP, etc.), the system's image reference is permanently changed to the local source. When connectivity is restored, operators must manually run another bootc switch command to restore the original registry reference.
This creates operational burden and increases the risk of systems becoming desynchronized from their intended update channel.
Use Cases
Devices Alternating Between Offline and Online Updates: Deploy updates via USB stick when disconnected from the registry while maintaining the registry reference for when connectivity is restored. Automated scripts can edge-trigger on USB insertion without concern for redundant operations due to built-in idempotency.
Proposed Solution
Add a --once flag to bootc switch:
bootc switch --once --transport oci /var/mnt/usb/myos.ociBehavior
When --once is specified:
- The next staged deployment uses the provided image source (works with all transports: registry, oci, oci-archive, containers-storage, etc.)
- Both the source image reference (where the image was actually fetched from) and the target image reference (what should be tracked for future updates) are persisted in the origin metadata
- The bootc status continues to show the original image reference as the tracked target; in verbose mode, it also displays the source reference
- Subsequent
bootc upgradeoperations will attempt to pull from the tracked target reference, not the temporary source reference - The temporary source is used only for the immediate switch operation
- Idempotency: If the system is already at the desired state (same image digest),
bootc switch --oncewill detect this and skip the operation, returning success without staging a new deployment
Example Workflow
# Initial state: tracking registry image
$ bootc status
Staged: registry:quay.io/exampleos/edge-prod:v2.1
# Temporarily switch to local image from USB
$ bootc switch --once --transport oci /var/mnt/usb/edge-prod-v2.2.oci
# Check status (verbose mode shows both source and target)
$ bootc status --verbose
...
Staged:
Image: registry:quay.io/exampleos/edge-prod:v2.1
Source: oci:/var/mnt/usb/edge-prod-v2.2.oci
...
# After reboot and when connectivity returns
$ bootc upgrade
Pulling from registry:quay.io/exampleos/edge-prod:v2.1...Automated USB Update Workflow with Idempotency
A common use case is edge-triggered automation that runs when a USB key is plugged in:
# Initial state: running v2.1
$ bootc status --booted
Booted:
Image: registry:quay.io/exampleos/edge-prod:v2.1
Version: 2.1.0
# USB key with v2.2 is inserted, automation triggers
$ bootc switch --once --transport oci /mnt/usb/edge-prod-v2.2.oci
Staging image from USB...
Staged deployment created.
# System reboots into v2.2
# USB key is still plugged in, automation runs again on boot
$ bootc switch --once --transport oci /mnt/usb/edge-prod-v2.2.oci
Image digest matches current deployment, no action needed.
# No redundant staging occurs - system recognizes it's already at desired stateThis idempotency is critical for automation: scripts can safely run bootc switch --once repeatedly without creating unnecessary staged deployments.
The --once flag also works with registry transport for testing scenarios:
# Initial state: tracking production tag
$ bootc status
Staged: registry:quay.io/exampleos/edge-prod:stable
# Temporarily test canary version
$ bootc switch --once quay.io/exampleos/edge-prod:canary
Staged: registry:quay.io/exampleos/edge-prod:canary (temporary)
Target: registry:quay.io/exampleos/edge-prod:stable
# After testing, upgrade returns to stable channel
$ bootc upgrade
Pulling from registry:quay.io/exampleos/edge-prod:stable...Implementation Considerations
The implementation would need to:
- Store both the source image reference (where the image was fetched from) and the target image reference (what to track for updates) in the deployment's origin metadata
- Display the target reference by default in
bootc status, and additionally show the source reference in--verbosemode - Ensure
bootc upgradealways pulls from the target reference, not the source reference - Implement idempotency checking by comparing the image digest of the provided source against the currently booted (or staged) deployment. If the digest matches, skip the operation and return success.
- Consider interaction with
--retainflag (should they be mutually exclusive or complementary?)
This follows the same pattern as bootc install --source-imgref and --target-imgref, which already support this source/target distinction during installation.
Idempotency Detection
The idempotency check is particularly important for edge-triggered automation (e.g., USB insertion events). The implementation should:
- Fetch the image manifest/metadata from the provided source to obtain the digest
- Compare this digest against the booted deployment's digest
- If they match, report "No action needed" and exit successfully without staging
- This check should be relatively lightweight, avoiding full layer downloads when possible
Alternative Syntax Considered
An alternative approach could explicitly specify both the source and target:
bootc switch --transport oci /var/mnt/usb/myos.oci --target quay.io/exampleos/edge-prod:v2.1However, --once is simpler and more intuitive for the common case where the user wants to retain their current target.
Current Workarounds
Users currently have two workarounds:
- Use
bootc switch --transport oci /path/to/local.oci, then manually runbootc switch registry:quay.io/example/prod:tagwhen connectivity is restored - Use
bootc switch --transport containers-storage PODMAN_IMAGE_ID, with the same manual restoration requirement
Both workarounds:
- Require manual intervention
- Risk configuration drift if the second step is forgotten
- Don't clearly indicate to automation that the system is in a temporary state
Relationship to Existing Features
bootc install --source-imgref and --target-imgref
The --once flag builds on the same source/target image reference pattern already used in bootc install:
--source-imgref: Install the system from an explicitly given source--target-imgref: Specify the image to fetch for subsequent updates
The bootc switch --once option applies this same distinction to runtime updates: the source is where you fetch from now (possibly offline/local), while the target is what you track for future updates (typically a registry reference).
--retain Flag
The existing --retain flag keeps a reference to the currently booted image. The --once flag is conceptually similar but inverted: it retains a reference to the target registry while temporarily using a different source.
Disconnected Updates Documentation
The existing documentation at docs/src/registries-and-offline.md describes using bootc switch --transport oci for offline updates, but notes that subsequent bootc upgrade commands are idempotent. The --once flag would change this behavior to make bootc upgrade pull from the original registry when connectivity is restored.
Open Questions
- Should there be a way to "clear" the temporary source without rebooting, making the target reference active again immediately?
- How does this interact with pinning and explicit digest references?
- Should
--oncebe compatible with--retain, or should they be mutually exclusive? - When a deployment is booted that was created with
--once, shouldbootc statusindicate this in some special way (e.g., a warning or notice that the booted deployment was fetched from a temporary source)? - For idempotency checking: If there's already a staged deployment (different from the requested image), should
bootc switch --oncereplace it, or should it refuse to operate? What if the staged deployment was also created with--once?
Related Issues
- #20 - Discusses the separation between podman storage and bootc storage
- #1320 - Download without applying (finalization locking) - complementary feature for pre-staging updates
- #1375 - Trickle-fetch support for bandwidth-constrained scenarios
Relationship to Other Proposed Features
Finalization Locking (#1320): This feature is about pre-positioning updates - downloading them without applying. This addresses a different use case than --once, which is about using already pre-positioned images (whether via USB, SCP, or other means) while maintaining the original registry target for future updates.
Trickle-fetch (#1375): The proposed trickle-fetch feature would help with bandwidth-constrained scenarios by limiting download rates or sizes. The --once feature addresses a different scenario: when bandwidth is unavailable or connectivity is completely absent, use a pre-positioned local image while maintaining the registry reference for when connectivity returns.