Skip to content

[WIP] test: Add integration test running on github runner #1496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: bootc integration test
on:
pull_request:
branches: [main]

jobs:
build:
strategy:
matrix:
test_os: [fedora-42]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's make this be quay.io/fedora/fedora:42 e.g. - see below

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This test_os will be [fedora-41, fedora-42, fedora-43, centos-9, centos-10].


runs-on: ubuntu-latest

steps:
- name: Install podman for heredoc support
Copy link
Collaborator

@cgwalters cgwalters Aug 8, 2025

Choose a reason for hiding this comment

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

Unrelated to this PR specifically but we should probably factor this stuff out into a shared action helper

run: |
set -eux
echo 'deb [trusted=yes] https://ftp.debian.org/debian/ testing main' | sudo tee /etc/apt/sources.list.d/testing.list
sudo apt update
sudo apt install -y crun/testing podman/testing

- uses: actions/checkout@v4

- name: Build bootc and bootc image
env:
TEST_OS: ${{ matrix.test_os }}
run: tests/build.sh

- name: Archive bootc disk image - disk.raw
uses: actions/upload-artifact@v4
with:
name: PR-${{ github.event.number }}-${{ matrix.test_os }}-disk
path: /tmp/tmp-bootc-build/disk.raw
retention-days: 1

- name: Archive SSH private key - id_rsa
uses: actions/upload-artifact@v4
with:
name: PR-${{ github.event.number }}-${{ matrix.test_os }}-id_rsa
path: /tmp/tmp-bootc-build/id_rsa
retention-days: 1

test:
needs: build
strategy:
matrix:
test_os: [fedora-42]
tmt_plan: [test-01-readonly, test-20-local-upgrade, test-21-logically-bound-switch, test-22-logically-bound-install, test-23-install-outside-container, test-24-local-upgrade-reboot]

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Install dependence
run: |
sudo apt-get update
sudo apt install -y qemu-kvm qemu-system
pip install --user tmt

- name: Create folder to save disk image
run: mkdir -p /tmp/tmp-bootc-build

- name: Download disk.raw
uses: actions/download-artifact@v4
with:
name: PR-${{ github.event.number }}-${{ matrix.test_os }}-disk
path: /tmp/tmp-bootc-build

- name: Download id_rsa
uses: actions/download-artifact@v4
with:
name: PR-${{ github.event.number }}-${{ matrix.test_os }}-id_rsa
path: /tmp/tmp-bootc-build

- name: Run test
env:
TMT_PLAN_NAME: ${{ matrix.tmt_plan }}
run: chmod 600 /tmp/tmp-bootc-build/id_rsa && tests/test.sh

- name: Archive TMT logs
if: always()
uses: actions/upload-artifact@v4
with:
name: tmt-log-PR-${{ github.event.number }}-${{ matrix.test_os }}-${{ matrix.tmt_plan }}
path: /var/tmp/tmt
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ test-bin-archive: all
test-tmt:
cargo xtask test-tmt

test:
tests/build.sh && tests/test.sh
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this would then become:

tmpd=$(mktemp -d) && cd $tmpd && $srcdir/tests/build.sh && $srcdir/tests/test.sh

or so


# This gates CI by default. Note that for clippy, we gate on
# only the clippy correctness and suspicious lints, plus a select
# set of default rustc warnings.
Expand Down
118 changes: 118 additions & 0 deletions tests/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#!/bin/bash
set -exuo pipefail

# This script basically builds bootc from source using the provided base image,
# then runs the target tests.

mkdir -p /tmp/tmp-bootc-build
BOOTC_TEMPDIR="/tmp/tmp-bootc-build"

# Get OS info from TEST_OS env
OS_ID=$(echo "$TEST_OS" | cut -d '-' -f 1)
OS_VERSION_ID=$(echo "$TEST_OS" | cut -d '-' -f 2)

# Base image
case "$OS_ID" in
"centos")
TIER1_IMAGE_URL="quay.io/centos-bootc/centos-bootc:stream${OS_VERSION_ID}"
;;
"fedora")
TIER1_IMAGE_URL="quay.io/fedora/fedora-bootc:${OS_VERSION_ID}"
;;
esac

