run-vm
⎇
Raw
1#!/bin/sh
2# Entrypoint of the build VM container. It packs /in into the job disk, boots
3# the VM, and leaves the image at /out/image.tar.
4#
5# Exit codes: 0 image written, 1 build failed, 2 the VM did not run,
6# 3 image over HF_VM_MAX_IMAGE_BYTES.
7set -eu
8
9cpus=${HF_VM_CPUS:-2}
10mem=${HF_VM_MEMORY_MB:-2048}
11disk=${HF_VM_DISK_BYTES:-21474836480}
12max=${HF_VM_MAX_IMAGE_BYTES:-4294967296}
13
14if [ ! -r /dev/kvm ] || [ ! -w /dev/kvm ]; then
15 echo "hearthforge: /dev/kvm is missing or not writable in the build VM container"
16 exit 2
17fi
18
19tar -c -f /work/job.tar -C /in .
20truncate -s "$disk" /work/scratch.img
21: > /out/image.tar
22
23arch=$(uname -m)
24case $arch in
25x86_64)
26 # acpi=off: QEMU puts a large initramfs over the microvm ACPI tables, and
27 # the kernel hangs while it parses them.
28 machine=microvm,accel=kvm,acpi=off,pit=off,pic=off,isa-serial=on,rtc=on
29 console=ttyS0
30 ;;
31aarch64)
32 machine=virt,accel=kvm,gic-version=host
33 console=ttyAMA0
34 ;;
35*)
36 echo "hearthforge: unsupported architecture $arch"
37 exit 2
38 ;;
39esac
40
41# The serial numbers let the guest find its disks whatever order the
42# virtio-mmio transports probe in.
43qemu-system-"$arch" \
44 -nodefaults -no-user-config -display none -no-reboot \
45 -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
46 -machine "$machine" -cpu host -smp "$cpus" -m "$mem" \
47 -kernel /vm/vmlinuz -initrd /vm/initramfs.gz \
48 -append "console=$console quiet panic=-1 reboot=t" \
49 -serial stdio \
50 -drive if=none,id=job,file=/work/job.tar,format=raw,readonly=on \
51 -device virtio-blk-device,drive=job,serial=hfjob \
52 -drive if=none,id=scratch,file=/work/scratch.img,format=raw,cache=unsafe,discard=unmap \
53 -device virtio-blk-device,drive=scratch,serial=hfscratch \
54 -netdev user,id=net -device virtio-net-device,netdev=net \
55 -device virtio-rng-device \
56 -device virtio-serial-device \
57 -chardev file,id=image,path=/out/image.tar \
58 -device virtserialport,chardev=image,name=hf.image &
59qemu=$!
60
61# The guest controls how much it writes. Polling lets it overshoot by about
62# one second of writes, which the engine's disk absorbs.
63over=0
64while kill -0 "$qemu" 2>/dev/null; do
65 if [ "$(wc -c < /out/image.tar)" -gt "$max" ]; then
66 over=1
67 # QEMU may have exited since the check.
68 kill "$qemu" 2>/dev/null || true
69 break
70 fi
71 sleep 1
72done
73status=0
74wait "$qemu" || status=$?
75
76size=$(wc -c < /out/image.tar)
77if [ "$over" = 1 ] || [ "$size" -gt "$max" ]; then
78 : > /out/image.tar
79 echo "hearthforge: the image is larger than $max bytes"
80 exit 3
81fi
82if [ "$status" != 0 ]; then
83 echo "hearthforge: QEMU exited with status $status"
84 exit 2
85fi
86[ "$size" -gt 0 ] || exit 1
87