Files
bootapi/docs/data-model.md
T
unkinben 274c480b09
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Initial bootapi: NetBox-driven PXE/kickstart boot service
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
2026-07-28 20:57:11 +10:00

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:

  1. provision_template custom field (exact template name)
  2. .Platform slug (e.g. almalinux9)
  3. .OSFamily (e.g. almalinux, or fedora)
  4. BOOTAPI_DEFAULT_TEMPLATE (default almalinux9)