#!/bin/bash
# ksim-vm run    boot the exam host of this container. Its disk is /env/disk.qcow2, a thin copy of
#                the base disk made on the first start; /course is the task's /opt/course.
# ksim-vm build  make the base disk: boot the Ubuntu cloud image once with guest/provision.sh as
#                its first-boot script, and keep the result.
#
# /base   .state/vm of the simulator: the Ubuntu cloud image and the base disks (read-only for run)
# /env    the host's own directory (.state/envs/<host>): disk and console log
# /keys   the simulator's ssh key pair (read-only)
set -euo pipefail
KVM=(-enable-kvm -cpu host -machine q35 -display none -monitor none -device virtio-rng-pci)

case "${1:-run}" in
run)
  base=/base/${KSIM_BASE:?}
  [ -f /env/disk.qcow2 ] || qemu-img create -q -f qcow2 -F qcow2 -b "$base" /env/disk.qcow2
  # what the machine needs to know about itself, handed over as a second shared directory:
  # its name, and the key the simulator and the desktop log in with (guest/firstboot.sh reads both)
  mkdir -p /run/ksim && echo "${KSIM_HOSTNAME:?}" > /run/ksim/hostname && cp /keys/id_ed25519.pub /run/ksim/authorized_keys
  exec qemu-system-x86_64 "${KVM[@]}" -smp "${KSIM_VM_CPUS:-2}" -m "${KSIM_VM_MB:-2048}" -serial file:/env/console.log \
    -drive file=/env/disk.qcow2,if=virtio,cache=unsafe,discard=unmap \
    -netdev user,id=n0,hostfwd=tcp::22-:22,hostfwd=tcp::6443-:6443 -device virtio-net-pci,netdev=n0 \
    -virtfs local,path=/course,mount_tag=course,security_model=passthrough,id=course \
    -virtfs local,path=/run/ksim,mount_tag=ksim,security_model=none,readonly=on,id=ksim
  ;;
build)
  out=/base/${KSIM_BASE:?}; work=/base/.build.qcow2; log=/base/build.log
  rm -f "$work" /base/.seed.iso "$out.new"; : > "$log"
  qemu-img create -q -f qcow2 -F qcow2 -b /base/noble.img "$work" 20G
  printf 'instance-id: ksim-build\nlocal-hostname: ksim-build\n' > /tmp/meta-data
  cloud-localds /base/.seed.iso /build/provision.sh /tmp/meta-data
  # the guest powers itself off when provision.sh is through; -no-reboot turns that into QEMU exiting
  timeout "${KSIM_BUILD_TIMEOUT:-2400}" qemu-system-x86_64 "${KVM[@]}" -smp 4 -m 4096 -serial "file:$log" -no-reboot \
    -drive file="$work",if=virtio,cache=unsafe -drive file=/base/.seed.iso,if=virtio,format=raw \
    -netdev user,id=n0 -device virtio-net-pci,netdev=n0 \
    -virtfs local,path=/build,mount_tag=build,security_model=none,readonly=on,id=build || true
  if ! grep -q KSIM-PROVISION-OK "$log"; then
    echo "provisioning did not finish - the end of the VM's console:" >&2; tail -n 40 "$log" >&2; rm -f "$work" /base/.seed.iso; exit 1
  fi
  qemu-img convert -O qcow2 "$work" "$out.new" && mv "$out.new" "$out"
  rm -f "$work" /base/.seed.iso
  ;;
*) echo "usage: ksim-vm run|build" >&2; exit 2 ;;
esac