CONTAINERFILE="${BOOTC_TEMPDIR}/Containerfile"
tee "$CONTAINERFILE" > /dev/null << CONTAINERFILEOF
FROM $TIER1_IMAGE_URL as build

WORKDIR /code

RUN <<EORUN
set -xeuo pipefail
. /usr/lib/os-release
case \$ID in
centos|rhel) dnf config-manager --set-enabled crb;;
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
esac
dnf -y builddep contrib/packaging/bootc.spec
dnf -y install git-core
EORUN

RUN mkdir -p /build/target/dev-rootfs
# git config --global --add safe.directory /code to fix "fatal: detected dubious ownership in repository at '/code'" error
RUN --mount=type=cache,target=/build/target --mount=type=cache,target=/var/roothome git config --global --add safe.directory /code && make test-bin-archive && mkdir -p /out && cp target/bootc.tar.zst /out

FROM $TIER1_IMAGE_URL

# Inject our built code
COPY --from=build /out/bootc.tar.zst /tmp
RUN tar -C / --zstd -xvf /tmp/bootc.tar.zst && rm -vrf /tmp/*

RUN <<EORUN
set -xeuo pipefail

# Provision test requirement
/code/hack/provision-derived.sh
# Also copy in some default install configs we use for testing
cp -a /code/hack/install-test-configs/* /usr/lib/bootc/install/
# And some test kargs
cp -a /code/hack/test-kargs/* /usr/lib/bootc/kargs.d/

# For testing farm
mkdir -p -m 0700 /var/roothome

# Enable ttyS0 console
mkdir -p /usr/lib/bootc/kargs.d/
cat <<KARGEOF >> /usr/lib/bootc/kargs.d/20-console.toml
kargs = ["console=ttyS0,115200n8"]
KARGEOF

# For test-22-logically-bound-install
cp -a /code/tmt/tests/lbi/usr/. /usr
ln -s /usr/share/containers/systemd/curl.container /usr/lib/bootc/bound-images.d/curl.container
ln -s /usr/share/containers/systemd/curl-base.image /usr/lib/bootc/bound-images.d/curl-base.image
ln -s /usr/share/containers/systemd/podman.image /usr/lib/bootc/bound-images.d/podman.image

# Install rsync which is required by tmt
dnf -y install cloud-init rsync
dnf -y clean all

rm -rf /var/cache /var/lib/dnf
EORUN
CONTAINERFILEOF

LOCAL_IMAGE="localhost/bootc:test"
sudo podman build \
--retry 5 \
--retry-delay 5s \
-v "$(pwd)":/code:z \
-t "$LOCAL_IMAGE" \
-f "$CONTAINERFILE" \
"$BOOTC_TEMPDIR"

SSH_KEY=${BOOTC_TEMPDIR}/id_rsa
ssh-keygen -f "${SSH_KEY}" -N "" -q -t rsa-sha2-256 -b 2048

sudo truncate -s 10G "${BOOTC_TEMPDIR}/disk.raw"

# For test-22-logically-bound-install
sudo podman pull --retry 5 --retry-delay 5s quay.io/curl/curl:latest
sudo podman pull --retry 5 --retry-delay 5s quay.io/curl/curl-base:latest
sudo podman pull --retry 5 --retry-delay 5s registry.access.redhat.com/ubi9/podman:latest

sudo podman run \
--rm \
--privileged \
--pid=host \
--security-opt label=type:unconfined_t \
-v /var/lib/containers:/var/lib/containers \
-v /dev:/dev \
-v "$BOOTC_TEMPDIR":/output \
"$LOCAL_IMAGE" \
bootc install to-disk \
--filesystem "xfs" \
--root-ssh-authorized-keys "/output/id_rsa.pub" \
--karg=console=ttyS0,115200n8 \
--generic-image \
--via-loopback \
/output/disk.raw
70 changes: 70 additions & 0 deletions tests/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash
set -exuo pipefail

# This script runs disk image with qemu-system and run tmt against this vm.

BOOTC_TEMPDIR="/tmp/tmp-bootc-build"
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The temporary directory path /tmp/tmp-bootc-build is hardcoded here and in build.sh. This creates a tight, implicit coupling between the two scripts. It would be more robust to define this path in one place (e.g., in the Makefile), export it as an environment variable, and have both scripts use it. This would also make it easier to manage the lifecycle of the temporary directory (creation and cleanup).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I think we could just require this script to be invoked in the context of the temporary directory.

That said also, the only thing that actually binds the two things together right now is the ssh key.

But we can avoid that by not using --root-ssh-authorized-keys at bootc install to-disk time but instead injecting the SSH key via systemd credentials - that's how podman-bootc does it.

(Of course this whole topic instantly gets into the whole https://gitlab.com/fedora/bootc/tracker/-/issues/2 and whether/how podman-bootc and other virt provisioning tools should be shared underneath different testing frameworks)

Anyways for now though let's just change the GHA to allocate a temporary directory, see below

SSH_OPTIONS=(-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5)
SSH_KEY=${BOOTC_TEMPDIR}/id_rsa

ARCH=$(uname -m)
case "$ARCH" in
"aarch64")
sudo qemu-system-aarch64 \
-name bootc-vm \
-enable-kvm \
-machine virt \
-cpu host \
-m 2G \
-bios /usr/share/AAVMF/AAVMF_CODE.fd \
-drive file="${BOOTC_TEMPDIR}/disk.raw",if=virtio,format=raw \
-net nic,model=virtio \
-net user,hostfwd=tcp::2222-:22 \
-display none \
-daemonize
;;
"x86_64")
sudo qemu-system-x86_64 \
-name bootc-vm \
-enable-kvm \
-cpu host \
-m 2G \
-drive file="${BOOTC_TEMPDIR}/disk.raw",if=virtio,format=raw \
-net nic,model=virtio \
-net user,hostfwd=tcp::2222-:22 \
-display none \
-daemonize
;;
*)
echo "Only support x86_64 and aarch64" >&2
exit 1
;;
esac

wait_for_ssh_up() {
SSH_STATUS=$(ssh "${SSH_OPTIONS[@]}" -i "$SSH_KEY" -p 2222 root@"${1}" '/bin/bash -c "echo -n READY"')
if [[ $SSH_STATUS == READY ]]; then
echo 1
else
echo 0
fi
}

for _ in $(seq 0 30); do
RESULT=$(wait_for_ssh_up "localhost")
if [[ $RESULT == 1 ]]; then
echo "SSH is ready now! 🥳"
break
fi
sleep 10
done

# Make sure VM is ready for testing
ssh "${SSH_OPTIONS[@]}" \
-i "$SSH_KEY" \
-p 2222 \
root@localhost \
"bootc status"

# TMT will rsync tmt-* scripts to TMT_SCRIPTS_DIR=/var/lib/tmt/scripts
tmt run --all --verbose -e TMT_SCRIPTS_DIR=/var/lib/tmt/scripts provision --how connect --guest localhost --port 2222 --user root --key "$SSH_KEY" plan --name "/tmt/plans/bootc-integration/${TMT_PLAN_NAME}"
46 changes: 46 additions & 0 deletions tmt/plans/bootc-integration.fmf
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
execute:
how: tmt

/test-01-readonly:
summary: Execute booted readonly/nondestructive tests
discover:
how: fmf
test:
- /tmt/tests/test-01-readonly

/test-20-local-upgrade:
summary: Execute local upgrade tests
discover:
how: fmf
test:
- /tmt/tests/test-20-local-upgrade

/test-21-logically-bound-switch:
summary: Execute logically bound images tests for switching images
discover:
how: fmf
test:
- /tmt/tests/test-21-logically-bound-switch

/test-22-logically-bound-install:
summary: Execute logically bound images tests for switching images
environment+:
LBI: enabled
discover:
how: fmf
test:
- /tmt/tests/test-22-logically-bound-install

/test-23-install-outside-container:
summary: Execute tests for installing outside of a container
discover:
how: fmf
test:
- /tmt/tests/test-23-install-outside-container

/test-24-local-upgrade-reboot:
summary: Execute local upgrade tests with automated reboot
discover:
how: fmf
test:
- /tmt/tests/test-24-local-upgrade-reboot
Loading