274c480b09
bootapi replaces Cobbler's PXE/kickstart side. It resolves a PXE-booting host
from NetBox (by MAC or hostname), renders an iPXE boot script and a kickstart
from Go text/templates, and serves them over HTTP. The ENC half already moved to
encapi; this covers the provisioning/boot half.
What's here:
- cmd/bootapi + internal/{config,model,netbox,render,server}; embedded default
templates under templates/ (AlmaLinux 9 + Fedora kickstarts, iPXE boot +
unknown-MAC fallbacks) ported from Cobbler's boot/bootstrap contract.
- NetBox client (v4.x API) behind a Resolver interface with a short-TTL cache;
tested against httptest fixtures using real NetBox JSON shapes.
- chi HTTP server: /ipxe/{mac}, /boot/ipxe?mac=, /ks/{ident}, healthz/readyz,
Prometheus /metrics. Unknown MAC -> safe fallback iPXE (200), unknown KS -> 404.
- Secrets (root pw hash, ssh keys) injected at render time from env/Vault, never
NetBox. Config is env-based per estate convention.
- Makefile (build/test/lint/docker + patch/minor/major), Dockerfile (distroless),
.woodpecker (pre-commit, golangci-lint v2 + go test -race, docker build on PR;
image push + Gitea binary release on v* tag), docs/ and example config.
go build/vet clean, go test -race green, golangci-lint v2 clean, pre-commit clean.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
3.9 KiB
3.9 KiB
Template data model
Every kickstart and iPXE template is rendered with Go text/template against a
single flat value. This is the exact, stable contract template authors code
against. It is assembled in internal/render.dataFor from a NetBox device
(internal/netbox) plus render-time config (env/Vault).
Kickstart templates (*.ks.tmpl)
| Field | Type | Source | Notes |
|---|---|---|---|
.Hostname |
string | NetBox device name | short name, e.g. web01 |
.Domain |
string | NetBox CF domain, else BOOTAPI_DOMAIN |
|
.FQDN |
string | derived | Hostname.Domain (or Hostname if no domain) |
.Platform |
string | NetBox platform slug | e.g. almalinux9 — primary template-selection key |
.OSFamily |
string | derived from platform | e.g. almalinux |
.OSVersion |
string | derived from platform | e.g. 9 |
.Arch |
string | fixed x86_64 (today) |
|
.Role |
string | NetBox device role slug | e.g. kubernetes-worker |
.Interfaces |
[]Interface |
NetBox interfaces + IPs | primary interface sorted first |
.PrimaryInterface |
*Interface |
derived | the NIC carrying the primary IP (or first) |
.PrimaryIP |
string | NetBox device primary_ip |
address only, no prefix |
.Nameservers |
[]string |
NetBox CF nameservers, else BOOTAPI_NAMESERVERS |
|
.RootPasswordHash |
string | render-time (BOOTAPI_ROOT_PASSWORD_HASH[_FILE]) |
crypt(3) hash; empty ⇒ lock root. Never from NetBox — see security.md |
.SSHAuthorizedKeys |
[]string |
render-time (BOOTAPI_SSH_AUTHORIZED_KEYS) |
|
.PuppetServer |
string | BOOTAPI_PUPPET_SERVER |
default puppet.query.consul |
.PuppetCAServer |
string | BOOTAPI_PUPPET_CA_SERVER |
default puppetca.query.consul |
.BaseURL |
string | BOOTAPI_BASE_URL |
bootapi's own URL |
.BootBaseURL |
string | BOOTAPI_BOOT_BASE_URL |
OS install-tree base |
.KickstartURL |
string | derived | BaseURL/ks/Hostname |
.Custom |
map[string]any |
all NetBox custom fields, verbatim | escape hatch for site-specific knobs without a code change |
Interface
| Field | Type | Notes |
|---|---|---|
.Name |
string | NetBox interface name, e.g. eth0 |
.MAC |
string | normalized lower-case colon form |
.IP |
string | address only (empty ⇒ no IP; skip in the network stanza) |
.PrefixLen |
int | CIDR length, e.g. 24 |
.Netmask |
string | dotted-quad, e.g. 255.255.255.0 |
.Gateway |
string | per-IP CF gateway, else device CF gateway, else empty |
.VLAN |
int | untagged VLAN id, or 0 |
.Primary |
bool | true for the NIC with the primary IP |
iPXE templates (*.ipxe.tmpl)
Rendered with everything above plus:
| Field | Type | Notes |
|---|---|---|
.KernelURL |
string | BootBaseURL/images/pxeboot/vmlinuz (empty if BootBaseURL unset) |
.InitrdURL |
string | BootBaseURL/images/pxeboot/initrd.img |
The fallback templates (fallback-local, fallback-shell) are rendered with an
empty value — they take no host data by design.
NetBox custom fields bootapi reads
Define these on the device (or, where noted, the IP address) in NetBox. All are optional; sensible fallbacks apply.
| Custom field | On | Effect |
|---|---|---|
domain |
device | DNS domain; overrides BOOTAPI_DOMAIN |
gateway |
device / IP address | default gateway (IP-level wins) |
nameservers |
device | comma-separated resolvers; overrides BOOTAPI_NAMESERVERS |
provision_template |
device | force a specific template name (see below) |
Template selection precedence
SelectKickstart picks the first template name that exists, in order:
provision_templatecustom field (exact template name).Platformslug (e.g.almalinux9).OSFamily(e.g.almalinux, orfedora)BOOTAPI_DEFAULT_TEMPLATE(defaultalmalinux9)