Skip to content

Add boot test infrastructure using osbuild/images library (HMS-10336)#85

Draft
thozza wants to merge 22 commits into
osbuild:mainfrom
thozza:HMS-10336
Draft

Add boot test infrastructure using osbuild/images library (HMS-10336)#85
thozza wants to merge 22 commits into
osbuild:mainfrom
thozza:HMS-10336

Conversation

@thozza
Copy link
Copy Markdown
Member

@thozza thozza commented May 6, 2026

Marked as draft until osbuild/images#2335 is merged.

Add end-to-end boot testing for derived bootc container images by reusing the existing test tooling from the osbuild/images repository. Instead of building custom test infrastructure, the pipeline clones the images library at a pinned commit, builds disk images using its cmd/build tool, and validates them with its boot-image script. A Python-based CI generator produces the GitLab CI configuration from a declarative test matrix, keeping job definitions maintainable as new image types and distros are added.

Note that the images library does not yet support boot-testing all image types - notably qcow2 on aarch64 and GCP images. For those, the pipeline still builds the container and disk images (validating the build succeeds), but skips the boot validation step. Once the images library gains boot-test support for these types, it will be automatically picked up when the Schutzfile ref is updated.

Architectural Changes

The test pipeline is split into four composable shell scripts (setup.shget-container.shbuild.shboot.sh), each handling one stage of the build-and-boot flow. This separation allows swapping the container source (e.g., from a local build to a registry pull) without touching the build or boot logic.

The GitLab CI configuration is generated from test/config.yml by test/generate_ci.py rather than hand-maintained. The generator parses Containerfile COPY directives to produce per-job change detection rules, so CI jobs only run when relevant files change. A GitHub Actions staleness check enforces that the committed .gitlab-ci.yml stays in sync with the generator output.

Key Changes

  • Pin the osbuild/images library via Schutzfile and delegate setup, dependency installation, and boot validation to its scripts
  • Add shell pipeline: get-container.sh (podman build), build.sh (disk image via cmd/build + info.json for boot-image), boot.sh (delegates to boot-image)
  • Add Python CI generator that reads test/config.yml, parses Containerfile COPY sources for change detection rules, and emits .gitlab-ci.yml
  • Support per-containerfile runner overrides, RHEL subscription, and Red Hat registry login as config-driven CI variables
  • Add GitHub Actions workflows: staleness check for generated CI config, weekly Schutzfile ref update with auto-PR
  • Fix stream10-installer and rhel-10-installer to use containers-storage transport for the bootc payload, and add fuse-overlayfs for overlay-on-overlay support

Breaking Changes

This PR is fully backward compatible.

Testing

  • 29 unit tests cover the CI generator: COPY directive parsing (single-source, multi-source, heredoc skip, ${TARGETARCH} substitution, error cases), change rule construction, job building, and end-to-end config generation
  • GitHub Actions staleness check regenerates .gitlab-ci.yml on every PR to main and fails if the committed file diverges from the generator output
  • Boot tests themselves run in GitLab CI on Fedora runners (AWS for cloud image types, OpenStack for image types requiring nested virtualization)

Comment thread test/test_generate_ci.py Outdated
@thozza thozza force-pushed the HMS-10336 branch 4 times, most recently from aad6cfc to b9c4d06 Compare May 12, 2026 17:06
Comment thread test/generate_ci.py Outdated
"aarch64": "arm64",
}

COPY_RE = re.compile(r"^COPY\s+(\S+)\s+(\S+)")
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COPY verb supports various arguments, this is not captured here which is fine - we do not use it AFAIK. However, this will silently ignore them which is dangerous.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I've added a detection logic to the generator and it produces hard failure.

Comment thread test/generate_ci.py
rules.extend(copy_dirs)
rules.append("test/**/*")
rules.append("Schutzfile")
return rules
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this only cares about directories and not files? Like COPY file1 /file1.

This is very fragile, if there is a bug here or we add something that is not covered, this will be painful to figure out.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generator now handles files and directories. The original version was handling only the bare minimum currently used by the Containerfiles in this repo.

@lzap
Copy link
Copy Markdown
Collaborator

lzap commented May 13, 2026

Tests makes assumptions we can possibly break in the future making tests to pass incorrectly. If we are doing this, let's write some validator/linter that will enforce these, for example:

  • No COPY rule can contain arguments.
  • All COPY rules only copy directories.

