{{- /* Image-based AlmaLinux 9 kickstart. Anaconda `liveimg` unpacks a prebuilt rootfs tarball (catalog var rootfs_tarball, on the artifactapi rootfs-images local repo) onto the disk instead of resolving+installing packages: it formats the KS-defined filesystems, untars the rootfs, installs grub and regenerates the initramfs. The package set (kernel, grub2, openssh, chrony, puppet-agent, ...) is baked into the tarball by .woodpecker/build-image.yaml. The image is GENERIC (no per-host identity). liveimg overwrites /etc with the tarball, so all per-host config is applied in %post AFTER the unpack: static NetworkManager keyfiles from the SAME NetBox interface data the classic template uses, the hostname, the puppet-initial env, and the provisioned callback. Storage reuses the shared _storage.ks.tmpl partials (storage_mode / vg_grow), so image and package installs land on disk identically (VM autopart, OptiPlex NVMe). Select via a device's provision_template custom field (e.g. almalinux9-image). */ -}} #version=RHEL9 # Rendered by bootapi (image install) for {{ .FQDN }} (platform {{ .Platform }}) text firstboot --disable reboot # --- payload: unpack the prebuilt rootfs tarball --- liveimg --url={{ .DistroVars.rootfs_tarball }} # --- localization --- keyboard --xlayouts='au' lang en_AU.UTF-8 timezone Australia/Sydney --utc # --- security --- {{ if .RootPasswordHash -}} rootpw --iscrypted {{ .RootPasswordHash }} {{- else -}} rootpw --lock {{- end }} selinux --enforcing firewall --enabled --service=ssh # --- install-time networking (primary NIC only, so Anaconda can fetch the # tarball). The installed system's network is written authoritatively in %post # below, because the liveimg unpack overwrites whatever Anaconda configures. --- {{- $primary := .PrimaryInterface }} {{- if and $primary $primary.IP }} network --bootproto=static --device={{ $primary.MAC }} --ip={{ $primary.IP }} --netmask={{ $primary.Netmask }}{{ if $primary.Gateway }} --gateway={{ $primary.Gateway }}{{ end }}{{ range .Nameservers }} --nameserver={{ . }}{{ end }} --hostname={{ $.FQDN }} --activate --onboot=on --noipv6 {{- else }} network --bootproto=dhcp --hostname={{ .FQDN }} --activate {{- end }} # --- storage (model-aware; shared with almalinux9.ks.tmpl via _storage.ks.tmpl) --- {{ template "storage-block" . }} # kdump: reserve crash memory (kexec-tools is baked into the image). %addon com_redhat_kdump --enable --reserve-mb='auto' %end {{ template "storage-pre" . }} # NOTE: no %packages section - liveimg provides the package set from the tarball. # --- %post: apply per-host config AFTER the generic image is unpacked --- %post --log=/root/bootapi-post.log set -x # Hostname (the image is generic). echo "{{ .FQDN }}" > /etc/hostname # Static per-host networking as NetworkManager keyfiles, from NetBox interface # data. Written here (not via `network`) because the liveimg unpack clobbers # /etc. Match on MAC so NIC renaming can't misapply an address. install -d -m0755 /etc/NetworkManager/system-connections rm -f /etc/NetworkManager/system-connections/*.nmconnection {{- range .Interfaces }} {{- if .IP }} cat > "/etc/NetworkManager/system-connections/{{ .Name }}.nmconnection" <<'EOF' [connection] id={{ .Name }} type=ethernet interface-name={{ .Name }} autoconnect=true [ethernet] mac-address={{ .MAC }} [ipv4] method=manual address1={{ .IP }}/{{ .PrefixLen }}{{ if .Gateway }},{{ .Gateway }}{{ end }} dns={{ range $.Nameservers }}{{ . }};{{ end }} may-fail=false [ipv6] method=disabled EOF {{- end }} {{- end }} chmod 600 /etc/NetworkManager/system-connections/*.nmconnection # chrony + ssh + NetworkManager come from the image; ensure they're enabled. systemctl enable chronyd sshd NetworkManager {{ if .SSHAuthorizedKeys -}} install -d -m0700 /root/.ssh cat > /root/.ssh/authorized_keys <<'EOF' {{ range .SSHAuthorizedKeys }}{{ . }} {{ end }}EOF chmod 0600 /root/.ssh/authorized_keys {{- end }} # Puppet agent is baked into the image; just point it at the k8s server/CA. PUPPET_BIN=/opt/puppetlabs/bin/puppet "$PUPPET_BIN" config set --section main certname "{{ .FQDN }}" "$PUPPET_BIN" config set --section main server "{{ .PuppetServer }}" "$PUPPET_BIN" config set --section main ca_server "{{ .PuppetCAServer }}" "$PUPPET_BIN" config set --section main report_server "{{ .PuppetServer }}" "$PUPPET_BIN" config set --section main environment production install -d -m0755 /etc/sysconfig cat > /etc/sysconfig/puppet-initial <<'EOF' PUPPETCA_URL={{ .PuppetCAURL }} EOF systemctl enable puppet {{ if and .ProvisionToken .CallbackURL -}} # Clear pxe_enabled in NetBox so the next PXE boots local disk (plain HTTP; the # token authenticates). Non-fatal on failure. curl -fsS -m 15 -X POST \ -H "Authorization: Bearer {{ .ProvisionToken }}" \ "{{ .CallbackURL }}" || echo "bootapi: provisioned callback failed (non-fatal)" {{- end }} %end