Skip to content

Commit 8d1e570

Browse files
allisonkarlitskayacgwalters
authored andcommitted
examples: port the tests to test.thing
Drop our dependency on cockpit-bots (checked out from its git repository and requiring libvirt and other heavy dependencies) and switch over to using test.thing (vendored) via pytest. We no longer install ssh keys into the images: test.thing generates an ephemeral key on each run and feeds it into the guest. Expand examples/README.md to describe how this is all intended to be used. Adjust our github workflows appropriately. The systemd version on the runner isn't new enough to have systemd-ssh-proxy, so install our polyfill. We also need to make sure the vhost-vsock is accessible to the user in the same way as /dev/kvm. Signed-off-by: Allison Karlitskaya <[email protected]>
1 parent e9b0c47 commit 8d1e570

File tree

17 files changed

+1211
-90
lines changed

17 files changed

+1211
-90
lines changed

.github/workflows/examples.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ jobs:
4141

4242
- name: Setup /dev/kvm
4343
run: |
44+
set -eux
4445
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm.rules
46+
echo 'KERNEL=="vhost-vsock", GROUP="kvm", MODE="0666", OPTIONS+="static_node=vhost-vsock"' | sudo tee /etc/udev/rules.d/99-vhost-vsock.rules
4547
sudo udevadm control --reload-rules
46-
sudo udevadm trigger --name-match=kvm --settle
47-
ls -l /dev/kvm
48+
sudo udevadm trigger --settle
49+
ls -l /dev/kvm /dev/vhost-vsock
4850
4951
- name: Install dependencies
5052
run: |
@@ -55,10 +57,8 @@ jobs:
5557
erofs-utils \
5658
fsverity \
5759
mtools \
58-
libvirt-daemon \
59-
libvirt-daemon-driver-qemu \
60-
python3-libvirt \
61-
qemu-system \
60+
python3-pytest-asyncio \
61+
qemu-kvm \
6262
systemd-boot-efi
6363
6464
- name: Get a newer podman for heredoc support (from plucky)
@@ -84,6 +84,9 @@ jobs:
8484
examples/common/install-patched-tools ~/bin
8585
fi
8686
87+
- name: Install systemd-ssh-proxy polyfill
88+
run: sudo cp examples/bls/test-thing.workarounds/systemd-ssh-proxy /usr/lib/systemd
89+
8790
- name: Run example tests
8891
run: |
8992
export PATH="${HOME}/bin:${PATH}"