thozza added 3 commits May 14, 2026 15:45
The Schutzfile pins the images library commit that the boot test
infrastructure uses. The update script fetches the latest commit
from GitHub and updates the ref, mirroring the pattern from the
images library's update-schutzfile-osbuild.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Clone the images library at the Schutzfile-pinned ref, then
delegate to its setup-osbuild-repo (which auto-detects the host
distro and reads the per-distro osbuild commit from the images
library's own Schutzfile) and install-dependencies scripts.
The images repo URL is overridable via IMAGES_REPO_URL for
cross-testing with draft PRs in the images library.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Build a container from a Containerfile into local podman storage
at quay.io/redhat-services-prod/insights-management-tenant/image-builder-bootc-foundry/${CONTAINERFILE}:latest,
which is consistent with the location for prod container images. Using
the same tag is important to make the installer images work out of the
box.

This script is isolated from build.sh so the container source can be
swapped to a registry pull without changing the build logic.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
@thozza thozza changed the title Add boot tests (HMS-10336) Add boot test infrastructure using osbuild/images library (HMS-10336) May 14, 2026
thozza added 5 commits May 14, 2026 18:31
Build a disk image using the images library's cmd/build tool.
Create the build config JSON (with optional installer payload
ref), invoke cmd/build with the bootc container ref, and write
info.json into the output directory for boot-image to consume.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Discover the build output directory and config, then delegate to
the images library's boot-image script. boot-image reads info.json
to determine the boot method (QEMU, ISO, cloud) and runs
check-host-config for post-boot validation.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Add scripts that update GitHub PR with the GitLab CI pipeline status and
unregister a RHEL host. Also add the file with terraform ref and also
team SSH keys, which get configured as trusted on the CI runner. These
files were taken from the osbuild/images and osbuild/osbuild-composer
repositories and amended for the use in this repo.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Parse COPY directives from Containerfiles to extract source paths
for CI change detection rules. Validate each source against the
filesystem to classify it as a directory (producing glob patterns)
or a plain file. Support single-source and multi-source COPY commands
(e.g. COPY src1 src2 /dest/). Handle ${TARGETARCH} substitution,
skip heredoc COPYs, and reject COPY with options (--chmod, --from,
etc.).

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Build change rules from parsed COPY directives, compose CI job
dictionaries with runner tags and script sections, and assemble
the full GitLab CI config. Installer entries with a payload
containerfile get extra container build steps and expanded
change detection rules.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
thozza added 14 commits May 14, 2026 18:32
Wire up main() to read config, parse all referenced
Containerfiles, generate CI jobs, and emit YAML to stdout.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Allow individual containerfile entries in config.yml to specify a
runner, overriding the distro-level default. This is needed for image
types like installers that require nested virtualization for boot
tests.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Building RHEL derived bootc container images needs accessing RHEL
repositories to install additional packages. Add a subscription-needed
flag support to the test config, propagate it as a CI variable, and
register the system with subscription-manager when the flag is set.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Allow authenticating podman with registry.redhat.io when the
rh-registry-login-needed flag is set in the test config.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Define the central test matrix for boot tests. Each distro maps to
a list of Containerfiles with their target image type and supported
architectures. The generator reads this to produce the GitLab CI
configuration.

The osbuild/images CI runs only on Fedora. As a consequence, it uses
packages for boot-testing, which are not available on RHEL or CentOS
Stream. To not complicate the setup in this repository, let's use
Fedora runner as well for all distros. For the purpose of boot-testing
the disk images built from derived containers, there is no downside in
doing it all on Fedora.

Use rhos-01 runner for boot-testing image types which require nested
virtualization.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Generated from test/config.yml by test/generate_ci.py. This file
is committed so it is reviewable in PRs. Regenerate with
'python3 test/generate_ci.py > .gitlab-ci.yml' after changing
the config or generator.

Update .yamllint.yaml to use consistent 2-space indentation for
sequences, matching PyYAML's default output format. This ensures
the generated .gitlab-ci.yml passes yamllint validation.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Regenerate .gitlab-ci.yml on every PR to 'main', and fail if the
result differs from what is committed. This catches forgotten
regeneration after config or generator changes.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Automatically fetch the latest images library main branch
commit, update the Schutzfile ref, and open a PR. The resulting
PR triggers the normal GitLab CI pipeline so the updated images
library version is boot-tested before merging.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Add 'make test' to run the generator unit tests and 'make
generate-ci' to regenerate .gitlab-ci.yml from the test config.

Assisted-by: Claude Code
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Switch the bootc kickstart source from pulling the upstream
centos-bootc image via registry to using the foundry-built
stream10-qcow2 image from containers-storage, and drop the
now-unnecessary --target-imgref.

This is consistent with the rhel-10-installer.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
When the booted Anaconda installer deploys the bootc payload from
containers-storage, the container runtime attempts to use overlayfs
on a filesystem that is already overlay-backed, which the kernel
does not support. Adding fuse-overlayfs provides a userspace overlay
implementation that avoids this limitation.

This aligns with the rhel-10-installer which already includes
fuse-overlayfs.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Fix the ostreecontainer --url to include the :latest tag and correct
the commented-out bootc --source-imgref to use containers-storage:
transport, consistent with stream10-installer. The previous
local-storage:// transport does not exist.

Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Signed-off-by: Tomáš Hozza <thozza@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants