diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a99d6e --- /dev/null +++ b/README.md @@ -0,0 +1,120 @@ +# 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.ssh_public_key` — public key injected into new hosts +- `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`