Skip to content

Commit d3c3820

Browse files
committed
smoke: one Xvfb per run, and the EGL libs a runner lacks
The worst CI run in the repo's history was one push with two host-side wiring bugs and a latent third, all mine, none of them guest code: - install, iso, dead-disk and boot all died at qemu's first line: 'Couldn't open libEGL.so.1' — the runner image never had EGL libs because no job before this one asked qemu for a GL display. The kvm action now installs libegl1 and libgl1 beside xvfb. - xvfb-run ran qemu as a child, not exec, so the smoke's $! named the wrapper shell and every kill below would have orphaned the VM — port still bound, cleanup traps blind. Fixed by starting one Xvfb for the whole run and exporting DISPLAY: qemu is the direct child again, and the kill contract is what it was before. - the shellcheck findings (unquoted $QEMU_XVFB, three sites) dissolve with the wrapper they named. Verified locally before push: shellcheck v0.11.0 clean (the pinned version), actionlint clean at the digest the workflow pins, and the underlying combination — Xvfb :77, DISPLAY, gtk,gl=on, virtio-gpu-gl — is the one measured end to end on Oct 05, greeter alive indefinitely.
1 parent 3b3bbb9 commit d3c3820

2 files changed

Lines changed: 40 additions & 18 deletions

File tree

‎.github/actions/kvm/action.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ runs:
1616
run: |
1717
sudo apt-get update -qq
1818
sudo apt-get install -y -qq qemu-system-x86 cryptsetup-bin ovmf xvfb \
19+
libegl1 libgl1 \
1920
${{ inputs.sshpass == 'true' && 'sshpass' || '' }}
2021
2122
# /dev/kvm is present on a hosted runner and the CPU exposes svm;

‎scripts/smoke.sh‎

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
# has no disk to inspect and its account has no password for ssh to use.
7676
#
7777
# Env: KUMA (default target/debug/kuma), QEMU_DISPLAY (default gtk,gl=on),
78-
# QEMU_VGA (default virtio-gpu-gl), QEMU_XVFB (default "xvfb-run -a").
78+
# QEMU_VGA (default virtio-gpu-gl), QEMU_XVFB_NUM (default 77).
7979
set -euo pipefail
8080

