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>
84 lines
3.0 KiB
Bash
Executable File
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."
|