stack/docker/local-emulator/qemu/test-serial.sh
BilalG1 5399142db9
local emulator build improvements (#1330)
… V8 --jitless

2.6 GB to 1.3 GB final image

Flip arm64 matrix back to ubicloud-standard-8 so both arches share one
runner fleet. Cross-arch TCG on an amd64 host previously SIGTRAP'd in
migrations because V8's JIT emitted arm64 instructions that QEMU's
cross-arch translator mis-handled; pair the existing -cpu cortex-a72
fallback with NODE_OPTIONS=--jitless on the migration docker exec to
force V8 to stay on the interpreter. Does not affect amd64 migrations
(KVM, no TCG).

<!--

Make sure you've read the CONTRIBUTING.md guidelines:
https://github.com/stack-auth/stack-auth/blob/dev/CONTRIBUTING.md

-->


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Optimized emulator images with binary stripping, compression, and
preservation of standalone runtime dependencies.
* Improved multi-architecture build matrix, added optional KVM
detection/fallback, and gated certain emulator runtime steps for arm64.
* Enhanced build scripts to generate and include env files and persist
richer logs and artifacts.

* **New Features**
* Centralized provision entrypoint to streamline install → migrations →
slimming sequence.

* **Tests**
  * Added a fast QEMU serial boot test for architecture validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-04-13 19:21:02 -07:00

125 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Quick test: boot the base QEMU image with a minimal cloud-init that writes to
# serial via runcmd. Verifies that our logging approach works without running
# the full emulator build (~10s instead of ~10min).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/common.sh"
detect_host
ARCH="${1:-$HOST_ARCH}"
BASE_IMG="$SCRIPT_DIR/images/debian-13-base-${ARCH}.qcow2"
if [ ! -f "$BASE_IMG" ]; then
echo "Base image not found: $BASE_IMG" >&2
exit 1
fi
TMP_DIR="$(mktemp -d /tmp/stack-serial-test-XXXXXX)"
trap 'kill "$(cat "$TMP_DIR/qemu.pid" 2>/dev/null)" 2>/dev/null; rm -rf "$TMP_DIR"' EXIT
# Create a temporary disk
cp "$BASE_IMG" "$TMP_DIR/disk.qcow2"
# Minimal cloud-init user-data that tests serial output from runcmd
cat > "$TMP_DIR/user-data" << 'EOF'
#cloud-config
write_files:
- path: /usr/local/bin/provision-build
permissions: '0755'
content: |
#!/bin/bash
set -euo pipefail
SERIAL=""
for d in /dev/ttyAMA0 /dev/ttyS0; do
[ -c "$d" ] && SERIAL="$d" && break
done
if [ -n "$SERIAL" ]; then
exec > >(tee -a "$SERIAL") 2>&1
fi
echo "STACK_PROVISION: script started"
sleep 1
echo "STACK_PROVISION: step 2"
for dev in /dev/console /dev/ttyAMA0 /dev/ttyS0; do
echo "STACK_CLOUD_INIT_DONE" > "$dev" 2>/dev/null || true
done
shutdown -P now
runcmd:
- [bash, /usr/local/bin/provision-build]
EOF
cat > "$TMP_DIR/meta-data" << 'EOF'
instance-id: serial-test
local-hostname: serial-test
EOF
# Build seed ISO
make_iso_from_dir "$TMP_DIR/seed.iso" "cidata" "$TMP_DIR"
: > "$TMP_DIR/serial.log"
case "$ARCH" in
arm64)
accel="hvf"
firmware="$(find_aarch64_firmware)"
qemu_base="qemu-system-aarch64 -machine virt -accel $accel -cpu max -bios $firmware"
;;
amd64)
qemu_base="qemu-system-x86_64 -machine q35 -accel hvf -cpu max"
;;
esac
$qemu_base \
-boot order=c \
-m 1024 \
-smp 2 \
-drive "file=$TMP_DIR/disk.qcow2,format=qcow2,if=virtio" \
-drive "file=$TMP_DIR/seed.iso,format=raw,if=virtio,readonly=on" \
-netdev user,id=net0 \
-device virtio-net-pci,netdev=net0 \
-serial "file:$TMP_DIR/serial.log" \
-display none \
-daemonize \
-pidfile "$TMP_DIR/qemu.pid"
echo "QEMU started, waiting for serial output..."
echo "Serial log: $TMP_DIR/serial.log"
elapsed=0
timeout=120
while [ "$elapsed" -lt "$timeout" ]; do
if grep -q "STACK_CLOUD_INIT_DONE" "$TMP_DIR/serial.log" 2>/dev/null; then
echo ""
echo "=== SUCCESS: STACK_CLOUD_INIT_DONE received ==="
echo ""
echo "=== All STACK_PROVISION lines ==="
grep "STACK_PROVISION" "$TMP_DIR/serial.log" || echo "(none found)"
exit 0
fi
# Show any STACK_PROVISION lines as they appear
if grep -q "STACK_PROVISION" "$TMP_DIR/serial.log" 2>/dev/null; then
grep "STACK_PROVISION" "$TMP_DIR/serial.log" | while IFS= read -r line; do
echo " [${elapsed}s] $line"
done
fi
sleep 2
elapsed=$((elapsed + 2))
printf "\r [%ds / %ds] waiting..." "$elapsed" "$timeout"
done
echo ""
echo "=== TIMEOUT: no STACK_CLOUD_INIT_DONE after ${timeout}s ==="
echo ""
echo "=== Last 30 lines of serial log ==="
tail -30 "$TMP_DIR/serial.log"
echo ""
echo "=== STACK_PROVISION lines ==="
grep "STACK_PROVISION" "$TMP_DIR/serial.log" || echo "(none found)"
exit 1