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
5.5 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.k8s.syd1.au.unkin.net |
.PuppetCAServer |
string | BOOTAPI_PUPPET_CA_SERVER |
default puppetca.k8s.syd1.au.unkin.net |
.PuppetCAURL |
string | BOOTAPI_PUPPET_CA_URL |
written to /etc/sysconfig/puppet-initial as PUPPETCA_URL |
.BaseURL |
string | BOOTAPI_BASE_URL |
bootapi's own http URL |
.KickstartURL |
string | derived | BaseURL/ks/Hostname |
.CallbackURL |
string | derived | CallbackBaseURL/provisioned/Hostname |
.ProvisionToken |
string | render-time (BOOTAPI_PROVISION_TOKEN[_FILE]) |
bearer token the %post callback sends; empty ⇒ callback snippet omitted |
.DistroVars |
map[string]string |
selected catalog entry's evaluated vars |
e.g. .DistroVars.mirror (install-tree base); empty when no catalog entry matched |
.BootBaseURL |
string | BOOTAPI_BOOT_BASE_URL |
legacy OS-tree base; empty when catalog-driven |
.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 | from the selected catalog entry's kernel_url (else legacy BootBaseURL/images/pxeboot/vmlinuz) |
.InitrdURL |
string | catalog initrd_url (else legacy path) |
.RepoURL |
string | OS install-tree root (KernelURL minus images/pxeboot/vmlinuz); passed as inst.repo= |
.KernelArgs |
[]string |
catalog entry's extra kernel args |
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 | Type | Effect |
|---|---|---|---|
domain |
device | text | DNS domain; overrides BOOTAPI_DOMAIN |
gateway |
device / IP address | text | default gateway (IP-level wins) |
nameservers |
device | text | comma-separated resolvers; overrides BOOTAPI_NAMESERVERS |
provision_template |
device | text | force a specific catalog entry / template name |
pxe_enabled |
device | boolean | gate network install (Cobbler's netboot_enabled). Unset ⇒ treated as enabled. Set false (or let the callback clear it) to boot local disk instead of re-installing. |
Distro selection and the catalog
Host → distro is resolved through the distro catalog (catalog/*.yaml in the
templates repo / embedded defaults). Each entry names a kickstart template, the
kernel/initrd URL templates (artifactapi remotes) and extra kernel args. See
template-authoring.md.
Selection precedence (both catalog Select and the kickstart-name fallback):
provision_templatecustom field — exact catalog entry / template name..Platformslug (e.g.almalinux9) matched against a catalog entry'smatch.platforms, else a template of that name..OSFamily(e.g.fedora) matched againstmatch.family, else a template of that name.BOOTAPI_DEFAULT_TEMPLATE(defaultalmalinux9).
The version substituted into the catalog URLs is .OSVersion (the numeric
suffix of the platform slug), falling back to the entry's version_default.