mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 06:45:13 +01:00
lib: Add --from-downloaded flag for bootc upgrade
Add a new --from-downloaded flag to bootc upgrade that allows users to unlock a staged deployment created with --download-only without fetching updates from the container image source. This provides a way to apply already-downloaded updates without triggering a fetch operation, which is useful for scheduled maintenance workflows where the update was downloaded earlier and should now be applied at a scheduled time. Usage: # Download update without applying bootc upgrade --download-only # Later: Apply the staged update (without fetching from image source) bootc upgrade --from-downloaded # Or: Apply staged update and reboot immediately bootc upgrade --from-downloaded --apply The flag conflicts with --check and --download-only as those operations have different purposes. It can be combined with --apply to immediately reboot after unlocking the staged deployment. This commit also updates the documentation (upgrades.md) to describe all three ways to apply a download-only update, and updates the download-only test case (test-25) to use --from-downloaded instead of plain 'bootc upgrade' when clearing the download-only flag. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Wei Shi <wshi@redhat.com>
This commit is contained in:
@@ -276,6 +276,9 @@ pub(crate) async fn upgrade_composefs(
|
||||
if opts.download_only {
|
||||
anyhow::bail!("--download-only is not yet supported for composefs backend");
|
||||
}
|
||||
if opts.from_downloaded {
|
||||
anyhow::bail!("--from-downloaded is not yet supported for composefs backend");
|
||||
}
|
||||
|
||||
let host = get_composefs_status(storage, composefs)
|
||||
.await
|
||||
|
||||
@@ -108,6 +108,14 @@ pub(crate) struct UpgradeOpts {
|
||||
#[clap(long, conflicts_with_all = ["check", "apply"])]
|
||||
pub(crate) download_only: bool,
|
||||
|
||||
/// Apply a staged deployment that was previously downloaded with --download-only.
|
||||
///
|
||||
/// This unlocks the staged deployment without fetching updates from the container image source.
|
||||
/// The deployment will be applied on the next shutdown or reboot. Use with --apply to
|
||||
/// reboot immediately.
|
||||
#[clap(long, conflicts_with_all = ["check", "download_only"])]
|
||||
pub(crate) from_downloaded: bool,
|
||||
|
||||
#[clap(flatten)]
|
||||
pub(crate) progress: ProgressOptions,
|
||||
}
|
||||
@@ -933,6 +941,28 @@ async fn upgrade(
|
||||
let staged = host.status.staged.as_ref();
|
||||
let staged_image = staged.as_ref().and_then(|s| s.image.as_ref());
|
||||
let mut changed = false;
|
||||
|
||||
// Handle --from-downloaded: unlock existing staged deployment without fetching from image source
|
||||
if opts.from_downloaded {
|
||||
let ostree = storage.get_ostree()?;
|
||||
let staged_deployment = ostree
|
||||
.staged_deployment()
|
||||
.ok_or_else(|| anyhow::anyhow!("No staged deployment found"))?;
|
||||
|
||||
if staged_deployment.is_finalization_locked() {
|
||||
ostree.change_finalization(&staged_deployment)?;
|
||||
println!("Staged deployment will now be applied on reboot");
|
||||
} else {
|
||||
println!("Staged deployment is already set to apply on reboot");
|
||||
}
|
||||
|
||||
handle_staged_soft_reboot(booted_ostree, opts.soft_reboot, &host)?;
|
||||
if opts.apply {
|
||||
crate::reboot::reboot()?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if opts.check {
|
||||
let imgref = imgref.clone().into();
|
||||
let mut imp = crate::deploy::new_importer(repo, &imgref).await?;
|
||||
|
||||
@@ -65,6 +65,10 @@ Soft reboot allows faster system restart by avoiding full hardware reboot when p
|
||||
|
||||
Download and stage the update without applying it
|
||||
|
||||
**--from-downloaded**
|
||||
|
||||
Apply a staged deployment that was previously downloaded with --download-only
|
||||
|
||||
<!-- END GENERATED OPTIONS -->
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
@@ -6,7 +6,7 @@ updates from a registry and booting into them, while supporting rollback.
|
||||
|
||||
## The `bootc upgrade` verb
|
||||
|
||||
This will query the registry and queue an updated container image for the next boot.
|
||||
This will query the container image source and queue an updated container image for the next boot.
|
||||
|
||||
This is backed today by ostree, implementing an A/B style upgrade system.
|
||||
Changes to the base image are staged, and the running system is not
|
||||
@@ -23,7 +23,7 @@ them on the next reboot:
|
||||
bootc upgrade --download-only
|
||||
```
|
||||
|
||||
This will pull the new container image from the registry and create a staged deployment
|
||||
This will pull the new container image from the container image source and create a staged deployment
|
||||
in download-only mode. The deployment will not be applied on shutdown or reboot until
|
||||
you explicitly apply it.
|
||||
|
||||
@@ -40,24 +40,36 @@ In the output, you'll see `Download-only: yes` for deployments in download-only
|
||||
|
||||
#### Applying download-only updates
|
||||
|
||||
There are two ways to apply a staged update that is in download-only mode:
|
||||
There are three ways to apply a staged update that is in download-only mode:
|
||||
|
||||
**Option 1: Apply immediately with reboot**
|
||||
**Option 1: Apply the staged update without checking for newer updates**
|
||||
|
||||
```shell
|
||||
bootc upgrade --apply
|
||||
bootc upgrade --from-downloaded
|
||||
```
|
||||
|
||||
This will clear the download-only flag and immediately reboot into the staged deployment.
|
||||
This unlocks the staged deployment for automatic application on the next shutdown or reboot,
|
||||
without fetching updates from the container image source. This is useful when you want to apply the
|
||||
already-downloaded update at a scheduled time.
|
||||
|
||||
**Option 2: Clear download-only for automatic application**
|
||||
**Option 2: Apply the staged update and reboot immediately**
|
||||
|
||||
```shell
|
||||
bootc upgrade --from-downloaded --apply
|
||||
```
|
||||
|
||||
This unlocks the staged deployment and immediately reboots into it, without checking for
|
||||
newer updates.
|
||||
|
||||
**Option 3: Check for newer updates and apply**
|
||||
|
||||
```shell
|
||||
bootc upgrade
|
||||
```
|
||||
|
||||
Running `bootc upgrade` without flags on a staged deployment in download-only mode will
|
||||
clear the flag. The deployment will then be applied automatically on the next shutdown or reboot.
|
||||
Running `bootc upgrade` without flags will pull from the container image source to check for updates.
|
||||
If the staged deployment matches the latest available update, it will be unlocked. If a newer update is
|
||||
available, the staged deployment will be replaced with the newer version.
|
||||
|
||||
#### Checking for updates without side effects
|
||||
|
||||
@@ -84,15 +96,23 @@ bootc status --verbose
|
||||
# 3. Test or wait for maintenance window...
|
||||
|
||||
# 4. Apply the update (choose one):
|
||||
# Option A: Clear download-only flag and let it apply on next shutdown
|
||||
bootc upgrade
|
||||
# Option A: Apply staged update without fetching from image source
|
||||
bootc upgrade --from-downloaded
|
||||
|
||||
# Option B: Apply immediately with reboot
|
||||
bootc upgrade --apply
|
||||
# Option B: Apply staged update and reboot immediately (without fetching from image source)
|
||||
bootc upgrade --from-downloaded --apply
|
||||
|
||||
# Option C: Check for newer updates first, then apply
|
||||
bootc upgrade
|
||||
```
|
||||
|
||||
**Important notes**:
|
||||
|
||||
- **Image source check difference**: `bootc upgrade --from-downloaded` does NOT fetch from the
|
||||
container image source to check for newer updates, while `bootc upgrade` always does.
|
||||
Use `--from-downloaded` when you want to apply the specific version you already downloaded,
|
||||
regardless of whether newer updates are available.
|
||||
|
||||
- If you reboot before applying a download-only update, the system will boot into the
|
||||
current deployment and the staged deployment will be discarded. However, the downloaded image
|
||||
data remains cached, so re-running `bootc upgrade --download-only` will be fast and won't
|
||||
|
||||
@@ -95,12 +95,12 @@ execute:
|
||||
test:
|
||||
- /tmt/tests/tests/test-25-soft-reboot
|
||||
|
||||
/plan-25-download-only-upgrade:
|
||||
/plan-26-download-only-upgrade:
|
||||
summary: Execute download-only upgrade tests
|
||||
discover:
|
||||
how: fmf
|
||||
test:
|
||||
- /tmt/tests/tests/test-25-download-only-upgrade
|
||||
- /tmt/tests/tests/test-26-download-only-upgrade
|
||||
|
||||
/plan-27-custom-selinux-policy:
|
||||
summary: Execute custom selinux policy test
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# number: 25
|
||||
# number: 26
|
||||
# tmt:
|
||||
# summary: Execute download-only upgrade tests
|
||||
# duration: 40m
|
||||
@@ -13,7 +13,7 @@
|
||||
# reboot (should still boot into v1, staged deployment discarded)
|
||||
# verify staged deployment is null (discarded on reboot)
|
||||
# bootc upgrade --download-only (re-stage v2 in download-only mode)
|
||||
# bootc upgrade (clear download-only mode)
|
||||
# bootc upgrade --from-downloaded (clear download-only mode without fetching from image source)
|
||||
# reboot (should boot into v2)
|
||||
#
|
||||
use std assert
|
||||
@@ -113,9 +113,9 @@ def third_boot [] {
|
||||
assert ($status_json.status.staged != null) "Staged deployment should exist"
|
||||
assert ($status_json.status.staged.downloadOnly) "Staged deployment should be in download-only mode"
|
||||
|
||||
# Now clear download-only mode by running upgrade without flags
|
||||
print "Clearing download-only mode with bootc upgrade"
|
||||
bootc upgrade
|
||||
# Now clear download-only mode by running upgrade --from-downloaded (without fetching from image source)
|
||||
print "Clearing download-only mode with bootc upgrade --from-downloaded"
|
||||
bootc upgrade --from-downloaded
|
||||
|
||||
# Verify via JSON that deployment is not in download-only mode
|
||||
let status_after_json = bootc status --json | from json
|
||||
@@ -41,10 +41,10 @@
|
||||
duration: 30m
|
||||
test: nu booted/test-soft-reboot.nu
|
||||
|
||||
/test-25-download-only-upgrade:
|
||||
/test-26-download-only-upgrade:
|
||||
summary: Execute download-only upgrade tests
|
||||
duration: 40m
|
||||
test: nu booted/test-25-download-only-upgrade.nu
|
||||
test: nu booted/test-download-only-upgrade.nu
|
||||
|
||||
/test-27-custom-selinux-policy:
|
||||
summary: Execute custom selinux policy test
|
||||
|
||||
Reference in New Issue
Block a user