Files
llmgw/deploy/bootstrap/provision-node.sh
T
Ilker ManapandClaude Opus 5 c1ac2f022f Onboard a node with a script, and find two examples that never worked
New nodes had been joined by hand, four times, by me. There was no procedure,
so there was nothing to be wrong — and nothing to be right either. Two scripts
now: provision-node.sh makes the VM on Proxmox, onboard-node.sh gives it an
identity. They are separate because they are run by different people with
different access, and the second must run where the certificate authority is,
which is the one part that cannot be delegated.

Running them turned up why phase 4 was never verified. FabricAttachment
carried no koanf tags, so the `name:` key the shipped example documents bound
to nothing and `rate_gbps` was never read at all. An agent configured exactly
as instructed refused to start with "fabrics[0]: name is required" — naming
the key the operator had just written. Every fabric in this project had been
configured in a Go test, where the tags do not matter.

The server example did not load either: its models had no source, so it failed
validation the moment anything tried to parse it.

Both examples are now parsed by a test. A published example that has never
been loaded is a guess, and these two had been guesses since they were
written.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 12:28:36 +02:00

84 lines
3.0 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Create a VM on Proxmox for a new llmgw node.
#
# Run on the Proxmox host. It does the half of onboarding that is about
# hardware; onboard-node.sh does the half that is about identity, and the two
# are separate because they are done by different people with different access.
#
# Idempotent only in the sense that it refuses to touch an existing VMID. A node
# that already exists is not something a provisioning script should have an
# opinion about.
set -euo pipefail
usage() {
cat >&2 <<USAGE
usage: $0 --vmid N --name NAME --ip ADDR [options]
--vmid N Proxmox VM id; must be free
--name NAME VM name; use the node id, so the machine, the hostname and
the certificate common name are the same string
--ip ADDR address with prefix, e.g. 10.0.0.144/24
--gw ADDR gateway (default 10.0.0.1)
--cores N (default 4)
--memory MB (default 8192)
--disk GB (default 20)
--bridge NAME (default vmbr0)
--storage NAME (default local-lvm)
--image PATH cloud image (default Ubuntu 24.04 in the ISO store)
--user NAME cloud-init user (default ilker)
--sshkeys PATH authorized_keys to install (default /root/.ssh/authorized_keys)
USAGE
exit 2
}
VMID= NAME= IP= GW=10.0.0.1 CORES=4 MEMORY=8192 DISK=20
BRIDGE=vmbr0 STORAGE=local-lvm USER=ilker
IMAGE=/var/lib/vz/template/iso/noble-server-cloudimg-amd64.img
SSHKEYS=/root/.ssh/authorized_keys
while [ $# -gt 0 ]; do
case "$1" in
--vmid) VMID="$2"; shift 2;;
--name) NAME="$2"; shift 2;;
--ip) IP="$2"; shift 2;;
--gw) GW="$2"; shift 2;;
--cores) CORES="$2"; shift 2;;
--memory) MEMORY="$2"; shift 2;;
--disk) DISK="$2"; shift 2;;
--bridge) BRIDGE="$2"; shift 2;;
--storage) STORAGE="$2"; shift 2;;
--image) IMAGE="$2"; shift 2;;
--user) USER="$2"; shift 2;;
--sshkeys) SSHKEYS="$2"; shift 2;;
*) usage;;
esac
done
[ -n "$VMID" ] && [ -n "$NAME" ] && [ -n "$IP" ] || usage
if qm status "$VMID" >/dev/null 2>&1; then
echo "VM $VMID already exists. Pick a free id; this script will not adopt one." >&2
exit 1
fi
[ -f "$IMAGE" ] || { echo "no cloud image at $IMAGE" >&2; exit 1; }
echo "creating $NAME as VM $VMID at $IP"
qm create "$VMID" \
--name "$NAME" --cores "$CORES" --memory "$MEMORY" \
--net0 "virtio,bridge=$BRIDGE" --ostype l26 --agent enabled=1
# Imported rather than installed: a cloud image plus cloud-init is the whole
# reason a node takes a minute to build instead of an afternoon.
qm importdisk "$VMID" "$IMAGE" "$STORAGE" >/dev/null
qm set "$VMID" --scsihw virtio-scsi-pci --scsi0 "$STORAGE:vm-$VMID-disk-0,discard=on,ssd=1" >/dev/null
qm disk resize "$VMID" scsi0 "${DISK}G" >/dev/null
qm set "$VMID" --ide2 "$STORAGE:cloudinit" --boot order=scsi0 >/dev/null
qm set "$VMID" \
--ipconfig0 "ip=$IP,gw=$GW" \
--nameserver "$GW 8.8.8.8" \
--ciuser "$USER" \
--sshkeys "$SSHKEYS" >/dev/null
qm start "$VMID"
echo "started. cloud-init takes a minute; then run onboard-node.sh from the CA host."