Initial bootapi: NetBox-driven PXE/kickstart boot service #1
Reference in New Issue
Block a user
Delete Branch "benvin/bootapi-initial"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Cobbler's ENC role moved to encapi; bootapi replaces the remaining PXE/kickstart side. It resolves a booting host by MAC (or hostname) from NetBox and serves iPXE boot scripts and rendered kickstart files, so adding a host becomes terraform netbox + encapi and the machine self-installs against this 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@@ -4,0 +16,4 @@## How it works```DHCP next-server ─▶ iPXE ─▶ GET /ipxe/<mac> ─▶ boot kernel+initrd, inst.ks=<bootapi>/ks/<host>there should be an option to set if the host should pxeboot or not, something the client unticks at the end of kickstart.
@@ -4,0 +24,4 @@interface lookup → device → primary IP, platform, role, interfaces), renders aGo `text/template` selected from the host's platform/role/custom-field, andserves it. Templates are embedded defaults, overridable from a directory(ConfigMap in k8s).can we use a repo in git? have bootapi pull that repo every x minutes (do 3, like arogcd). the repo should have CI to ensure that the templates match strict requirements.
@@ -0,0 +39,4 @@# --- network defaults (used when NetBox does not record them per-device) ---BOOTAPI_DOMAIN=main.unkin.netBOOTAPI_NAMESERVERS=198.18.19.19this should be the bind resolvers in k8s now
@@ -0,0 +34,4 @@BOOTAPI_BOOT_BASE_URL=http://mirror.k8s.syd1.au.unkin.net/almalinux/9# --- puppet bootstrap targets (baked into kickstart %post) ---BOOTAPI_PUPPET_SERVER=puppet.query.consulpuppet in kubernetes instead
@@ -0,0 +31,4 @@# bootapi's own externally-reachable base URL (goes into the iPXE inst.ks=).BOOTAPI_BASE_URL=http://bootapi.k8s.syd1.au.unkin.net# Base URL of the OS install trees (kernel/initrd + inst.repo).BOOTAPI_BOOT_BASE_URL=http://mirror.k8s.syd1.au.unkin.net/almalinux/9there is already an almalinux remote in artifactapi.
almalinux/${version}/BaseOS/${arch}/os/images/pxeboot/but I also want to be able to boot other os, like fedora. is there a way we can describe distros in netbox? or should this be environment variables? What happens if we want debian or tailos later?
@@ -0,0 +1,68 @@# bootapi HTTP endpointsbootapi speaks plain HTTP. It is fronted by the same Vault-issued TLS the Cobblerit should be accessible via http and https, since pxebooting hosts may not trust the https cert we use.
Done. Added a NetBox
pxe_enabledboolean custom field (Cobbler's netboot_enabled): a known host with it false now gets the safe local-boot script from /ipxe. And 'something the client unticks at the end of kickstart' -> new token-guardedPOST /provisioned/{ident}that clears pxe_enabled in NetBox, called from a %post snippet in the default kickstarts. NetBox token now needs write on that one custom field (flagged in docs/security.md + deployment.md).Done. bootapi now git-syncs a templates repo (
unkin/bootapi-templates, terraform-git PR #50) every BOOTAPI_TEMPLATE_GIT_INTERVAL (default 3m, like argocd), atomically swapping the template set; last-good is kept on a parse failure and embedded defaults are the startup fallback. The templates repo gets CI that validates every template/catalog renders (bootapi validate) + shellcheck on %post.Done. Default nameserver is now the k8s bind-resolvers LB 198.18.200.7 (BOOTAPI_NAMESERVERS).
Done. Puppet now targets the k8s puppetserver: server=puppet.k8s.syd1.au.unkin.net, ca_server=puppetca.k8s.syd1.au.unkin.net, and %post writes /etc/sysconfig/puppet-initial with PUPPETCA_URL (default puppetca.k8s.syd1.au.unkin.net) for the puppet-initial unit instead of hardcoding.
Done. Kernel/initrd now come from the artifactapi almalinux remote: {ArtifactBase}/almalinux/${version}/BaseOS/${arch}/os/images/pxeboot/. On 'describe distros in NetBox or env?': neither hardcoded - implemented a distro catalog (catalog/*.yaml in the templates repo), one file per OS (match, kernel/initrd URL templates -> artifactapi remotes, kickstart ref, kernel args). Host->distro selection stays NetBox-driven (platform slug / family / provision_template). Shipped almalinux9 + fedora (fedora remote exists). Adding debian/talos later = a yaml + template (+ maybe a new artifactapi remote), no bootapi code change; their differing artifact shapes are documented in docs/template-authoring.md and the catalog README. Env vars are now only for bootapi's own endpoints.
Done. The boot path (/ipxe, /boot/ipxe, /ks) is always served over plain HTTP so installers with no internal-CA trust can reach it; iPXE/kickstart URLs are http:// (BOOTAPI_BASE_URL). bootapi also serves HTTPS in parallel when BOOTAPI_TLS_* is set, for clients that trust the CA. The %post provisioned callback also runs over plain HTTP by default (the token authenticates it, before any CA is installed); BOOTAPI_CALLBACK_BASE_URL can point it at https if you install the CA early. docs/deployment.md now says the Gateway/HTTPRoute must NOT 301 HTTP->HTTPS for the boot endpoints.