Seed bootapi templates + distro catalog #1
@@ -0,0 +1,15 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v5.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: check-merge-conflict
|
||||
|
||||
- repo: https://github.com/adrienverge/yamllint
|
||||
rev: v1.35.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
args: [-c, .yamllint.yaml]
|
||||
@@ -0,0 +1,18 @@
|
||||
when:
|
||||
- event: [pull_request, push]
|
||||
|
||||
steps:
|
||||
- name: pre-commit
|
||||
image: git.unkin.net/unkin/almalinux9-gobuilder:20260606
|
||||
commands:
|
||||
- uvx pre-commit run --all-files
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 512Mi
|
||||
cpu: 1
|
||||
limits:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
@@ -0,0 +1,44 @@
|
||||
when:
|
||||
- event: [pull_request, push]
|
||||
|
||||
steps:
|
||||
# Render every kickstart + iPXE script for every catalog distro against a
|
||||
# fixture host, failing on any parse/resolve error or unresolved value. Reuses
|
||||
# the real bootapi engine via its `validate` subcommand (fetched @main).
|
||||
- name: validate
|
||||
image: golang:1.25
|
||||
environment:
|
||||
GOFLAGS: -buildvcs=false
|
||||
GOPRIVATE: git.unkin.net
|
||||
GONOSUMCHECK: "1"
|
||||
GOSUMDB: "off"
|
||||
GOPROXY: direct
|
||||
commands:
|
||||
- go run git.unkin.net/unkin/bootapi/cmd/bootapi@main validate .
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 512Mi
|
||||
cpu: 1
|
||||
limits:
|
||||
memory: 2Gi
|
||||
cpu: 2
|
||||
|
||||
# Best-effort shellcheck of the %post blocks (template actions stripped first).
|
||||
- name: shellcheck
|
||||
image: koalaman/shellcheck-alpine:stable
|
||||
commands:
|
||||
- apk add --no-cache bash
|
||||
- bash ci/shellcheck-post.sh
|
||||
backend_options:
|
||||
kubernetes:
|
||||
serviceAccountName: default
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
cpu: 100m
|
||||
limits:
|
||||
memory: 512Mi
|
||||
cpu: 500m
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
extends: relaxed
|
||||
|
||||
rules:
|
||||
line-length: disable
|
||||
document-start: disable
|
||||
comments:
|
||||
min-spaces-from-content: 1
|
||||
@@ -1,3 +1,43 @@
|
||||
# bootapi-templates
|
||||
|
||||
Live kickstart/iPXE templates + distro catalog for bootapi. Pulled by bootapi via git-sync; CI validates templates render for every distro.
|
||||
Live kickstart / iPXE templates and the **distro catalog** for
|
||||
[bootapi](https://git.unkin.net/unkin/bootapi). bootapi git-syncs this repo
|
||||
(every ~3 minutes, like argocd) and hot-swaps its template set on change, so OS
|
||||
and template updates ship by merging here — no bootapi rebuild or redeploy. If
|
||||
this repo is unreachable, bootapi falls back to its embedded copy of these files.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
kickstart/<name>.ks.tmpl # kickstart templates (Go text/template)
|
||||
ipxe/<name>.ipxe.tmpl # iPXE scripts: boot, fallback-local, fallback-shell
|
||||
catalog/<name>.yaml # distro catalog: host -> boot images + kickstart
|
||||
catalog/README.md # catalog field reference + debian/talos path
|
||||
ci/shellcheck-post.sh # %post shellcheck helper (used by CI)
|
||||
```
|
||||
|
||||
The data model available to templates and the catalog field reference live in
|
||||
the bootapi docs: [data-model](https://git.unkin.net/unkin/bootapi/src/branch/main/docs/data-model.md),
|
||||
[template-authoring](https://git.unkin.net/unkin/bootapi/src/branch/main/docs/template-authoring.md),
|
||||
and [catalog/README.md](catalog/README.md) here.
|
||||
|
||||
## CI (required before merge)
|
||||
|
||||
- **validate** — `bootapi validate .` renders every kickstart + iPXE script for
|
||||
every catalog distro against a fixture host and fails on any parse/resolve
|
||||
error or unresolved `<no value>`. Plus `shellcheck` (error severity) of the
|
||||
`%post` blocks.
|
||||
- **pre-commit** — yamllint + whitespace/EOF checks.
|
||||
|
||||
Validate locally before pushing:
|
||||
|
||||
```bash
|
||||
go run git.unkin.net/unkin/bootapi/cmd/bootapi@main validate .
|
||||
bash ci/shellcheck-post.sh # needs shellcheck
|
||||
```
|
||||
|
||||
## Adding a distro
|
||||
|
||||
Add `catalog/<name>.yaml` + `kickstart/<name>.ks.tmpl` (and, if the OS needs a
|
||||
mirror bootapi can't reach, a terraform-artifactapi remote). See
|
||||
[catalog/README.md](catalog/README.md) — including the debian/talos path.
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
# Distro catalog
|
||||
|
||||
One YAML file per bootable OS. bootapi selects an entry for a NetBox host
|
||||
(platform slug / OS family / `provision_template` override) and uses it to build
|
||||
the iPXE kernel/initrd URLs and pick the kickstart template. Adding an OS is a
|
||||
YAML + template change here — **no bootapi code change**.
|
||||
|
||||
## Fields
|
||||
|
||||
| Field | Required | Meaning |
|
||||
|-------|----------|---------|
|
||||
| `name` | yes | catalog key; also what a `provision_template` override matches |
|
||||
| `match.platforms` | one of platforms/family | exact NetBox platform slugs |
|
||||
| `match.family` | one of platforms/family | NetBox platform family (matches any version) |
|
||||
| `kickstart` | yes | kickstart template name (`kickstart/<name>.ks.tmpl`) |
|
||||
| `kernel_url` | yes | Go-template for the installer kernel URL |
|
||||
| `initrd_url` | yes | Go-template for the installer initrd URL |
|
||||
| `version_default` | no | version used when the platform slug carries none |
|
||||
| `kernel_args` | no | extra iPXE kernel args |
|
||||
| `vars` | no | named Go-template strings exposed to templates as `.DistroVars.<key>` |
|
||||
|
||||
`kernel_url`, `initrd_url` and `vars` values are rendered with:
|
||||
`{{.ArtifactBase}}` (bootapi's `BOOTAPI_ARTIFACT_BASE_URL`), `{{.Version}}`,
|
||||
`{{.Arch}}`, `{{.Hostname}}`, `{{.Platform}}`, `{{.OSFamily}}`.
|
||||
|
||||
## Shipped entries
|
||||
|
||||
- **almalinux9** — artifactapi `almalinux` remote, tree
|
||||
`almalinux/<ver>/BaseOS/<arch>/os/`.
|
||||
- **fedora** — artifactapi `fedora` remote, tree
|
||||
`fedora/releases/<ver>/Everything/<arch>/os/`.
|
||||
|
||||
## Adding another distro (the intended path)
|
||||
|
||||
Add `catalog/<name>.yaml` + `kickstart/<name>.ks.tmpl`. If the OS lives on a
|
||||
mirror bootapi can't already reach, add an artifactapi remote first
|
||||
(terraform-artifactapi `config/remote_rpm/<name>.yaml`). CI (`bootapi validate`)
|
||||
will render the new distro against a fixture host and fail the PR if anything is
|
||||
unresolved.
|
||||
|
||||
### Debian / Talos — not implemented, different artifact shapes
|
||||
|
||||
These need their own catalog fields/template because their PXE artifacts differ
|
||||
from the RHEL-family `images/pxeboot/{vmlinuz,initrd.img}` layout:
|
||||
|
||||
- **Debian**: netboot installer under
|
||||
`dists/<release>/main/installer-<arch>/current/images/netboot/` with
|
||||
`linux` + `initrd.gz`, and preseed (not kickstart). A `debian` entry would set
|
||||
`kernel_url`/`initrd_url` to those paths and reference a `debian.preseed.tmpl`
|
||||
template (and bootapi would serve it from `/ks` unchanged — it's just text).
|
||||
- **Talos**: immutable OS booted from factory images (`vmlinuz` + `initramfs.xz`
|
||||
from the Talos image factory / a mirrored remote), configured by a machine
|
||||
config, not a kickstart. A `talos` entry would point `kernel_url`/`initrd_url`
|
||||
at the factory artifacts and carry the config URL via `kernel_args`/`vars`.
|
||||
|
||||
Both are deferred; this note records the shape so the follow-up is mechanical.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Distro catalog entry: AlmaLinux 9.
|
||||
# Boot images are proxied through the artifactapi "almalinux" remote. Host ->
|
||||
# distro selection is NetBox-driven (platform slug almalinux9, or the almalinux
|
||||
# family, or a provision_template override naming "almalinux9").
|
||||
name: almalinux9
|
||||
match:
|
||||
platforms: [almalinux9]
|
||||
family: almalinux
|
||||
kickstart: almalinux9
|
||||
version_default: "9"
|
||||
kernel_url: "{{.ArtifactBase}}/almalinux/{{.Version}}/BaseOS/{{.Arch}}/os/images/pxeboot/vmlinuz"
|
||||
initrd_url: "{{.ArtifactBase}}/almalinux/{{.Version}}/BaseOS/{{.Arch}}/os/images/pxeboot/initrd.img"
|
||||
kernel_args:
|
||||
- inst.text
|
||||
- net.ifnames=0
|
||||
vars:
|
||||
# Version-level mirror base; the kickstart appends BaseOS/AppStream under it.
|
||||
mirror: "{{.ArtifactBase}}/almalinux/{{.Version}}"
|
||||
@@ -0,0 +1,16 @@
|
||||
# Distro catalog entry: Fedora (family-level, matches any fedoraNN platform).
|
||||
# Boot images are proxied through the artifactapi "fedora" remote, whose tree
|
||||
# lives under releases/<ver>/Everything/<arch>/os/.
|
||||
name: fedora
|
||||
match:
|
||||
family: fedora
|
||||
kickstart: fedora
|
||||
version_default: "41"
|
||||
kernel_url: "{{.ArtifactBase}}/fedora/releases/{{.Version}}/Everything/{{.Arch}}/os/images/pxeboot/vmlinuz"
|
||||
initrd_url: "{{.ArtifactBase}}/fedora/releases/{{.Version}}/Everything/{{.Arch}}/os/images/pxeboot/initrd.img"
|
||||
kernel_args:
|
||||
- inst.text
|
||||
- net.ifnames=0
|
||||
vars:
|
||||
# Install-tree root; the kickstart appends <arch>/os/ under it.
|
||||
mirror: "{{.ArtifactBase}}/fedora/releases/{{.Version}}/Everything"
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Best-effort shellcheck of the %post ... %end blocks in the kickstart templates.
|
||||
# The bodies are Go text/templates, so we first replace every {{ ... }} action
|
||||
# with a shell-safe placeholder, then extract each %post block into a script and
|
||||
# run shellcheck at "error" severity (template placeholders make lower-severity
|
||||
# style warnings meaningless). Fails the build on any shellcheck error.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${ROOT_DIR}"
|
||||
|
||||
tmp="$(mktemp -d)"
|
||||
trap 'rm -rf "${tmp}"' EXIT
|
||||
rc=0
|
||||
|
||||
shopt -s nullglob
|
||||
for ks in kickstart/*.ks.tmpl; do
|
||||
# Split into %post-scriptlets; strip {{...}} -> "PH"; give each a shebang.
|
||||
awk '
|
||||
/^%post/ { inpost=1; n++; next }
|
||||
/^%end/ { inpost=0; next }
|
||||
inpost { print > ("'"${tmp}"'/post-" n ".sh") }
|
||||
' "${ks}"
|
||||
|
||||
for f in "${tmp}"/post-*.sh; do
|
||||
[ -e "${f}" ] || continue
|
||||
# Neutralize Go template actions and prepend a shebang.
|
||||
sed -i 's/{{[^}]*}}/PH/g' "${f}"
|
||||
printf '#!/usr/bin/env bash\n%s' "$(cat "${f}")" > "${f}.final"
|
||||
echo "shellcheck (error severity): ${ks} -> $(basename "${f}")"
|
||||
if ! shellcheck -S error "${f}.final"; then
|
||||
rc=1
|
||||
fi
|
||||
rm -f "${f}" "${f}.final"
|
||||
done
|
||||
done
|
||||
|
||||
if [ "${rc}" -eq 0 ]; then
|
||||
echo "shellcheck: no errors in %post blocks"
|
||||
fi
|
||||
exit "${rc}"
|
||||
@@ -0,0 +1,20 @@
|
||||
{{- /*
|
||||
iPXE boot script for a known, PXE-enabled host. Chains the OS installer
|
||||
kernel+initrd (from the distro catalog) and points inst.ks= back at bootapi's
|
||||
/ks/<host> over plain HTTP, so an installer with no internal-CA trust can fetch
|
||||
it. Mirrors how Cobbler generated a per-MAC gPXE script carrying inst.ks=.
|
||||
|
||||
KernelURL/InitrdURL/RepoURL come from the selected catalog entry (artifactapi
|
||||
remote); KernelArgs are the catalog's extra args. KickstartURL uses
|
||||
BOOTAPI_BASE_URL (http://).
|
||||
*/ -}}
|
||||
#!ipxe
|
||||
echo bootapi: provisioning {{ .FQDN }} ({{ .Platform }})
|
||||
{{ if and .KernelURL .InitrdURL -}}
|
||||
kernel {{ .KernelURL }} initrd=initrd.img{{ if .RepoURL }} inst.repo={{ .RepoURL }}{{ end }} inst.ks={{ .KickstartURL }} ip=dhcp{{ range .KernelArgs }} {{ . }}{{ end }}
|
||||
initrd {{ .InitrdURL }}
|
||||
boot
|
||||
{{- else -}}
|
||||
echo bootapi: no boot images resolved for {{ .Platform }} (no catalog entry / BOOTAPI_BOOT_BASE_URL); booting local disk
|
||||
sanboot --no-describe --drive 0x80 || exit
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{- /*
|
||||
Safe default for an UNKNOWN MAC (NetBox has no matching device). We deliberately
|
||||
do NOT start an installer for a machine we can't identify — that could wipe a
|
||||
production box that PXE-booted by accident. Instead we boot from local disk, so
|
||||
an already-installed host just continues, and a brand-new host loops back to PXE
|
||||
on its next attempt (by which point NetBox should know it).
|
||||
*/ -}}
|
||||
#!ipxe
|
||||
echo bootapi: unknown MAC ${net0/mac}; not provisioning. Booting local disk.
|
||||
sanboot --no-describe --drive 0x80 || exit
|
||||
@@ -0,0 +1,10 @@
|
||||
{{- /*
|
||||
Debug fallback for an unknown MAC (opt in via BOOTAPI_UNKNOWN_MAC_FALLBACK=shell).
|
||||
Drops to an interactive iPXE shell instead of booting anything, so an operator
|
||||
racking a new box can inspect ${net0/mac} and register it in NetBox. Not the
|
||||
default because it halts the boot and is unsafe for an accidental PXE of a prod
|
||||
host.
|
||||
*/ -}}
|
||||
#!ipxe
|
||||
echo bootapi: unknown MAC ${net0/mac}; dropping to iPXE shell for debugging.
|
||||
shell
|
||||
@@ -0,0 +1,113 @@
|
||||
{{- /*
|
||||
AlmaLinux 9 kickstart, ported from the Cobbler default.ks contract.
|
||||
|
||||
Rendered by bootapi from NetBox data + render-time secrets + the distro catalog.
|
||||
Install source comes from the artifactapi almalinux remote (via the catalog
|
||||
mirror var). The %post installs the Puppet agent and points it at the k8s
|
||||
puppetserver (puppet.k8s.syd1.au.unkin.net / puppetca.k8s...), writes the
|
||||
puppet-initial PUPPETCA_URL env file, then posts back to bootapi so pxe_enabled
|
||||
flips off (Cobbler's netboot_enabled flow).
|
||||
|
||||
Data model: see docs/data-model.md. `.RootPasswordHash` and `.ProvisionToken`
|
||||
come from Vault/env at render time, never from NetBox.
|
||||
*/ -}}
|
||||
{{- $mirror := .DistroVars.mirror -}}
|
||||
#version=RHEL9
|
||||
# Rendered by bootapi for {{ .FQDN }} (platform {{ .Platform }}, role {{ default "none" .Role }})
|
||||
text
|
||||
eula --agreed
|
||||
firstboot --disable
|
||||
reboot
|
||||
|
||||
# --- install source (artifactapi almalinux remote, from the distro catalog) ---
|
||||
url --url={{ $mirror }}/BaseOS/{{ .Arch }}/os/
|
||||
repo --name=AppStream --baseurl={{ $mirror }}/AppStream/{{ .Arch }}/os/
|
||||
|
||||
# --- localization ---
|
||||
keyboard --xlayouts='us'
|
||||
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
|
||||
authselect select sssd with-mkhomedir --force
|
||||
|
||||
# --- networking (static, from NetBox) ---
|
||||
{{- $primary := .PrimaryInterface }}
|
||||
{{- range .Interfaces }}
|
||||
{{- if .IP }}
|
||||
network --bootproto=static --device={{ .MAC }} --ip={{ .IP }} --netmask={{ .Netmask }}{{ if .Gateway }} --gateway={{ .Gateway }}{{ end }}{{ range $.Nameservers }} --nameserver={{ . }}{{ end }}{{ if and $primary (eq .MAC $primary.MAC) }} --hostname={{ $.FQDN }}{{ end }} --activate --onboot=on --noipv6
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# --- storage ---
|
||||
ignoredisk --only-use=sda
|
||||
clearpart --all --initlabel --drives=sda
|
||||
bootloader --location=mbr --boot-drive=sda --append="crashkernel=auto"
|
||||
autopart --type=lvm --nohome
|
||||
|
||||
# --- packages ---
|
||||
%packages --ignoremissing --excludedocs
|
||||
@^minimal-environment
|
||||
openssh-server
|
||||
chrony
|
||||
vim-minimal
|
||||
tmux
|
||||
git
|
||||
-iwl*-firmware
|
||||
%end
|
||||
|
||||
# --- bootstrap: puppet (k8s) + end-of-install callback ---
|
||||
%post --log=/root/bootapi-post.log
|
||||
set -x
|
||||
|
||||
# chrony: keep time sane before any cert work.
|
||||
systemctl enable chronyd
|
||||
|
||||
{{ if .SSHAuthorizedKeys -}}
|
||||
# root authorized_keys (from render-time config, not NetBox).
|
||||
install -d -m0700 /root/.ssh
|
||||
cat > /root/.ssh/authorized_keys <<'EOF'
|
||||
{{ range .SSHAuthorizedKeys }}{{ . }}
|
||||
{{ end }}EOF
|
||||
chmod 0600 /root/.ssh/authorized_keys
|
||||
{{- end }}
|
||||
|
||||
# Install the Puppet 8 agent from the puppet platform repo.
|
||||
rpm -q puppet-agent >/dev/null 2>&1 || \
|
||||
dnf install -y https://yum.puppet.com/puppet8-release-el-9.noarch.rpm
|
||||
dnf install -y puppet-agent
|
||||
|
||||
# Point the agent at the k8s puppetserver / 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
|
||||
|
||||
# puppet-initial bootstrap unit reads PUPPETCA_URL from this EnvironmentFile.
|
||||
install -d -m0755 /etc/sysconfig
|
||||
cat > /etc/sysconfig/puppet-initial <<'EOF'
|
||||
PUPPETCA_URL={{ .PuppetCAURL }}
|
||||
EOF
|
||||
|
||||
# Enable the agent; first boot triggers firstrun (autosign handles the CSR).
|
||||
systemctl enable puppet
|
||||
|
||||
{{ if and .ProvisionToken .CallbackURL -}}
|
||||
# Tell bootapi the install is done so it clears pxe_enabled in NetBox and the
|
||||
# next PXE boots local disk. Runs over plain HTTP (no internal CA trust yet);
|
||||
# the token authenticates the call. Non-fatal if it fails (the local-disk
|
||||
# fallback still protects a re-provisioned host on the following boot).
|
||||
curl -fsS -m 15 -X POST \
|
||||
-H "Authorization: Bearer {{ .ProvisionToken }}" \
|
||||
"{{ .CallbackURL }}" || echo "bootapi: provisioned callback failed (non-fatal)"
|
||||
{{- end }}
|
||||
%end
|
||||
@@ -0,0 +1,80 @@
|
||||
{{- /*
|
||||
Fedora kickstart (family-level template: matches any "fedoraNN" platform slug
|
||||
via the catalog family match). Kept close to the AlmaLinux template so the two
|
||||
stay comparable; the differences are the install-tree layout (releases/.../
|
||||
Everything) and the puppet release RPM. Install source + boot images come from
|
||||
the artifactapi fedora remote via the distro catalog.
|
||||
*/ -}}
|
||||
{{- $mirror := .DistroVars.mirror -}}
|
||||
#version=F{{ default "" .OSVersion }}
|
||||
# Rendered by bootapi for {{ .FQDN }} (platform {{ .Platform }})
|
||||
text
|
||||
firstboot --disable
|
||||
reboot
|
||||
|
||||
# --- install source (artifactapi fedora remote, from the distro catalog) ---
|
||||
url --url={{ $mirror }}/{{ .Arch }}/os/
|
||||
|
||||
keyboard --xlayouts='us'
|
||||
lang en_AU.UTF-8
|
||||
timezone Australia/Sydney --utc
|
||||
|
||||
{{ if .RootPasswordHash -}}
|
||||
rootpw --iscrypted {{ .RootPasswordHash }}
|
||||
{{- else -}}
|
||||
rootpw --lock
|
||||
{{- end }}
|
||||
selinux --enforcing
|
||||
firewall --enabled --service=ssh
|
||||
|
||||
# --- networking (static, from NetBox) ---
|
||||
{{- $primary := .PrimaryInterface }}
|
||||
{{- range .Interfaces }}
|
||||
{{- if .IP }}
|
||||
network --bootproto=static --device={{ .MAC }} --ip={{ .IP }} --netmask={{ .Netmask }}{{ if .Gateway }} --gateway={{ .Gateway }}{{ end }}{{ range $.Nameservers }} --nameserver={{ . }}{{ end }}{{ if and $primary (eq .MAC $primary.MAC) }} --hostname={{ $.FQDN }}{{ end }} --activate --onboot=on --noipv6
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# --- storage ---
|
||||
ignoredisk --only-use=sda
|
||||
clearpart --all --initlabel --drives=sda
|
||||
bootloader --location=mbr --boot-drive=sda
|
||||
autopart --type=lvm --nohome
|
||||
|
||||
%packages --ignoremissing
|
||||
@^minimal-environment
|
||||
openssh-server
|
||||
chrony
|
||||
git
|
||||
%end
|
||||
|
||||
%post --log=/root/bootapi-post.log
|
||||
set -x
|
||||
systemctl enable chronyd sshd
|
||||
{{ if .SSHAuthorizedKeys -}}
|
||||
install -d -m0700 /root/.ssh
|
||||
cat > /root/.ssh/authorized_keys <<'EOF'
|
||||
{{ range .SSHAuthorizedKeys }}{{ . }}
|
||||
{{ end }}EOF
|
||||
chmod 0600 /root/.ssh/authorized_keys
|
||||
{{- end }}
|
||||
dnf install -y "https://yum.puppet.com/puppet8-release-fedora-{{ default "40" .OSVersion }}.noarch.rpm" || true
|
||||
dnf install -y puppet-agent
|
||||
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 }}"
|
||||
|
||||
install -d -m0755 /etc/sysconfig
|
||||
cat > /etc/sysconfig/puppet-initial <<'EOF'
|
||||
PUPPETCA_URL={{ .PuppetCAURL }}
|
||||
EOF
|
||||
|
||||
systemctl enable puppet
|
||||
|
||||
{{ if and .ProvisionToken .CallbackURL -}}
|
||||
curl -fsS -m 15 -X POST \
|
||||
-H "Authorization: Bearer {{ .ProvisionToken }}" \
|
||||
"{{ .CallbackURL }}" || echo "bootapi: provisioned callback failed (non-fatal)"
|
||||
{{- end }}
|
||||
%end
|
||||
Reference in New Issue
Block a user