Skip to content

Commit 7e3e24e

Browse files
committed
ci/upgrade: Add composefs variant and upgrade --check test
Extend the upgrade test matrix with an ostree/composefs variant dimension, so we test upgrading both storage backends. For composefs, the upgrade source image needs: - The bootc dracut module in the initramfs (auto-excluded by check()) - A fsverity-capable root filesystem (ext4 or btrfs via configure-rootfs) - enforcing=0 karg (base image SELinux policy lacks composefs contexts) The enforcing=0 karg is also added to the target image test-kargs so the post-upgrade boot works. A new readonly test (031-test-upgrade-check) runs `bootc upgrade --check` after the upgrade to verify the running system can still self-update. For composefs with pre-upgrade bootc <= 1.13, this is a known failure (#2074) due to incompatible on-disk state. The pre-upgrade bootc version is saved to /var/bootc-pre-upgrade-version during first boot. Assisted-by: OpenCode (Claude claude-opus-4-6) Signed-off-by: Colin Walters <walters@verbum.org>
1 parent 1ed0aa2 commit 7e3e24e

7 files changed

Lines changed: 90 additions & 4 deletions

File tree

.github/workflows/ci.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ jobs:
270270
fail-fast: false
271271
matrix:
272272
test_os: [fedora-43, centos-10]
273+
variant: [ostree, composefs]
273274

274275
runs-on: ubuntu-24.04
275276

@@ -286,6 +287,7 @@ jobs:
286287
run: |
287288
BASE=$(just pullspec-for-os base ${{ matrix.test_os }})
288289
echo "BOOTC_base=${BASE}" >> $GITHUB_ENV
290+
echo "BOOTC_variant=${{ matrix.variant }}" >> $GITHUB_ENV
289291
echo "BOOTC_SKIP_PACKAGE=1" >> $GITHUB_ENV
290292
echo "RUST_BACKTRACE=full" >> $GITHUB_ENV
291293
@@ -302,7 +304,7 @@ jobs:
302304
if: always()
303305
uses: actions/upload-artifact@v7
304306
with:
305-
name: "tmt-log-PR-${{ github.event.number }}-${{ matrix.test_os }}-upgrade-${{ env.ARCH }}"
307+
name: "tmt-log-PR-${{ github.event.number }}-${{ matrix.test_os }}-${{ matrix.variant }}-upgrade-${{ env.ARCH }}"
306308
path: /var/tmp/tmt
307309

308310
# Test bootc install on Fedora CoreOS (separate job to avoid disk space issues

Justfile

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,22 @@ test-composefs bootloader filesystem boot_type seal_state *ARGS:
149149
# locally-built image available inside the VM via containers-storage transport.
150150
[group('core')]
151151
test-upgrade *ARGS: build _build-upgrade-source-image
152-
cargo xtask run-tmt --env=BOOTC_variant={{variant}} --env=BOOTC_test_upgrade_image={{base_img}} --upgrade-image={{base_img}} {{upgrade_source_img}} {{ARGS}} readonly
152+
#!/bin/bash
153+
set -xeuo pipefail
154+
composefs_args=()
155+
if [[ "{{variant}}" = composefs ]]; then
156+
composefs_args=(--composefs-backend \
157+
--bootloader={{bootloader}} \
158+
--filesystem={{filesystem}} \
159+
--seal-state={{seal_state}} \
160+
--boot-type={{boot_type}} \
161+
--karg=enforcing=0)
162+
fi
163+
cargo xtask run-tmt --env=BOOTC_variant={{variant}} \
164+
--env=BOOTC_test_upgrade_image={{base_img}} \
165+
--upgrade-image={{base_img}} \
166+
"${composefs_args[@]}" \
167+
{{upgrade_source_img}} {{ARGS}} readonly
153168

154169
# Run cargo fmt and clippy checks in container
155170
[group('core')]
@@ -351,7 +366,7 @@ _build-upgrade-image:
351366

352367
# Build the upgrade source image: base image + tmt dependencies (rsync, nu, cloud-init)
353368
_build-upgrade-source-image:
354-
podman build --build-arg=base={{base}} -t {{upgrade_source_img}} -f tmt/tests/Dockerfile.upgrade-source .
369+
podman build --build-arg=base={{base}} --build-arg=variant={{variant}} -t {{upgrade_source_img}} -f tmt/tests/Dockerfile.upgrade-source .
355370

356371
# Copy an image from user podman storage to root's podman storage
357372
# This allows building as regular user then running privileged tests

crates/xtask/src/tmt.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ pub(crate) fn run_tmt(sh: &Shell, args: &RunTmtArgs) -> Result<()> {
492492
opts.push(format!("--bootloader={b}"));
493493
}
494494

495+
for k in &args.karg {
496+
opts.push(format!("--karg={k}"));
497+
}
498+
495499
opts
496500
};
497501

