diff --git a/docs/src/bootc-experimental-composefs.7.md b/docs/src/bootc-experimental-composefs.7.md index 2fe382f58..ee8b22004 100644 --- a/docs/src/bootc-experimental-composefs.7.md +++ b/docs/src/bootc-experimental-composefs.7.md @@ -290,10 +290,6 @@ The composefs backend is experimental; on-disk formats are subject to change. - How container signature enforcement carries over from installation into the installed system is not settled yet. - Extended install APIs: Ability to cleanly implement anaconda %post and osbuild post mutations and general post-install pre-reboot; right now some tools just mount the deployment directory (note this one also relates to [APIs in general](https://github.com/bootc-dev/bootc/issues/522)) -- [zstd:chunked pull failures](https://github.com/bootc-dev/bootc/issues/2408): - images pushed with `--compression-format zstd:chunked` currently fail to - pull on the composefs backend ("unexpected EOF reading tar entry"). Until a - composefs-rs decode fix is incorporated, publish with plain zstd or gzip. ## Related issues diff --git a/tmt/plans/integration.fmf b/tmt/plans/integration.fmf index 06dadb2cf..d9868c4f8 100644 --- a/tmt/plans/integration.fmf +++ b/tmt/plans/integration.fmf @@ -331,4 +331,12 @@ execute: enabled: true extra-try_bind_storage: true extra-skip_if_ostree: true + +/plan-50-switch-zstd-chunked: + summary: Switch to an image with zstd:chunked compressed layers + discover: + how: fmf + test: + - /tmt/tests/tests/test-50-switch-zstd-chunked + extra-skip_if_ostree: true # END GENERATED PLANS diff --git a/tmt/tests/booted/test-switch-zstd-chunked.nu b/tmt/tests/booted/test-switch-zstd-chunked.nu new file mode 100644 index 000000000..60116d6ee --- /dev/null +++ b/tmt/tests/booted/test-switch-zstd-chunked.nu @@ -0,0 +1,96 @@ +# number: 50 +# tmt: +# summary: Switch to an image with zstd:chunked compressed layers +# duration: 30m +# extra: +# skip_if_ostree: true +# +# zstd:chunked layers are multi-frame zstd streams with skippable frames +# holding a table of contents, which a naive zstd decoder truncates; see +# https://github.com/bootc-dev/bootc/issues/2408 +# +# This test does: +# podman build +# podman push --compression-format zstd:chunked +# bootc switch +# Verify we boot into the new image +# +# An OCI directory is used rather than a registry to avoid a network +# dependency. The layers still go through the same decompression code +# as a registry pull. +# +# This is composefs-only for now: on ostree it trips over +# https://github.com/bootc-dev/bootc/issues/2402 (a /boot automount that +# has idled out loses the staged deployment). Enable it there too once +# that is fixed in the base images. +use std assert +use tap.nu + +const image_dir = "/var/tmp/bootc-zstd-chunked" +const data_dir = "/usr/share/testing-bootc-zstd-chunked" +const zstd_media_type = "application/vnd.oci.image.layer.v1.tar+zstd" +# Annotation that c/image adds to each zstd:chunked layer +const chunked_annotation = "io.github.containers.zstd-chunked.manifest-checksum" + +# This code runs on *each* boot. +bootc status +let st = bootc status --json | from json +let booted = $st.status.booted.image + +def initial_build [] { + tap begin "switch to zstd:chunked image" + + let td = mktemp -d + cd $td + + bootc image copy-to-storage + # Layers we already have (i.e. all the base image ones) are skipped when + # pulling, so only the layer added here is actually decompressed. Put a + # number of files in it: zstd:chunked compresses each into its own + # frame(s), so this layer is multi-frame too. The checksums verify + # nothing got silently truncated. + let gen_data = 'for i in $(seq 64); do head -c 65536 /dev/urandom > data$i; done && sha256sum data* > SHA256SUMS' + ( + tap make_uki_containerfile $" + FROM localhost/bootc as base + RUN mkdir -p ($data_dir) && cd ($data_dir) && ($gen_data) + ") | save Dockerfile + podman build -t localhost/bootc-zstd-chunked . + + rm -rf $image_dir + podman push --compression-format zstd:chunked --force-compression localhost/bootc-zstd-chunked $"oci:($image_dir)" + # Free up space; we only need the OCI directory from here on + podman rmi localhost/bootc-zstd-chunked localhost/bootc + + # Make sure we're actually testing what we think we are + let manifest = skopeo inspect --raw $"oci:($image_dir)" | from json + assert (($manifest.layers | length) > 0) + for layer in $manifest.layers { + assert equal $layer.mediaType $zstd_media_type + assert ($chunked_annotation in ($layer.annotations? | default {} | columns)) $"layer ($layer.digest) is not zstd:chunked" + } + + bootc switch --transport oci $image_dir + let st = bootc status --json | from json + assert equal $st.status.staged.image.image.transport oci + tmt-reboot +} + +def second_boot [] { + print "verifying second boot" + assert equal $booted.image.transport oci + assert equal $booted.image.image $image_dir + cd $data_dir + sha256sum --check --quiet SHA256SUMS + bootc internals fsck + 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, + $o => { error make { msg: $"Invalid TMT_REBOOT_COUNT ($o)" } }, + } +} diff --git a/tmt/tests/tests.fmf b/tmt/tests/tests.fmf index f27e9addd..f9f73990d 100644 --- a/tmt/tests/tests.fmf +++ b/tmt/tests/tests.fmf @@ -206,3 +206,8 @@ check: - when: composefs_bridge == true enabled: true test: nu booted/test-49-composefs-1-16-bridge.nu + +/test-50-switch-zstd-chunked: + summary: Switch to an image with zstd:chunked compressed layers + duration: 30m + test: nu booted/test-switch-zstd-chunked.nu