#!/bin/sh
set -eu

instance_id=${1:?instance ID is required}
nonce=${2:?registration nonce is required}

case "$instance_id" in
    ????????-????-????-????-????????????) ;;
    *) echo "invalid instance ID" >&2; exit 64 ;;
esac
case "$nonce" in
    *[!A-Za-z0-9_-]*|'') echo "invalid nonce" >&2; exit 64 ;;
esac

state_root=${RUNNER_STATE_ROOT:-/var/lib/microvm-runner}
base_image=${RUNNER_BASE_IMAGE:-$state_root/images/runner-base.qcow2}
firmware=${RUNNER_FIRMWARE:-$state_root/firmware/CLOUDHV.fd}
bridge=${RUNNER_BRIDGE:-mvrbr0}
cloud_hypervisor=${CLOUD_HYPERVISOR:-/usr/local/bin/cloud-hypervisor}
vm_timeout=${RUNNER_VM_TIMEOUT:-3h}
cpus=${RUNNER_VM_CPUS:-4}
memory=${RUNNER_VM_MEMORY:-3G}
gitea_instance=${GITEA_INSTANCE:-https://git.ddupan.top}
runner_labels=${RUNNER_LABELS:-self-hosted:host,vm:host}
token_url=${RUNNER_TOKEN_URL:-http://172.30.0.1:8787}

vm_dir="$state_root/instances/$instance_id"
tap="mvr${instance_id%%-*}"
overlay="$vm_dir/root.qcow2"
seed="$vm_dir/seed.img"
serial="$vm_dir/serial.log"

cleanup() {
    ip link delete "$tap" 2>/dev/null || true
    rm -rf -- "$vm_dir"
}
trap cleanup EXIT INT TERM

test -r "$base_image"
test -r "$firmware"
install -d -m 0700 "$state_root/instances" "$vm_dir"
# Cloud Hypervisor cannot open qcow2 backing chains.  Keep each disposable
# root disk flat; reflink-capable storage still makes this copy cheap.
cp --reflink=auto --sparse=always "$base_image" "$overlay"

cat >"$vm_dir/meta-data" <<EOF
instance-id: $instance_id
local-hostname: gitea-runner-${instance_id%%-*}
EOF
cat >"$vm_dir/user-data" <<EOF
#cloud-config
runcmd:
  - [ sh, -c, "curl --fail --silent --show-error --retry 10 --retry-all-errors $token_url/assets/guest-assets.tar.gz | tar -xz -C /" ]
  - [ /usr/local/libexec/gitea-microvm-guest-runner, "$token_url/token/$nonce", "$gitea_instance", "gitea-vm-${instance_id%%-*}", "$runner_labels" ]
EOF
cloud-localds "$seed" "$vm_dir/user-data" "$vm_dir/meta-data"

digest=$(printf '%s' "$instance_id" | sha256sum | cut -c1-10)
mac=$(printf '02:%s:%s:%s:%s:%s' \
    "$(printf '%s' "$digest" | cut -c1-2)" \
    "$(printf '%s' "$digest" | cut -c3-4)" \
    "$(printf '%s' "$digest" | cut -c5-6)" \
    "$(printf '%s' "$digest" | cut -c7-8)" \
    "$(printf '%s' "$digest" | cut -c9-10)")
ip tuntap add dev "$tap" mode tap
ip link set "$tap" master "$bridge"
ip link set "$tap" up

timeout --signal=TERM --kill-after=30s "$vm_timeout" "$cloud_hypervisor" \
    --firmware "$firmware" \
    --cpus "boot=$cpus" \
    --memory "size=$memory" \
    --disk "path=$overlay,image_type=qcow2" \
    --disk "path=$seed,readonly=on,image_type=raw" \
    --net "tap=$tap,mac=$mac" \
    --serial "file=$serial" \
    --console off