8181
cd "$(dirname "$0")/.."
@@ -91,22 +91,39 @@ KUMA=${KUMA:-target/debug/kuma}
9191
# llvmpipe alone: LIBGL_ALWAYS_SOFTWARE keeps host GL out of a real GPU,
9292
# where a bad guest submission could take the host session down.
9393
#
94-
# The display backend is Xvfb, not egl-headless: both give qemu a GL
95-
# context, but egl-headless builds its context through a host DRM render
96-
# node ("egl: no drm render node available" measured on a runner and on a
97-
# DRM-less local mount namespace), and a CI runner has no GPU. Xvfb serves
98-
# GLX on llvmpipe with no DRM node at all.
94+
# The display backend is gtk,gl=on against one Xvfb this script starts
95+
# itself, not egl-headless: egl-headless builds its GL context through a
96+
# host DRM render node ("egl: no drm render node available" measured on a
97+
# runner and on a DRM-less local mount namespace), and a CI runner has no
98+
# GPU. Xvfb serves GLX on llvmpipe with no DRM node at all.
99+
#
100+
# Xvfb is started once for the whole run, on purpose: the alternative
101+
# (xvfb-run around each qemu) puts a shell between this script and qemu,
102+
# so $! names the wrapper and every `kill $qemu` below orphans the VM —
103+
# the cleanup traps, the greenboot reboot probes and the port reuse all
104+
# assume qemu is the direct child (xvfb-run runs its command as a child,
105+
# not exec; measured against the script's own kill contract).
99106
QEMU_DISPLAY=${QEMU_DISPLAY:-gtk,gl=on}
100107
QEMU_VGA=${QEMU_VGA:-virtio-gpu-gl}
101-
# Every qemu below runs under xvfb-run so the default display backend has
102-
# an X server to draw into. Harmless for a QEMU_DISPLAY override that does
103-
# not want GL; xvfb-run comes with the xorg-x11-server-Xvfb (dnf) or xvfb
104-
# (apt) package.
105-
QEMU_XVFB=${QEMU_XVFB:-xvfb-run -a}
106-
command -v ${QEMU_XVFB%% *} >/dev/null || {
107-
echo "smoke: $QEMU_XVFB is missing (dnf install xorg-x11-server-Xvfb / apt-get install xvfb)" >&2
108-
exit 1
108+
QEMU_XVFB_NUM=${QEMU_XVFB_NUM:-77}
109+
start_xvfb() {
110+
# Only a GL display needs X; a caller's QEMU_DISPLAY override does not.
111+
[[ "$QEMU_DISPLAY" != gtk,gl=on ]] && return 0
112+
command -v Xvfb >/dev/null || {
113+
echo "smoke: Xvfb is missing (dnf install xorg-x11-server-Xvfb / apt-get install xvfb)" >&2
114+
exit 1
115+
}
116+
Xvfb ":$QEMU_XVFB_NUM" -screen 0 1280x800x24 >/dev/null 2>&1 &
117+
xvfb_pid=$!
118+
export DISPLAY=":$QEMU_XVFB_NUM"
119+
# DISPLAY is qemu's only window in; without it gtk aborts before the
120+
# console socket ever opens and the stage reads as a qemu death.
121+
[[ -S /tmp/.X11-unix/X$QEMU_XVFB_NUM ]] || { sleep 2; [[ -S /tmp/.X11-unix/X$QEMU_XVFB_NUM ]] || {
122+
echo "smoke: Xvfb did not come up on :$QEMU_XVFB_NUM" >&2
123+
exit 1
124+
}; }
109125
}
126+
stop_xvfb() { [[ -n "${xvfb_pid:-}" ]] && kill "$xvfb_pid" 2>/dev/null; }
110127
BOOT=0
111128
ISO=0
112129
INSTALL=0
@@ -975,7 +992,7 @@ smoke_published() {
975992
globals=(-global "driver=cfi.pflash01,property=secure,value=on"
976993
-global "ICH9-LPC.disable_s3=1")
977994
fi
978-
$QEMU_XVFB qemu-system-x86_64 \
995+
qemu-system-x86_64 \
979996
-enable-kvm -cpu host -smp 4 -m 8192 \
980997
"${machine[@]}" "${globals[@]}" \
981998
-drive "if=pflash,format=raw,readonly=on,file=$code" \
@@ -2806,7 +2823,7 @@ dead_disk_run() {
28062823
echo " .. Secure Boot firmware, Microsoft's keys enrolled: $sb_code"
28072824
fi || bad "cannot stage the OVMF vars"
28082825

2809-
$QEMU_XVFB qemu-system-x86_64 \
2826+
qemu-system-x86_64 \
28102827
-enable-kvm -cpu host -smp 4 -m 8192 \
28112828
-machine q35 \
28122829
-drive "if=pflash,format=raw,readonly=on,file=$ovmf_code" \
@@ -2997,7 +3014,7 @@ smoke_iso() {
29973014
ovmf_vars=${ovmf##* }
29983015
cp "$ovmf_vars" "$dir/vars.fd"
29993016

3000-
env LIBGL_ALWAYS_SOFTWARE=1 $QEMU_XVFB qemu-system-x86_64 \
3017+
env LIBGL_ALWAYS_SOFTWARE=1 qemu-system-x86_64 \
30013018
-enable-kvm -cpu host -smp 4 -m 8192 \
30023019
-drive "if=pflash,format=raw,readonly=on,file=$ovmf_code" \
30033020
-drive "if=pflash,format=raw,file=$dir/vars.fd" \
@@ -3118,7 +3135,7 @@ smoke_boot() {
31183135
ovmf_vars=${ovmf##* }
31193136
cp "$ovmf_vars" "$dir/OVMF_VARS.fd" || bad "cannot stage the OVMF vars"
31203137

3121-
env LIBGL_ALWAYS_SOFTWARE=1 $QEMU_XVFB qemu-system-x86_64 \
3138+
env LIBGL_ALWAYS_SOFTWARE=1 qemu-system-x86_64 \
31223139
-enable-kvm -cpu host -smp 4 -m 8192 \
31233140
-machine q35 \
31243141
-drive "if=pflash,format=raw,readonly=on,file=$ovmf_code" \
@@ -3387,6 +3404,9 @@ for file in examples/*.toml; do
33873404
port=$((port + 1))
33883405
example_file=$file
33893406

3407+
# One Xvfb for the whole run, before any stage can ask qemu for a GL
3408+
# display; stop_xvfb rides the summary's exit below.
3409+
start_xvfb
33903410
# The boot stage builds from the example plus a [user] block, not from
33913411
# the example as committed.
33923412
#
@@ -3460,6 +3480,7 @@ EOF
34603480
done
34613481

34623482
note "summary"
3483+
stop_xvfb
34633484
[ ${#PASS[@]} -gt 0 ] && printf ' pass: %s\n' "${PASS[*]}"
34643485
show_warnings
34653486
if [ ${#FAIL[@]} -gt 0 ]; then

0 commit comments

Comments
 (0)