examples/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
/*/*.qcow2
12
/*/VARS_CUSTOM.secboot.fd*
23
/*/cfsctl
34
/*/extra/usr/lib/dracut/modules.d/37composefs/composefs-setup-root
4-
/*/*.qcow2
55
/*/secureboot
66
/*/tmp/
77
/common/fix-verity/fix-verity.efi
88
/test/bots
9+
__pycache__/

examples/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,45 @@ a verified operating system image.
1212
- `unified`: similar to the `uki` example, but avoiding the intermediate `cfsctl` step by running `cfsctl` inside a build stage from the `Containerfile` itself.
1313
This involves bind-mounting the earlier build stage of the base image so that we can measure it from inside the stage that builds the UKI.
1414
- `unified-secureboot`: based on the `unified` example, adding signing for Secure Boot.
15+
16+
## Using the examples
17+
18+
The main use of the examples is to act as a scratch space for feature
19+
development (like initramfs integration) and to show how you can build a system
20+
image in various configurations using composefs. They are also run from CI and
21+
are very useful for local testing, however.
22+
23+
You can build the various images using the `build` script found in each
24+
subdirectory. It takes a single argument: the OS to build the image from
25+
(`fedora`, `rawhide`, `arch`, `ubuntu`, `rhel9`, etc.). You should not build
26+
multiple images in parallel due to conflicting feature flags and shared use of
27+
the tmp/ directory. After the image is built, you can run tests against it by
28+
saying something like:
29+
30+
```
31+
TEST_IMAGE=examples/bls/arch-bls-efi.qcow2 pytest examples/test
32+
```
33+
34+
Building and running tests on a particular image is supported via the
35+
`examples/test/run` script, which you can use like:
36+
37+
```
38+
examples/test/run bls rhel9
39+
```
40+
41+
The tests are run using [`test.thing`](https://codeberg.org/lis/test.thing). We
42+
keep a copy of it in-tree. You you can also use it to run the VM images for
43+
manual inspection:
44+
45+
```
46+
examples/testthing.py examples/bls/fedora-bls-efi.qcow2
47+
```
48+
49+
In that case, you should add this fragment to your ssh configuration:
50+
51+
```
52+
Host tt.*
53+
ControlPath ${XDG_RUNTIME_DIR}/test.thing/%h/ssh
54+
```
55+
56+
So you can access the test machine via `ssh tt.0` and so on.

examples/bls/build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ if [ "${FS_VERITY_MODE:-repart}" = "none" ]; then
6060
CFSCTL="$CFSCTL --insecure"
6161
fi
6262

63-
${CFSCTL} oci prepare-boot "${BASE_ID}" --bootdir tmp/efi --cmdline console=ttyS0,115200 --entry-id=example --cmdline rw
63+
${CFSCTL} oci prepare-boot "${BASE_ID}" --bootdir tmp/efi --entry-id=example --cmdline rw
6464

6565
../common/install-systemd-boot
6666
../common/make-image "${os}-bls-efi.qcow2"

examples/bls/extra/root/.ssh/authorized_keys

Lines changed: 0 additions & 1 deletion
This file was deleted.

examples/pyproject.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[tool.pytest.ini_options]
2+
addopts = "--strict-markers -v"
3+
asyncio_mode = "auto"
4+
pythonpath = "."
5+
testpaths = ["test"]

examples/test/run

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,8 @@ set -eux
44

55
cd "${0%/*}/.."
66

7-
if [ ! -e test/bots ]; then
8-
if [ -h ~/.config/cockpit-dev/bots ]; then
9-
ln -sfT "$(realpath --relative-to=test ~/.config/cockpit-dev)/bots" test/bots
10-
else
11-
git clone https://github.com/cockpit-project/bots test/bots
12-
fi
13-
fi
14-
157
EXAMPLE="$1"
168
OS="$2"
179

1810
"${EXAMPLE}/build" "${OS}"
19-
test/run-tests "${EXAMPLE}/${OS}-${EXAMPLE}-efi.qcow2"
11+
TEST_IMAGE="${EXAMPLE}/${OS}-${EXAMPLE}-efi.qcow2" pytest test

examples/test/run-tests

Lines changed: 0 additions & 65 deletions
This file was deleted.

examples/test/test_basic.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#!/usr/bin/python3
2+
3+
import os
4+
from collections.abc import AsyncGenerator
5+
6+
import pytest
7+
8+
import testthing
9+
10+
11+
@pytest.fixture
12+
async def machine() -> AsyncGenerator[testthing.VirtualMachine, None]:
13+
image = os.getenv("TEST_IMAGE")
14+
if not image:
15+
raise RuntimeError("TEST_IMAGE environment variable must be set")
16+
with testthing.IpcDirectory() as ipc:
17+
async with testthing.VirtualMachine(image=image, ipc=ipc, verbose=True) as vm:
18+
yield vm
19+
20+
21+
async def test_basic(machine: testthing.VirtualMachine) -> None:
22+
m = machine
23+
24+
# root filesystem is read-only
25+
with pytest.raises(testthing.SubprocessError):
26+
await m.execute("touch /a")
27+
28+
# the content of /sysroot is what we expect
29+
expected = set[str](("composefs", "state"))
30+
if os.getenv("FS_FORMAT", "") in ("ext4", ""):
31+
expected.add("lost+found")
32+
33+
output = await m.execute("ls /sysroot")
34+
assert set(output.splitlines()) == expected
35+
36+
# make sure /etc and /var persist across a reboot
37+
await m.write("/etc/persists.conf", "hihi conf")
38+
await m.write("/var/persists.db", "hihi db")
39+
await m.reboot()
40+
assert await m.execute("cat /etc/persists.conf") == "hihi conf"
41+
await m.execute("rm /etc/persists.conf")
42+
assert await m.execute("cat /var/persists.db") == "hihi db"
43+
await m.execute("rm /var/persists.db")

0 commit comments

Comments
 (0)