# bootapi HTTP endpoints bootapi speaks plain HTTP. It is fronted by the same Vault-issued TLS the Cobbler server used; the booting firmware reaches it at the DHCP `next-server` (see [deployment.md](deployment.md)). ## The PXE flow ``` DHCP ── next-server + filename (ipxe.efi / undionly.kpxe) ──▶ firmware loads iPXE iPXE ── GET /ipxe/ ───────────────────────────────────▶ bootapi renders a boot script boot ── kernel + initrd + inst.ks=/ks/ ────▶ Anaconda fetches the kickstart KS ── GET /ks/ ────────────────────────────────────▶ bootapi renders the kickstart ``` This mirrors Cobbler, which chained iPXE to `/cblr/svc/op/gpxe/mac/` and served a per-system script carrying `inst.ks=`. ## Endpoints | Method | Path | Purpose | |--------|------|---------| | GET | `/ipxe/{mac}` | iPXE boot script for the host owning `{mac}`. `{mac}` may use `:`/`-`/`.` separators or be bare hex; a trailing `.ipxe` is stripped. | | GET | `/boot/ipxe?mac=...` | Query-string alias of `/ipxe/{mac}` (some firmware finds this shape easier to template). | | GET | `/ks/{ident}` | Rendered kickstart. `{ident}` is a MAC (auto-detected) or a hostname; trailing `.ks`/`.cfg` is stripped. | | GET | `/healthz` | Liveness: always `200 ok`. | | GET | `/readyz` | Readiness: `200` once templates parsed. Does **not** probe NetBox (a NetBox outage still lets iPXE serve the safe fallback). | | GET | `/metrics` | Prometheus metrics (see below). | ## Host identification A booting host is identified by the **MAC** of the NIC it PXE-booted from (`/ipxe/{mac}`), which bootapi resolves via NetBox `GET /api/dcim/interfaces/?mac_address=` → device → primary IP, platform, role, interfaces. `/ks/{ident}` additionally accepts a **hostname** (NetBox device name), for hand-testing and for installers that template the hostname into the kickstart URL. ## Error behavior (important, and deliberate) The two endpoints fail **differently** on an unknown host, because the cost of a wrong answer differs: - **`/ipxe/{mac}` never returns 404.** iPXE needs a syntactically valid script or the boot chain simply errors. An unknown MAC — or *any* NetBox error — returns HTTP 200 with the **fallback script** selected by `BOOTAPI_UNKNOWN_MAC_FALLBACK`: - `local` (default): `sanboot` the local disk. Safe: a machine that PXE-booted by accident (or a NetBox blip) just boots its installed OS; a genuinely new machine loops back to PXE next time, by which point NetBox should know it. We deliberately do **not** start an installer for a machine we can't identify — that could wipe a production box. - `shell`: drop to an interactive iPXE shell so an operator racking a new box can read `${net0/mac}` and register it. Opt-in; unsafe as a default because it halts the boot. - **`/ks/{ident}` returns 404** for an unknown host (and 502 on a NetBox error). By the time Anaconda fetches the kickstart it has already committed to installing; a clear failure is safer than serving an empty or wrong kickstart. ## Metrics All on `/metrics`, prefix `bootapi_`: - `bootapi_http_requests_total{endpoint,status}` — endpoint = `ipxe|ks|healthz|readyz`, status = `2xx|3xx|4xx|5xx`. - `bootapi_render_total{kind,result}` — kind = `kickstart|ipxe`, result = `ok|error`. - `bootapi_netbox_lookups_total{field,result}` — field = `mac|name`, result = `ok|notfound|error`. - `bootapi_netbox_lookup_duration_seconds{field}` — histogram. - `bootapi_netbox_cache_hits_total` / `bootapi_netbox_cache_misses_total`. - standard Go/process collectors.