Skip to content

Commit 87de9f0

Browse files
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 4622243 commit 87de9f0

File tree

17 files changed

+1180
-90
lines changed

17 files changed

+1180
-90
lines changed

.github/workflows/examples.yml

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

3838
- name: Setup /dev/kvm
3939
run: |
40+
set -eux
4041
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm.rules
42+
echo 'KERNEL=="vhost-vsock", GROUP="kvm", MODE="0666", OPTIONS+="static_node=vhost-vsock"' | sudo tee /etc/udev/rules.d/99-vhost-vsock.rules
4143
sudo udevadm control --reload-rules
42-
sudo udevadm trigger --name-match=kvm --settle
43-
ls -l /dev/kvm
44+
sudo udevadm trigger --settle
45+
ls -l /dev/kvm /dev/vhost-vsock
4446
4547
- name: Install dependencies
4648
run: |
@@ -51,10 +53,8 @@ jobs:
5153
erofs-utils \
5254
fsverity \
5355
mtools \
54-
libvirt-daemon \
55-
libvirt-daemon-driver-qemu \
56-
python3-libvirt \
57-
qemu-system \
56+
python3-pytest-asyncio \
57+
qemu-kvm \
5858
systemd-boot-efi
5959
6060
- name: Get a newer podman for heredoc support (from plucky)
@@ -80,6 +80,9 @@ jobs:
8080
examples/common/install-patched-tools ~/bin
8181
fi
8282
83+
- name: Install systemd-ssh-proxy polyfill
84+
run: sudo cp examples/bls/test-thing.workarounds/systemd-ssh-proxy /usr/lib/systemd
85+
8386
- name: Run example tests
8487
run: |
8588
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)