8f356346eb
Implements the six review comments on PR #1: - Per-host PXE-enable gate: read NetBox pxe_enabled custom field; a known host with it false gets the safe local-boot script (Cobbler netboot_enabled). Add a token-guarded POST /provisioned/{ident} callback that clears pxe_enabled in NetBox, plus a %post snippet in the default kickstarts that calls it. - Templates from a git repo: bootapi clones a templates repo and re-pulls every BOOTAPI_TEMPLATE_GIT_INTERVAL (default 3m), atomically swapping the template set (last-good kept on parse failure; embedded defaults are the startup fallback). Metrics for syncs/failures/generation. - Distro catalog (catalog/*.yaml): NetBox host -> boot images/kickstart, so adding an OS is a YAML + template change. Ships almalinux + fedora entries (artifactapi remotes); debian/talos path documented. - Boot images from the artifactapi almalinux/fedora remotes via the catalog. - Bind resolvers, puppet server/CA and PUPPETCA_URL env file now target the k8s services (198.18.200.7; puppet(ca).k8s.syd1.au.unkin.net). - Boot path served over plain HTTP (installers lack CA trust) with an optional parallel HTTPS listener; docs say do not 301 the boot endpoints. New packages: internal/catalog, internal/gitsync. NetBox client gains a pxe_enabled write (token needs that scope - noted in docs). `bootapi validate` subcommand validates a template/catalog set for the templates-repo CI. go build/vet clean, go test -race green, golangci-lint v2 clean, pre-commit clean. Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
96 lines
4.3 KiB
Markdown
96 lines
4.3 KiB
Markdown
# bootapi
|
|
|
|
`bootapi` is a small Go service that replaces Cobbler's PXE/kickstart side. It
|
|
renders kickstart files and iPXE boot scripts from **NetBox** device data and
|
|
serves them over HTTP to PXE-booting hosts.
|
|
|
|
The ENC half of Cobbler already moved to [encapi](https://git.unkin.net/unkin/encapi).
|
|
With bootapi, provisioning a new host is:
|
|
|
|
1. `terraform` the host into **NetBox** (device, interfaces/MACs, IP, platform,
|
|
role) and **encapi** (classification), then
|
|
2. rack it and let it **PXE-boot** — DHCP points it at bootapi, which serves the
|
|
iPXE script and the rendered kickstart; the kickstart hands off to the
|
|
existing Puppet firstrun bootstrap.
|
|
|
|
## How it works
|
|
|
|
```
|
|
DHCP next-server ─▶ iPXE ─▶ GET /ipxe/<mac> ─▶ boot kernel+initrd, inst.ks=<bootapi>/ks/<host>
|
|
└▶ GET /ks/<host> ─▶ rendered kickstart ─▶ puppet firstrun
|
|
```
|
|
|
|
bootapi identifies the booting host by the **MAC** it booted from (NetBox
|
|
interface lookup → device → primary IP, platform, role, interfaces), renders a
|
|
Go `text/template` selected from the host's platform/role/custom-field, and
|
|
serves it. Templates are embedded defaults, overridable from a directory
|
|
(ConfigMap in k8s).
|
|
|
|
## Endpoints (summary)
|
|
|
|
| Path | Purpose |
|
|
|------|---------|
|
|
| `GET /ipxe/{mac}` · `GET /boot/ipxe?mac=` | iPXE boot script |
|
|
| `GET /ks/{ident}` | rendered kickstart (MAC or hostname) |
|
|
| `POST /provisioned/{ident}` | end-of-kickstart callback (token) → clears `pxe_enabled` in NetBox |
|
|
| `GET /healthz` · `/readyz` · `/metrics` | health + Prometheus |
|
|
|
|
The boot path is served over **plain HTTP** (PXE installers have no internal-CA
|
|
trust); HTTPS is offered in parallel. Unknown MAC → iPXE gets a **safe fallback**
|
|
(local-disk boot, HTTP 200), never a 404; a host with `pxe_enabled=false` gets the
|
|
same fallback so it won't re-install. Unknown kickstart host → **404**. Full
|
|
rationale in [docs/endpoints.md](docs/endpoints.md).
|
|
|
|
## Multi-distro + live templates
|
|
|
|
- **Distro catalog** (`catalog/*.yaml`): each OS maps a NetBox platform/family to
|
|
its boot images (artifactapi remotes), kernel args and kickstart template.
|
|
Adding Fedora/Debian/Talos is a YAML + template change, no code change. Ships
|
|
`almalinux9` + `fedora`.
|
|
- **Template git-sync**: bootapi pulls the `bootapi-templates` repo every 3m
|
|
(like argocd) and hot-swaps the template set (last-good kept on a bad push);
|
|
embedded defaults are the startup fallback.
|
|
|
|
## Documentation
|
|
|
|
- [docs/endpoints.md](docs/endpoints.md) — the PXE flow, every endpoint, error/fallback behavior, metrics.
|
|
- [docs/data-model.md](docs/data-model.md) — the exact template data model + NetBox custom fields + template selection.
|
|
- [docs/template-authoring.md](docs/template-authoring.md) — writing/overriding kickstart & iPXE templates.
|
|
- [docs/deployment.md](docs/deployment.md) — Kubernetes/argocd wiring, Vault secrets, and the DHCP cutover.
|
|
- [docs/security.md](docs/security.md) — what belongs in NetBox vs Vault; secrets in kickstarts.
|
|
|
|
## Configuration
|
|
|
|
Env-based (12-factor), see [`config.example.env`](config.example.env). Key vars:
|
|
`BOOTAPI_NETBOX_URL`, `BOOTAPI_NETBOX_TOKEN[_FILE]`, `BOOTAPI_BASE_URL`,
|
|
`BOOTAPI_BOOT_BASE_URL`, `BOOTAPI_ROOT_PASSWORD_HASH[_FILE]`,
|
|
`BOOTAPI_UNKNOWN_MAC_FALLBACK`.
|
|
|
|
## Development
|
|
|
|
```bash
|
|
make build # build ./bin/bootapi
|
|
make test-race # go test -race ./...
|
|
make lint # golangci-lint (v2) if installed, else go vet
|
|
make run # build + run
|
|
```
|
|
|
|
CI (Woodpecker): `pre-commit`, `golangci-lint v2` + `go test -race`, and a
|
|
docker build on PRs; on a `v*` tag, a container image push and a Gitea binary
|
|
release. Cut a release with `make patch|minor|major` (tags + pushes).
|
|
|
|
## Layout
|
|
|
|
```
|
|
cmd/bootapi/ main
|
|
internal/config/ env config
|
|
internal/model/ Host/Interface data model (incl. pxe_enabled gate)
|
|
internal/netbox/ NetBox client (reads + pxe_enabled write) + TTL cache, behind an interface
|
|
internal/catalog/ distro catalog: NetBox host -> boot images/kickstart
|
|
internal/render/ text/template engine (swappable Set), selection, loader
|
|
internal/gitsync/ periodic git pull + atomic template reload (last-good)
|
|
internal/server/ chi HTTP handlers + Prometheus metrics
|
|
templates/ embedded defaults: kickstart, iPXE, catalog/*.yaml
|
|
docs/ see above
|
|
```
|