Skip to content

probe: which display does a runner without a GPU accept? #3

probe: which display does a runner without a GPU accept?

probe: which display does a runner without a GPU accept? #3

Workflow file for this run

name: kvm-probe
# Throwaway. Answers one question: can scripts/smoke.sh --boot and --install
# run on a hosted runner? Delete this file and its branch once it has answered.
on:
push:
branches:
- ci-kvm-probe
jobs:
probe:
runs-on: ubuntu-latest
steps:
- name: resources
run: |
echo "nproc: $(nproc)"
free -h
df -h / /mnt 2>/dev/null || df -h /
echo "kernel: $(uname -r)"
- name: kvm device
run: |
ls -l /dev/kvm || echo "NO /dev/kvm"
id
test -r /dev/kvm && echo "readable" || echo "NOT readable"
test -w /dev/kvm && echo "writable" || echo "NOT writable"
grep -o -m1 -E 'vmx|svm' /proc/cpuinfo || echo "no vmx/svm flag"
- name: install qemu and friends
run: |
start=$SECONDS
sudo apt-get update -qq
sudo apt-get install -y -qq qemu-system-x86 cryptsetup-bin \
mesa-utils libegl1 libegl-mesa0 libgl1-mesa-dri >/dev/null
echo "apt took $((SECONDS - start))s"
qemu-system-x86_64 --version | head -1
cryptsetup --version
# The device is present and the CPU exposes svm; the runner user is
# simply not in the kvm group. This is the whole fix.
- name: grant access to /dev/kvm
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
| sudo tee /etc/udev/rules.d/99-kvm.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
ls -l /dev/kvm
test -w /dev/kvm && echo "PROBE: /dev/kvm now writable" \
|| echo "PROBE: /dev/kvm STILL not writable"
- name: qemu says kvm is enabled
run: |
printf 'info kvm\nquit\n' | timeout 60 qemu-system-x86_64 \
-accel kvm -display none -m 128 -S -monitor stdio 2>&1 | tee out
grep -q 'kvm support: enabled' out \
&& echo "PROBE: kvm ENABLED" || echo "PROBE: kvm UNAVAILABLE"
- name: cpu host under kvm
run: |
printf 'quit\n' | timeout 60 qemu-system-x86_64 \
-accel kvm -cpu host -display none -m 128 -S -monitor stdio 2>&1 \
| tee out
grep -qi 'error\|could not' out \
&& echo "PROBE: -cpu host FAILED" || echo "PROBE: -cpu host ok"
- name: kvm actually executes guest code
run: |
set +e
k=$(ls /boot/vmlinuz-* 2>/dev/null | head -1)
echo "kernel image: ${k:-none found}"
if [ -z "$k" ]; then echo "PROBE: no kernel on runner, skipped"; exit 0; fi
# Runner kernels are commonly mode 600, so read it as root.
sudo cp "$k" /tmp/vmlinuz && sudo chmod a+r /tmp/vmlinuz
timeout 90 qemu-system-x86_64 -accel kvm -cpu host -smp 2 -m 1024 \
-display none -serial stdio -no-reboot \
-kernel /tmp/vmlinuz -append "console=ttyS0 panic=-1" > out 2>&1
head -25 out
grep -q 'Linux version' out \
&& echo "PROBE: guest kernel BOOTED under kvm" \
|| echo "PROBE: guest did not boot"
- name: the display smoke.sh actually asks for
run: |
set +e
LIBGL_ALWAYS_SOFTWARE=1 timeout 45 qemu-system-x86_64 \
-enable-kvm -cpu host -smp 2 -m 1024 \
-device virtio-vga-gl -display egl-headless \
-S -monitor stdio <<< 'quit' > out 2>&1
rc=$?
cat out
# Exit status, not a grep for scary words: qemu prints its banner
# and the monitor prompt on success, and either would false-match.
[ $rc -eq 0 ] && echo "PROBE: virtio-vga-gl + egl-headless ok" \
|| echo "PROBE: virtio-vga-gl + egl-headless FAILED rc=$rc"
# egl-headless wants a DRM render node and a hosted runner has no GPU.
# smoke.sh already takes the display as $QEMU_DISPLAY, so the question
# is which alternative gives the guest a DRM device to run a
# compositor on. Software rendering in the guest is fine; what is not
# fine is a guest with no GPU device at all.
- name: display modes without a host GPU
run: |
set +e
ls -l /dev/dri 2>/dev/null || echo "no /dev/dri on the host"
sudo modprobe vgem 2>/dev/null && ls -l /dev/dri 2>/dev/null
for combo in "-device virtio-vga -display none" \
"-device virtio-gpu-pci -display none" \
"-vga std -display none" \
"-device virtio-vga-gl -display egl-headless"; do
timeout 30 qemu-system-x86_64 -enable-kvm -cpu host -m 512 \
$combo -S -monitor stdio <<< 'quit' > out 2>&1
rc=$?
[ $rc -eq 0 ] && echo "PROBE: ok $combo" \
|| echo "PROBE: FAILED $combo ($(head -1 out))"
done
- name: loop devices and partition scanning
run: |
set +e
truncate -s 2G /tmp/probe.raw
loop=$(sudo losetup -fP --show /tmp/probe.raw)
echo "loop: $loop"
sudo sgdisk -n 1:0:+100M -n 2:0:0 "$loop" >/dev/null 2>&1 \
|| sudo parted -s "$loop" mklabel gpt mkpart p1 1MiB 100MiB mkpart p2 100MiB 100%
sudo partprobe "$loop" 2>/dev/null
sleep 1
ls -l "${loop}p1" "${loop}p2" \
&& echo "PROBE: losetup -fP exposes partitions" \
|| echo "PROBE: partition nodes MISSING"
printf 'probe-passphrase' | sudo cryptsetup luksFormat --batch-mode \
--key-file - "${loop}p2" \
&& echo "PROBE: cryptsetup luksFormat ok" \
|| echo "PROBE: cryptsetup FAILED"
sudo losetup -d "$loop"
- name: privileged podman
run: |
set +e
podman --version
sudo podman version --format '{{.Server.Version}}'
sudo podman run --rm --privileged quay.io/fedora/fedora:44 \
sh -c 'echo PROBE: privileged podman ok' 2>&1 | tail -3