Add image-based provisioning (liveimg) #3
@@ -61,6 +61,39 @@ real NetBox platform slug — so these entries are *only* reachable via the
|
||||
override and never hijack a plain `almalinux9` host. To add another model, copy
|
||||
one of these files, change the `name`/slug and `storage_mode`.
|
||||
|
||||
## Image (liveimg) installs
|
||||
|
||||
`image.ks.tmpl` unpacks a prebuilt rootfs tarball with Anaconda `liveimg` instead
|
||||
of resolving packages — faster and reproducible. An image catalog entry looks
|
||||
like a normal one but sets `kickstart: image` and a `rootfs_tarball` var:
|
||||
|
||||
```yaml
|
||||
name: almalinux9-image
|
||||
match: {platforms: [almalinux9-image]}
|
||||
kickstart: image
|
||||
kernel_url: "{{.ArtifactBase}}/almalinux/{{.Version}}/BaseOS/{{.Arch}}/os/images/pxeboot/vmlinuz" # the Anaconda installer kernel, unchanged
|
||||
initrd_url: "...initrd.img"
|
||||
vars:
|
||||
rootfs_tarball: "https://artifactapi.k8s.syd1.au.unkin.net/api/v2/remotes/rootfs-images/files/almalinux9-node-<ver>.tar.zst"
|
||||
# storage_mode / vg_grow work exactly as for package installs (omit for VM autopart).
|
||||
```
|
||||
|
||||
- **Boot** is still the AlmaLinux installer kernel/initrd; `liveimg` only changes
|
||||
the payload. **Storage** reuses the shared `kickstart/_storage.ks.tmpl` partials
|
||||
(`storage_mode` / `vg_grow`), so image and package installs lay disks out
|
||||
identically — including the OptiPlex NVMe modes (`optiplex-7080-image` shows an
|
||||
image + `auto-nvme` + `vg_grow` combination).
|
||||
- **Networking is templated per-host in `%post`** (NetworkManager keyfiles from
|
||||
the same NetBox interface data), because the generic image has no per-host
|
||||
identity and the `liveimg` unpack overwrites `/etc`.
|
||||
- The tarball is built by the separate
|
||||
[bootapi-images](https://git.unkin.net/unkin/bootapi-images) repo (a `v*` tag
|
||||
builds and uploads `almalinux9-node-<ver>.tar.zst` to the artifactapi
|
||||
`rootfs-images` local repo). Baked into the image = everything the `%post`
|
||||
assumes present (kernel/grub/dracut, NetworkManager, openssh, chrony,
|
||||
kexec-tools, curl, puppet-agent). Bump an image = new bootapi-images release +
|
||||
a one-line `rootfs_tarball` edit here.
|
||||
|
||||
## Adding another distro (the intended path)
|
||||
|
||||
Add `catalog/<name>.yaml` + `kickstart/<name>.ks.tmpl`. If the OS lives on a
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Distro catalog entry: AlmaLinux 9, IMAGE install (liveimg).
|
||||
#
|
||||
# Boots the same AlmaLinux installer kernel/initrd as almalinux9, but the
|
||||
# kickstart (image.ks.tmpl) uses liveimg to unpack the prebuilt node rootfs
|
||||
# tarball instead of resolving packages -- much faster, reproducible. Generic
|
||||
# storage (autopart on sda). Select via a device's provision_template custom
|
||||
# field = "almalinux9-image".
|
||||
name: almalinux9-image
|
||||
match:
|
||||
platforms: [almalinux9-image]
|
||||
kickstart: image
|
||||
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:
|
||||
# Prebuilt node rootfs on the artifactapi rootfs-images local repo, built and
|
||||
# published by the bootapi-images repo (v* tag). Immutable, semver-versioned;
|
||||
# bump this one line to roll the fleet forward (overwrites are 409-rejected).
|
||||
rootfs_tarball: "https://artifactapi.k8s.syd1.au.unkin.net/api/v2/remotes/rootfs-images/files/almalinux9-node-1.0.0.tar.zst"
|
||||
@@ -0,0 +1,21 @@
|
||||
# Distro catalog entry: OptiPlex 7080, IMAGE install (liveimg).
|
||||
#
|
||||
# The image counterpart of optiplex-7080: same liveimg payload as
|
||||
# almalinux9-image, but with the 7080's auto-NVMe / grow-to-fill storage
|
||||
# (storage_mode auto-nvme + vg_grow). Proves the image kickstart reuses the
|
||||
# OptiPlex model storage exactly as the package install does. Select via a
|
||||
# device's provision_template custom field = "optiplex-7080-image".
|
||||
name: optiplex-7080-image
|
||||
match:
|
||||
platforms: [optiplex-7080-image]
|
||||
kickstart: image
|
||||
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:
|
||||
rootfs_tarball: "https://artifactapi.k8s.syd1.au.unkin.net/api/v2/remotes/rootfs-images/files/almalinux9-node-1.0.0.tar.zst"
|
||||
storage_mode: auto-nvme
|
||||
vg_grow: "true"
|
||||
@@ -0,0 +1,90 @@
|
||||
{{- /*
|
||||
Shared model-aware storage partials, used by both almalinux9.ks.tmpl (package
|
||||
install) and image.ks.tmpl (liveimg). One place for the storage layout so the
|
||||
classic and image installs stay identical on disk.
|
||||
|
||||
Driven by the distro catalog vars:
|
||||
storage_mode "" generic/VM -> autopart on sda
|
||||
"fixed-nvme" OptiPlex 3050 -> static nvme0n1, BIOS/MBR, fixed VG
|
||||
"auto-nvme" OptiPlex 3060/7080 -> %pre picks the NVMe, EFI-aware
|
||||
vg_grow "true" grow the LVM PV to fill the disk (OptiPlex 7080)
|
||||
|
||||
liveimg works with this unchanged: Anaconda creates these filesystems, untars the
|
||||
rootfs into them, writes fstab, installs grub and regenerates the initramfs.
|
||||
*/ -}}
|
||||
{{- define "storage-block" -}}
|
||||
{{- $storage := index .DistroVars "storage_mode" -}}
|
||||
{{- $grow := eq (index .DistroVars "vg_grow") "true" -}}
|
||||
{{- if eq $storage "fixed-nvme" }}
|
||||
# OptiPlex 3050: single known NVMe, legacy BIOS boot (no EFI, no boot-drive).
|
||||
ignoredisk --only-use=nvme0n1
|
||||
clearpart --all --initlabel --drives=nvme0n1
|
||||
part /boot --fstype="xfs" --ondisk=nvme0n1 --size=1024
|
||||
part pv.01 --fstype="lvmpv" --ondisk=nvme0n1 --size=31743
|
||||
volgroup rootvg --pesize=4096 pv.01
|
||||
logvol / --fstype="xfs" --size=10240 --name=root --vgname=rootvg
|
||||
logvol swap --fstype="swap" --size=2048 --name=swap --vgname=rootvg
|
||||
logvol /home --fstype="xfs" --size=9207 --name=home --vgname=rootvg
|
||||
logvol /var/log --fstype="xfs" --size=10240 --name=varlog --vgname=rootvg
|
||||
bootloader --location=mbr
|
||||
{{- else if eq $storage "auto-nvme" }}
|
||||
# OptiPlex 3060 / 7080: partition table generated in %pre (see storage-pre)
|
||||
# into /tmp/bootapi-partitions, so the OS lands on whichever internal NVMe is
|
||||
# present and an EFI partition is added only when booted UEFI.
|
||||
%include /tmp/bootapi-partitions
|
||||
{{- else }}
|
||||
# Generic / VM default: single virtual disk, autopart.
|
||||
ignoredisk --only-use=sda
|
||||
clearpart --all --initlabel --drives=sda
|
||||
bootloader --location=mbr --boot-drive=sda --append="crashkernel=auto"
|
||||
autopart --type=lvm --nohome
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
{{- define "storage-pre" -}}
|
||||
{{- $storage := index .DistroVars "storage_mode" -}}
|
||||
{{- $grow := eq (index .DistroVars "vg_grow") "true" -}}
|
||||
{{- if eq $storage "auto-nvme" }}
|
||||
# --- %pre: pick the internal NVMe and emit the partition table -----------------
|
||||
# Ported from Cobbler almalinux9_dell3060 / almalinux9_dell7080. Anaconda reads
|
||||
# every section before executing, so /tmp/bootapi-partitions (pulled in by the
|
||||
# %include above) is populated in time. Picks the first NVMe under 512GB, wipes
|
||||
# any prior rootvg so re-provisioning is idempotent, and adds an EFI System
|
||||
# Partition only when the host actually booted UEFI.
|
||||
%pre --interpreter=/usr/bin/bash --log=/root/bootapi-pre.log
|
||||
set -x
|
||||
lsblk -d -b -n -o NAME,SIZE
|
||||
|
||||
# First internal NVMe under 512GB (skips large data disks and USB installers).
|
||||
OSDISK=$(lsblk -d -b -n -o NAME,SIZE | awk '$1 ~ /^nvme/ && $2 < 549755813888 { print $1; exit }')
|
||||
|
||||
# Tear down a pre-existing rootvg so a re-install starts from a clean disk.
|
||||
if vgs rootvg >/dev/null 2>&1; then
|
||||
lvchange -an rootvg || true
|
||||
vgchange -an rootvg || true
|
||||
vgremove -y rootvg || true
|
||||
for pv in $(pvs --noheadings -o pv_name,vg_name | awk '$2 == "rootvg" { print $1 }'); do
|
||||
pvremove "$pv" --force --force -y || true
|
||||
done
|
||||
fi
|
||||
|
||||
wipefs -a "/dev/${OSDISK}"
|
||||
dd if=/dev/zero of="/dev/${OSDISK}" bs=512 count=100
|
||||
|
||||
{
|
||||
echo "ignoredisk --only-use=${OSDISK}"
|
||||
echo "clearpart --all --initlabel --drives=${OSDISK}"
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
echo "part /boot/efi --fstype=vfat --ondisk=${OSDISK} --size=200"
|
||||
fi
|
||||
echo "part /boot --fstype=xfs --ondisk=${OSDISK} --size=1024"
|
||||
echo "part pv.01 --fstype=lvmpv --ondisk=${OSDISK} --size=31743{{ if $grow }} --grow{{ end }}"
|
||||
echo "volgroup rootvg --pesize=4096 pv.01"
|
||||
echo "logvol / --fstype=xfs --size=10240 --name=root --vgname=rootvg"
|
||||
echo "logvol swap --fstype=swap --size=2048 --name=swap --vgname=rootvg"
|
||||
echo "logvol /home --fstype=xfs --size=9207 --name=home --vgname=rootvg"
|
||||
echo "logvol /var/log --fstype=xfs --size=10240 --name=varlog --vgname=rootvg"
|
||||
echo "bootloader --location=mbr --boot-drive=${OSDISK}"
|
||||
} > /tmp/bootapi-partitions
|
||||
%end
|
||||
{{- end }}
|
||||
{{- end -}}
|
||||
@@ -1,19 +1,15 @@
|
||||
{{- /*
|
||||
AlmaLinux 9 kickstart, ported from the Cobbler default.ks contract.
|
||||
AlmaLinux 9 kickstart (package install), ported from the Cobbler default.ks
|
||||
contract. Install source is the artifactapi almalinux remote (catalog mirror
|
||||
var). The %post installs the Puppet agent, points it at the k8s puppetserver,
|
||||
writes the puppet-initial PUPPETCA_URL env file, then posts back to bootapi so
|
||||
pxe_enabled flips off (Cobbler's netboot_enabled flow).
|
||||
|
||||
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).
|
||||
Storage is model-aware via the shared _storage.ks.tmpl partials (storage_mode /
|
||||
vg_grow catalog vars) so this and image.ks.tmpl lay disks out identically.
|
||||
|
||||
Storage is model-aware: the catalog entry selects a `storage_mode` (and, for
|
||||
grow-to-fill, `vg_grow`) so one template serves VMs and every Dell OptiPlex
|
||||
model. See the "storage" section and catalog/optiplex-*.yaml.
|
||||
|
||||
Data model: see docs/data-model.md. `.RootPasswordHash` and `.ProvisionToken`
|
||||
come from Vault/env at render time, never from NetBox.
|
||||
Data model: docs/data-model.md. `.RootPasswordHash` / `.ProvisionToken` come
|
||||
from Vault/env at render time, never from NetBox.
|
||||
*/ -}}
|
||||
{{- $mirror := .DistroVars.mirror -}}
|
||||
#version=RHEL9
|
||||
@@ -50,90 +46,13 @@ network --bootproto=static --device={{ .MAC }} --ip={{ .IP }} --netmask={{ .Netm
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# --- storage (model-aware; selected by the distro catalog's storage_mode var) ---
|
||||
# storage_mode is set per-model by the catalog entry (catalog/optiplex-*.yaml):
|
||||
# "" generic/VM default -> autopart on sda (unchanged legacy path)
|
||||
# "fixed-nvme" OptiPlex 3050 -> static nvme0n1, BIOS/MBR, fixed 31G VG
|
||||
# "auto-nvme" OptiPlex 3060 / 7080 -> %pre picks the internal NVMe, EFI-aware
|
||||
# vg_grow ("true") grows the LVM PV to fill the disk (OptiPlex 7080 only).
|
||||
# Layout (explicit LVM: /boot, root, swap, /home, /var/log) mirrors the Cobbler
|
||||
# profiles almalinux9-dell_3050 / _3060 / _7080. Ported from the real templates
|
||||
# almalinux9_dell3050 / almalinux9_dell3060 / almalinux9_dell7080.
|
||||
{{- $storage := index .DistroVars "storage_mode" }}
|
||||
{{- $grow := eq (index .DistroVars "vg_grow") "true" }}
|
||||
{{- if eq $storage "fixed-nvme" }}
|
||||
# OptiPlex 3050: single known NVMe, legacy BIOS boot (no EFI, no boot-drive).
|
||||
ignoredisk --only-use=nvme0n1
|
||||
clearpart --all --initlabel --drives=nvme0n1
|
||||
part /boot --fstype="xfs" --ondisk=nvme0n1 --size=1024
|
||||
part pv.01 --fstype="lvmpv" --ondisk=nvme0n1 --size=31743
|
||||
volgroup rootvg --pesize=4096 pv.01
|
||||
logvol / --fstype="xfs" --size=10240 --name=root --vgname=rootvg
|
||||
logvol swap --fstype="swap" --size=2048 --name=swap --vgname=rootvg
|
||||
logvol /home --fstype="xfs" --size=9207 --name=home --vgname=rootvg
|
||||
logvol /var/log --fstype="xfs" --size=10240 --name=varlog --vgname=rootvg
|
||||
bootloader --location=mbr
|
||||
{{- else if eq $storage "auto-nvme" }}
|
||||
# OptiPlex 3060 / 7080: partition table is generated in %pre (below) into
|
||||
# /tmp/bootapi-partitions and pulled in here, so the OS lands on whichever
|
||||
# internal NVMe is present and the EFI partition is added only when booted UEFI.
|
||||
%include /tmp/bootapi-partitions
|
||||
{{- else }}
|
||||
# Generic / VM default: single virtual disk, autopart.
|
||||
ignoredisk --only-use=sda
|
||||
clearpart --all --initlabel --drives=sda
|
||||
bootloader --location=mbr --boot-drive=sda --append="crashkernel=auto"
|
||||
autopart --type=lvm --nohome
|
||||
{{- end }}
|
||||
# --- storage (model-aware; shared with image.ks.tmpl via _storage.ks.tmpl) ---
|
||||
{{ template "storage-block" . }}
|
||||
|
||||
# kdump: reserve crash memory + install kexec-tools (Cobbler com_redhat_kdump).
|
||||
# kdump: reserve crash memory (Cobbler com_redhat_kdump; kexec-tools baked below).
|
||||
%addon com_redhat_kdump --enable --reserve-mb='auto'
|
||||
%end
|
||||
{{- if eq $storage "auto-nvme" }}
|
||||
|
||||
# --- %pre: pick the internal NVMe and emit the partition table -----------------
|
||||
# Ported from Cobbler almalinux9_dell3060 / almalinux9_dell7080. Anaconda runs
|
||||
# %pre before partitioning, so /tmp/bootapi-partitions (pulled in by the
|
||||
# %include above) is populated in time. Picks the first NVMe under 512GB, wipes
|
||||
# any prior rootvg so re-provisioning is idempotent, and adds an EFI System
|
||||
# Partition only when the host actually booted UEFI.
|
||||
%pre --interpreter=/usr/bin/bash --log=/root/bootapi-pre.log
|
||||
set -x
|
||||
lsblk -d -b -n -o NAME,SIZE
|
||||
|
||||
# First internal NVMe under 512GB (skips large data disks and USB installers).
|
||||
OSDISK=$(lsblk -d -b -n -o NAME,SIZE | awk '$1 ~ /^nvme/ && $2 < 549755813888 { print $1; exit }')
|
||||
|
||||
# Tear down a pre-existing rootvg so a re-install starts from a clean disk.
|
||||
if vgs rootvg >/dev/null 2>&1; then
|
||||
lvchange -an rootvg || true
|
||||
vgchange -an rootvg || true
|
||||
vgremove -y rootvg || true
|
||||
for pv in $(pvs --noheadings -o pv_name,vg_name | awk '$2 == "rootvg" { print $1 }'); do
|
||||
pvremove "$pv" --force --force -y || true
|
||||
done
|
||||
fi
|
||||
|
||||
wipefs -a "/dev/${OSDISK}"
|
||||
dd if=/dev/zero of="/dev/${OSDISK}" bs=512 count=100
|
||||
|
||||
{
|
||||
echo "ignoredisk --only-use=${OSDISK}"
|
||||
echo "clearpart --all --initlabel --drives=${OSDISK}"
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
echo "part /boot/efi --fstype=vfat --ondisk=${OSDISK} --size=200"
|
||||
fi
|
||||
echo "part /boot --fstype=xfs --ondisk=${OSDISK} --size=1024"
|
||||
echo "part pv.01 --fstype=lvmpv --ondisk=${OSDISK} --size=31743{{ if $grow }} --grow{{ end }}"
|
||||
echo "volgroup rootvg --pesize=4096 pv.01"
|
||||
echo "logvol / --fstype=xfs --size=10240 --name=root --vgname=rootvg"
|
||||
echo "logvol swap --fstype=swap --size=2048 --name=swap --vgname=rootvg"
|
||||
echo "logvol /home --fstype=xfs --size=9207 --name=home --vgname=rootvg"
|
||||
echo "logvol /var/log --fstype=xfs --size=10240 --name=varlog --vgname=rootvg"
|
||||
echo "bootloader --location=mbr --boot-drive=${OSDISK}"
|
||||
} > /tmp/bootapi-partitions
|
||||
%end
|
||||
{{- end }}
|
||||
{{ template "storage-pre" . }}
|
||||
|
||||
# --- packages ---
|
||||
%packages --ignoremissing --excludedocs
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
{{- /*
|
||||
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
|
||||
Reference in New Issue
Block a user