# Provisioning Central control plane for a Proxmox homelab cluster. Handles PXE booting bare metal, unattended Proxmox installation, cluster join, and host lifecycle management. ## What it does 1. Operator registers a host (MAC address + server type) 2. Operator triggers "rebuild with Proxmox" 3. Host PXE boots → dnsmasq responds → iPXE chain-loads the Proxmox installer 4. Installer fetches a per-host answer file (TOML) from Provisioning 5. Proxmox installs unattended → post-install webhook fires 6. Host reboots → first-boot script phones home with IP + hardware ID 7. Provisioning SSHes into the new host → `pvecm add` joins the cluster 8. Host registered in Infrastructure → marked ready Admin dashboard shows real-time progress via SSE. ## Deploy ### Prerequisites - Docker + Docker Compose on the target host - Host must be on the same network as the bare-metal nodes (for PXE/DHCP) - SSH key pair for root access to new Proxmox nodes - Registry access to `gitea.thewrightserver.net` ### Setup ```bash mkdir -p /opt/provisioning/keys cd /opt/provisioning # Log in to the container registry docker login gitea.thewrightserver.net # Pull the compose file curl -sO https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/docker-compose.yml # Pull example configs curl -s https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/deploy/provisioning.example.yaml -o provisioning.yaml curl -s https://gitea.thewrightserver.net/josh/Provisioning/raw/branch/main/deploy/server-types.example.yaml -o server-types.yaml # Copy your SSH key pair cp /path/to/id_ed25519 ./keys/ ``` ### Configure Edit `provisioning.yaml`: - `server.public_url` — LAN-reachable URL (e.g. `http://192.168.1.100:8080`) - `pxe.interface` — NIC name on the host (e.g. `eth0`, `enp2s0`) - `pxe.subnet` — LAN CIDR for proxy-DHCP - `proxmox.existing_node` — IP of any current cluster member - `proxmox.join_fingerprint` — from `pvecm status` on an existing node - `credentials.root_password_hash` — `mkpasswd -m sha-512` - `infrastructure.base_url` — URL of the Infrastructure service - `infrastructure.server_type_map` — maps local type keys to Infrastructure IDs Edit `server-types.yaml` with your actual hardware types. ### Run ```bash docker compose up -d ``` Dashboard at `http://:8080`. ### Update ```bash docker compose pull docker compose up -d ``` ## Development ```bash # Run tests go test ./... # Run locally (PXE disabled) cp deploy/provisioning.example.yaml provisioning.yaml cp deploy/server-types.example.yaml server-types.yaml # Edit provisioning.yaml: set pxe.enabled=false, infrastructure.base_url="" go run ./cmd/provisioning -config provisioning.yaml # Build binary make build # Build Docker image locally make docker ``` ## Architecture ``` cmd/provisioning/ Entry point, wiring, shutdown internal/ config/ YAML config + hot-reloaded server types db/ SQLite (WAL, embedded migrations) model/ Domain types store/ Hand-written SQL (hosts, operations, locks, images) statemachine/ Table-driven host state machine events/ SSE fan-out hub pxe/ dnsmasq supervisor, iPXE scripts, answer files orchestrator/ Lifecycle driver (state transitions, cluster join) infra/ Infrastructure API client api/ HTTP handlers (JSON API + dashboard) httpserver/ chi router assembly web/ Embedded static assets (CSS, JS) ``` ## CI/CD Gitea Actions workflow (`.gitea/workflows/build.yml`): - Runs `go test` and `go vet` on every push to main - Builds Docker image and pushes to `gitea.thewrightserver.net/josh/provisioning:latest`