From 39123d78064fb06f1c8d99fc1da48498c27756c3 Mon Sep 17 00:00:00 2001 From: Keith Jackson Date: Tue, 25 Aug 2026 10:23:21 -0500 Subject: [PATCH] infra(cloud-init): deliver baseline via bpg user-data snippet; drop netplan/meta-data templates bpg/proxmox generates cloud-init network-config (static IP/gw/DNS) and meta-data natively from the VM initialization block, so remove network-config.yaml.tftpl and meta-data.yaml.tftpl. The rich first-boot baseline (users, SSH key, packages, kernel modules, Longhorn /dev/vdb mount, swap-off) is preserved and shipped as a user-data snippet referenced by initialization.user_data_file_id. Comments updated (libvirt -> Proxmox); /dev/vdb still valid (data disk is virtio1). Co-Authored-By: Claude Opus 4.8 --- infra/cloud-init/README.md | 20 +++++++++++++------- infra/cloud-init/meta-data.yaml.tftpl | 3 --- infra/cloud-init/network-config.yaml.tftpl | 19 ------------------- infra/cloud-init/user-data.yaml.tftpl | 8 ++++---- 4 files changed, 17 insertions(+), 33 deletions(-) delete mode 100644 infra/cloud-init/meta-data.yaml.tftpl delete mode 100644 infra/cloud-init/network-config.yaml.tftpl diff --git a/infra/cloud-init/README.md b/infra/cloud-init/README.md index 8eccefb..5dcad4d 100644 --- a/infra/cloud-init/README.md +++ b/infra/cloud-init/README.md @@ -1,8 +1,15 @@ # infra/cloud-init — first-boot baseline templates -Phase 1 **T-1.2**. The "Baseline" node lifecycle stage (docs/02 stage 2). These -templates are consumed by the OpenTofu `libvirt_cloudinit_disk` in `../tofu/` -(via `templatefile()`), one seed per node. **Authoring only — never applied.** +The "Baseline" node lifecycle stage (docs/02 stage 2). `user-data.yaml.tftpl` is +rendered by OpenTofu (`templatefile()`) and shipped to Proxmox as a **cloud-init +user-data snippet** (`proxmox_virtual_environment_file`, one per node), referenced +by each VM's `initialization.user_data_file_id`. **Authoring only — never applied.** + +> Migrated from libvirt: bpg/proxmox generates the cloud-init **network-config** +> (static IP/gateway/DNS) and **meta-data** natively from the VM's `initialization` +> block, so the old `network-config.yaml.tftpl` / `meta-data.yaml.tftpl` templates +> were removed. Only the user-data (this baseline) is still a hand-authored template. +> Requires the `snippets` content type enabled on the image datastore (see ../tofu/README). Serves **R-ENV-01** (nodes are "created, baselined, cluster-joined, managed as code") and lays the kernel/OS floor ADR-0001 (k3s) + ADR-0002 (Cilium) + @@ -12,12 +19,11 @@ ADR-0003 (Longhorn) + ADR-0005 (KubeVirt) require. - `user-data.yaml.tftpl` — `#cloud-config`: login user + injected SSH **public** key, hostname, package baseline, kernel modules, sysctls, Longhorn data-disk mount, swap-off. -- `meta-data.yaml.tftpl` — NoCloud instance-id / local-hostname. -- `network-config.yaml.tftpl` — netplan v2 **static** IP (DHCP is off on the NAT). `${...}` tokens are **OpenTofu** template vars filled by `../tofu/main.tf` -(`hostname`, `fqdn`, `username`, `ssh_authorized_key`, `ip`, `prefix`, `gateway`) -— they are not cloud-init/Jinja. +(`hostname`, `fqdn`, `username`, `ssh_authorized_key`) — they are not cloud-init/Jinja. +IP/gateway/DNS are no longer templated here; bpg/proxmox injects them from the VM's +`initialization` block. ## Baseline (cloud-init's job) vs. Ansible's job diff --git a/infra/cloud-init/meta-data.yaml.tftpl b/infra/cloud-init/meta-data.yaml.tftpl deleted file mode 100644 index 0dd269c..0000000 --- a/infra/cloud-init/meta-data.yaml.tftpl +++ /dev/null @@ -1,3 +0,0 @@ -# meta-data — NoCloud datasource identity. Rendered by OpenTofu templatefile(). -instance-id: ${hostname} -local-hostname: ${hostname} diff --git a/infra/cloud-init/network-config.yaml.tftpl b/infra/cloud-init/network-config.yaml.tftpl deleted file mode 100644 index e2d01b7..0000000 --- a/infra/cloud-init/network-config.yaml.tftpl +++ /dev/null @@ -1,19 +0,0 @@ -# network-config (cloud-init Networking Config v2 / netplan). Rendered by OpenTofu. -# Static addressing on the k3s-dev NAT: DHCP is off on the libvirt network, so each -# node's IP comes from here. `match: name "en*"` avoids hard-coding ens3 vs enp1s0 -# across cloud images. Gateway == libvirt bridge host IP; it also serves DNS. -version: 2 -ethernets: - primary: - match: - name: "en*" - dhcp4: false - dhcp6: false - addresses: - - ${ip}/${prefix} - routes: - - to: default - via: ${gateway} - nameservers: - addresses: - - ${gateway} diff --git a/infra/cloud-init/user-data.yaml.tftpl b/infra/cloud-init/user-data.yaml.tftpl index b696064..9e0764f 100644 --- a/infra/cloud-init/user-data.yaml.tftpl +++ b/infra/cloud-init/user-data.yaml.tftpl @@ -18,7 +18,7 @@ users: ssh_authorized_keys: - ${ssh_authorized_key} -# Baseline packages: guest agent (tofu/libvirt), and Longhorn's node prerequisites +# Baseline packages: guest agent (tofu/Proxmox), and Longhorn's node prerequisites # (open-iscsi provides iscsid + iscsiadm; nfs-common provides the NFS client). package_update: true packages: @@ -48,8 +48,8 @@ write_files: fs.inotify.max_user_instances = 8192 fs.inotify.max_user_watches = 524288 -# Dedicated Longhorn data disk (/dev/vdb) → ext4 mounted at /var/lib/longhorn. -# nofail so a node still boots if the disk is absent during a rebuild. +# Dedicated Longhorn data disk (/dev/vdb, the VM's virtio1 disk) → ext4 mounted at +# /var/lib/longhorn. nofail so a node still boots if the disk is absent during a rebuild. fs_setup: - label: longhorn filesystem: ext4 @@ -65,7 +65,7 @@ runcmd: - ["modprobe", "br_netfilter"] - ["modprobe", "iscsi_tcp"] - ["sysctl", "--system"] - # Longhorn needs iscsid running; guest agent for libvirt/tofu. + # Longhorn needs iscsid running; guest agent for Proxmox/tofu. - ["systemctl", "enable", "--now", "iscsid"] - ["systemctl", "enable", "--now", "qemu-guest-agent"] # k3s/kubelet baseline: disable swap.