crates/xtask/src/xtask.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ pub(crate) struct RunTmtArgs {
178178
// Required to send kargs to only bls installs
179179
#[arg(long, default_value_t, requires = "composefs_backend")]
180180
pub(crate) boot_type: BootType,
181+
182+
/// Additional kernel arguments to pass to bcvk
183+
#[arg(long)]
184+
pub(crate) karg: Vec<String>,
181185
}
182186

183187
/// Arguments for tmt-provision command

tmt/tests/Dockerfile.upgrade-source

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,27 @@
66
# handles SSH key injection itself; cloud-init interferes with that.
77
ARG base
88
FROM ${base}
9-
COPY hack/provision-derived.sh hack/packages.txt /run/provision/
9+
COPY hack/provision-derived.sh hack/packages.txt contrib/packaging/configure-rootfs /run/provision/
10+
ARG variant=ostree
1011
RUN --mount=type=tmpfs,target=/tmp <<EORUN
1112
set -xeuo pipefail
1213
cd /run/provision
1314
# Install nu and tmt dependencies using the same script as the main build,
1415
# but with SKIP_CONFIGS=1 since we don't need LBIs or test kargs in the
1516
# upgrade source image (those come from the image we upgrade into).
1617
SKIP_CONFIGS=1 ./provision-derived.sh
18+
# Ensure a root filesystem type is configured so `bootc install to-disk`
19+
# works for base images that don't ship a default (e.g. Fedora).
20+
# For the ostree variant, configure-rootfs will default to xfs.
21+
./configure-rootfs "${variant}"
22+
# For composefs, rebuild the initramfs to include the bootc dracut module.
23+
# The module's check() returns 255 so it's never auto-included, but it's
24+
# required for composefs root setup during boot.
25+
if [[ "${variant}" == composefs* ]]; then
26+
mkdir -p /etc/dracut.conf.d
27+
echo 'add_dracutmodules+=" bootc "' > /etc/dracut.conf.d/50-bootc-composefs.conf
28+
kver=$(cd /usr/lib/modules && echo *)
29+
dracut --force --kver "$kver" "/usr/lib/modules/$kver/initramfs.img"
30+
fi
1731
rm -rf /run/provision
1832
EORUN

tmt/tests/booted/bootc_testlib.nu

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ export def maybe_upgrade [] {
5050
if not (have_hostexports) {
5151
error make { msg: "BOOTC_test_upgrade_image is set but host exports (--bind-storage-ro) are not available" }
5252
}
53+
# Save the pre-upgrade bootc version so post-upgrade tests
54+
# can detect known incompatibilities with older versions.
55+
let pre_ver = (bootc --version | parse "bootc {v}" | get 0.v)
56+
$pre_ver | save /var/bootc-pre-upgrade-version
57+
print $"Pre-upgrade bootc version: ($pre_ver)"
58+
5359
print $"Upgrade image specified: ($upgrade_image)"
5460
print "Performing upgrade switch..."
5561
bootc switch --transport containers-storage $upgrade_image
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
use std assert
2+
use tap.nu
3+
4+
tap begin "verify bootc upgrade --check succeeds after upgrade"
5+
6+
# After an upgrade (bootc switch), verify that the running system can
7+
# still query for further upgrades. This catches regressions where
8+
# on-disk state created by an older bootc is incompatible with the
9+
# new bootc's upgrade machinery (e.g. #2074).
10+
# Only meaningful when we actually performed an upgrade.
11+
let upgrade_image = $env.BOOTC_test_upgrade_image? | default ""
12+
if $upgrade_image == "" {
13+
print "# skip: not an upgrade test (BOOTC_test_upgrade_image not set)"
14+
tap ok
15+
exit 0
16+
}
17+
18+
# Read the pre-upgrade bootc version saved during first boot.
19+
let old_version_str = (open /var/bootc-pre-upgrade-version | str trim)
20+
let old_ver = ($old_version_str | split row "." | each { into int })
21+
print $"Pre-upgrade bootc version: ($old_version_str)"
22+
23+
let is_composefs = (tap is_composefs)
24+
25+
print "Running bootc upgrade --check to verify upgrade machinery works..."
26+
let result = do -i { bootc upgrade --check } | complete
27+
if $result.exit_code == 0 {
28+
print "bootc upgrade --check succeeded"
29+
} else {
30+
print $"bootc upgrade --check failed: ($result.stderr)"
31+
# Known failure: composefs upgrades from bootc <= 1.13 have
32+
# incompatible on-disk state (see #2074).
33+
let old_bootc_le_1_13 = ($old_ver.0 < 1) or (($old_ver.0 == 1) and ($old_ver.1 <= 13))
34+
if $is_composefs and $old_bootc_le_1_13 {
35+
print $"# known failure: composefs upgrade --check from bootc ($old_version_str) \(see #2074\)"
36+
} else {
37+
error make { msg: $"bootc upgrade --check failed unexpectedly: ($result.stderr)" }
38+
}
39+
}
40+
41+
tap ok

0 commit comments

Comments
 (0)