1
0
mirror of https://github.com/containers/bootc.git synced 2026-02-05 15:45:53 +01:00
Files
bootc/tmt/tests/booted/test-download-only-upgrade.nu
Wei Shi a5784832d0 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>
2025-12-12 13:52:56 -05:00

151 lines
5.4 KiB
Nu

# number: 26
# tmt:
# summary: Execute download-only upgrade tests
# duration: 40m
#
# This test does:
# bootc image copy-to-storage
# podman build <from that image> (v1)
# bootc switch <into that image>
# Verify we boot into the new image (v1)
# podman build updated image (v2)
# bootc upgrade --download-only (stage v2 in download-only mode)
# 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 --from-downloaded (clear download-only mode without fetching from image source)
# reboot (should boot into v2)
#
use std assert
use tap.nu
use bootc_testlib.nu
# This code runs on *each* boot.
# Here we just capture information.
bootc status
journalctl --list-boots
let st = bootc status --json | from json
let booted = $st.status.booted.image
def imgsrc [] {
$env.BOOTC_upgrade_image? | default "localhost/bootc-derived-local"
}
# Run on the first boot - build v1 and switch to it
def initial_build [] {
tap begin "download-only upgrade test"
let imgsrc = imgsrc
# This test only works in local mode
assert ($imgsrc | str ends-with "-local") "This test requires local mode"
bootc image copy-to-storage
# Create test file v1 on host
"v1" | save testing-bootc-upgrade-apply
# A simple derived container (v1) that adds a file
"FROM localhost/bootc
COPY testing-bootc-upgrade-apply /usr/share/testing-bootc-upgrade-apply
" | save Dockerfile
# Build it
podman build -t $imgsrc .
# Now, switch into the new image
print $"Applying ($imgsrc)"
bootc switch --transport containers-storage ($imgsrc)
tmt-reboot
}
# Check we have the updated image (v1), then test --download-only
def second_boot [] {
print "verifying second boot - should be on v1"
assert equal $booted.image.transport containers-storage
assert equal $booted.image.image $"(imgsrc)"
# Verify the v1 file exists
assert ("/usr/share/testing-bootc-upgrade-apply" | path exists) "v1 file should exist"
let v1_content = open /usr/share/testing-bootc-upgrade-apply | str trim
assert equal $v1_content "v1"
# Build v2 - updated derived image with same tag
let imgsrc = imgsrc
# Create test file v2 on host
"v2" | save --force testing-bootc-upgrade-apply
"FROM localhost/bootc
COPY testing-bootc-upgrade-apply /usr/share/testing-bootc-upgrade-apply
" | save --force Dockerfile
podman build -t $imgsrc .
# Now upgrade with --download-only (should set deployment to download-only mode)
print $"Upgrading with --download-only to v2"
bootc upgrade --download-only
# Verify deployment is staged and in download-only mode
let status_json = bootc status --json | from json
assert ($status_json.status.staged != null) "Staged deployment should exist"
assert ($status_json.status.staged.downloadOnly) "Staged deployment should be in download-only mode"
# Reboot - should still boot into v1 since deployment is in download-only mode
tmt-reboot
}
# Third boot - verify still on v1, staged deployment discarded, re-stage and clear download-only mode
def third_boot [] {
print "verifying third boot - should still be on v1 (download-only deployment was discarded)"
# Verify we're still on v1
let v1_content = open /usr/share/testing-bootc-upgrade-apply | str trim
assert equal $v1_content "v1" "Should still be on v1 after download-only reboot"
# Verify that the staged deployment was discarded on reboot, as is expected for download-only deployments
let status_before = bootc status --json | from json
assert ($status_before.status.staged == null) "Staged deployment should be discarded after rebooting with a download-only deployment"
# Re-run upgrade --download-only to re-stage the deployment
print "Re-staging with upgrade --download-only"
bootc upgrade --download-only
# Verify via JSON that deployment is in download-only mode again
let status_json = bootc status --json | from json
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 --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
assert (not $status_after_json.status.staged.downloadOnly) "Staged deployment should not be in download-only mode"
# Reboot to apply the update
tmt-reboot
}
# Fourth boot - verify we're on v2
def fourth_boot [] {
print "verifying fourth boot - should be on v2"
assert equal $booted.image.transport containers-storage
assert equal $booted.image.image $"(imgsrc)"
# Verify v2 file content
let v2_content = open /usr/share/testing-bootc-upgrade-apply | str trim
assert equal $v2_content "v2" "Should be on v2 after clearing download-only and reboot"
tap ok
}
def main [] {
# See https://tmt.readthedocs.io/en/stable/stories/features.html#reboot-during-test
match $env.TMT_REBOOT_COUNT? {
null | "0" => initial_build,
"1" => second_boot,
"2" => third_boot,
"3" => fourth_boot,
$o => { error make { msg: $"Invalid TMT_REBOOT_COUNT ($o)" } },
}
}