Skip to content

Commit 3a74eed

Browse files
committed
lib: Add --apply-staged flag for bootc upgrade
Add a new --apply-staged flag to bootc upgrade that allows users to unlock a staged deployment created with --download-only without checking for newer updates from the registry. This provides a way to apply already-downloaded updates without triggering a registry check, 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 (no registry check) bootc upgrade --apply-staged # Or: Apply staged update and reboot immediately bootc upgrade --apply-staged --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 --apply-staged instead of plain `bootc upgrade` when clearing the download-only flag. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Wei Shi <[email protected]>
1 parent ebe7f63 commit 3a74eed

File tree

3 files changed

+67
-15
lines changed

3 files changed

+67
-15
lines changed

crates/lib/src/cli.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ pub(crate) struct UpgradeOpts {
108108
#[clap(long, conflicts_with_all = ["check", "apply"])]
109109
pub(crate) download_only: bool,
110110

111+
/// Apply a staged deployment that was previously downloaded with --download-only.
112+
///
113+
/// This unlocks the staged deployment without checking for newer updates from the registry.
114+
/// The deployment will be applied on the next shutdown or reboot. Use with --apply to
115+
/// reboot immediately.
116+
#[clap(long, conflicts_with_all = ["check", "download_only"])]
117+
pub(crate) apply_staged: bool,
118+
111119
#[clap(flatten)]
112120
pub(crate) progress: ProgressOptions,
113121
}
@@ -933,6 +941,30 @@ async fn upgrade(
933941
let staged = host.status.staged.as_ref();
934942
let staged_image = staged.as_ref().and_then(|s| s.image.as_ref());
935943
let mut changed = false;
944+
945+
// Handle --apply-staged: unlock existing staged deployment without registry check
946+
if opts.apply_staged {
947+
let staged_deployment = storage
948+
.get_ostree()?
949+
.staged_deployment()
950+
.ok_or_else(|| anyhow::anyhow!("No staged deployment found"))?;
951+
952+
if staged_deployment.is_finalization_locked() {
953+
storage
954+
.get_ostree()?
955+
.change_finalization(&staged_deployment)?;
956+
println!("Staged deployment will now be applied on reboot");
957+
} else {
958+
println!("Staged deployment is already set to apply on reboot");
959+
}
960+
961+
handle_staged_soft_reboot(booted_ostree, opts.soft_reboot, &host)?;
962+
if opts.apply {
963+
crate::reboot::reboot()?;
964+
}
965+
return Ok(());
966+
}
967+
936968
if opts.check {
937969
let imgref = imgref.clone().into();
938970
let mut imp = crate::deploy::new_importer(repo, &imgref).await?;

docs/src/upgrades.md

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,36 @@ In the output, you'll see `Download-only: yes` for deployments in download-only
4040

4141
#### Applying download-only updates
4242

43-
There are two ways to apply a staged update that is in download-only mode:
43+
There are three ways to apply a staged update that is in download-only mode:
4444

45-
**Option 1: Apply immediately with reboot**
45+
**Option 1: Apply the staged update without checking for newer updates**
4646

4747
```shell
48-
bootc upgrade --apply
48+
bootc upgrade --apply-staged
4949
```
5050

51-
This will clear the download-only flag and immediately reboot into the staged deployment.
51+
This unlocks the staged deployment for automatic application on the next shutdown or reboot,
52+
without checking the registry for newer updates. This is useful when you want to apply the
53+
already-downloaded update at a scheduled time.
5254

53-
**Option 2: Clear download-only for automatic application**
55+
**Option 2: Apply the staged update and reboot immediately**
56+
57+
```shell
58+
bootc upgrade --apply-staged --apply
59+
```
60+
61+
This unlocks the staged deployment and immediately reboots into it, without checking for
62+
newer updates.
63+
64+
**Option 3: Check for newer updates and apply**
5465

5566
```shell
5667
bootc upgrade
5768
```
5869

59-
Running `bootc upgrade` without flags on a staged deployment in download-only mode will
60-
clear the flag. The deployment will then be applied automatically on the next shutdown or reboot.
70+
Running `bootc upgrade` without flags will check the registry for updates. If the staged
71+
deployment matches the latest available update, it will be unlocked. If a newer update is
72+
available, the staged deployment will be replaced with the newer version.
6173

6274
#### Checking for updates without side effects
6375

@@ -84,15 +96,23 @@ bootc status --verbose
8496
# 3. Test or wait for maintenance window...
8597

8698
# 4. Apply the update (choose one):
87-
# Option A: Clear download-only flag and let it apply on next shutdown
88-
bootc upgrade
99+
# Option A: Apply staged update without registry check
100+
bootc upgrade --apply-staged
101+
102+
# Option B: Apply staged update and reboot immediately (no registry check)
103+
bootc upgrade --apply-staged --apply
89104

90-
# Option B: Apply immediately with reboot
91-
bootc upgrade --apply
105+
# Option C: Check for newer updates first, then apply
106+
bootc upgrade
92107
```
93108

94109
**Important notes**:
95110

111+
- **Registry check difference**: `bootc upgrade --apply-staged` does NOT check the registry for
112+
newer updates, while `bootc upgrade` always checks. Use `--apply-staged` when you want to
113+
apply the specific version you already downloaded, regardless of whether newer updates are
114+
available.
115+
96116
- If you reboot before applying a download-only update, the system will boot into the
97117
current deployment and the staged deployment will be discarded. However, the downloaded image
98118
data remains cached, so re-running `bootc upgrade --download-only` will be fast and won't

tmt/tests/booted/test-25-download-only-upgrade.nu

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# reboot (should still boot into v1, staged deployment discarded)
1414
# verify staged deployment is null (discarded on reboot)
1515
# bootc upgrade --download-only (re-stage v2 in download-only mode)
16-
# bootc upgrade (clear download-only mode)
16+
# bootc upgrade --apply-staged (clear download-only mode without registry check)
1717
# reboot (should boot into v2)
1818
#
1919
use std assert
@@ -113,9 +113,9 @@ def third_boot [] {
113113
assert ($status_json.status.staged != null) "Staged deployment should exist"
114114
assert ($status_json.status.staged.downloadOnly) "Staged deployment should be in download-only mode"
115115

116-
# Now clear download-only mode by running upgrade without flags
117-
print "Clearing download-only mode with bootc upgrade"
118-
bootc upgrade
116+
# Now clear download-only mode by running upgrade --apply-staged (without registry check)
117+
print "Clearing download-only mode with bootc upgrade --apply-staged"
118+
bootc upgrade --apply-staged
119119

120120
# Verify via JSON that deployment is not in download-only mode
121121
let status_after_json = bootc status --json | from json

0 commit comments

Comments
 (0)