--- # Flux Kustomization: VM tier (KubeVirt VirtualMachines). Reconciles ./apps/vms. # # NON-GATING (wait:false): unlike the app waves, this does NOT health-wait. A VM's first-boot image # import (CDI, minutes) + in-guest software install mean a VM can be intentionally long-not-Ready, so # health-gating it would wedge reconciliation for no benefit. VMs have no in-cluster dependents. # dependsOn platform-config so KubeVirt/CDI + the longhorn-vm StorageClass + CDI StorageProfiles # exist first. prune:true — this Kustomization solely owns the VM manifests (no adoption concern). apiVersion: kustomize.toolkit.fluxcd.io/v1 kind: Kustomization metadata: name: apps-vms namespace: flux-system spec: interval: 10m retryInterval: 2m timeout: 5m prune: true wait: false dependsOn: - name: platform-config sourceRef: kind: GitRepository name: flux-system path: ./apps/vms # postBuild.substituteFrom ENABLED 2026-08-31 (R-ENV-02). It was previously omitted because Flux's # envsubst runs over the ENTIRE manifest — including VM cloud-init shell scripts — and would mangle # every `${...}`; the omission was safe only while no VM manifest referenced a cluster-var. It now # does: apps/vms/unifi/50-service-l4.yaml pins the UniFi L4 VIP from ${UNIFI_L4_VIP} instead of the # hardcoded dev-LAN literal that would have shipped 192.168.1.54 onto the PROD LAN. # # The escape contract the old comment prescribed is now in force and MUST be honoured by every VM # manifest under this path (verified with `flux envsubst`): # `${VAR}` -> substituted (empty when unset) => escape shell braces as `$${VAR}`, which # envsubst emits back as a literal `${VAR}`. # `$VAR` -> left alone by envsubst => bare shell vars need NO escaping. # `$(cmd)` -> left alone by envsubst => command substitution needs NO escaping. # `${ARR[0]}` (e.g. ${PIPESTATUS[0]}) -> HARD ERROR "missing closing brace", which fails this # whole Kustomization. NEVER use an indexed expansion here, escaped or not. postBuild: substituteFrom: - kind: ConfigMap name: cluster-vars