* feat(infra,cilium): wire Cilium ClusterMesh anchors via tofu→cloudinit→envsubst (#1101)
Follow-up to #1223. The Flux Kustomization on every Sovereign points
at clusters/_template/bootstrap-kit/ and post-build-substitutes per-
Sovereign vars (SOVEREIGN_FQDN, MARKETPLACE_ENABLED, ...). The
per-Sovereign overlay file at clusters/<sov>/bootstrap-kit/01-cilium.yaml
that #1223 added is therefore dead code (Flux doesn't read that
path). The canonical mechanism is to extend the template with
envsubst placeholders + thread the values through tofu vars.
Wires four layers end-to-end:
1. clusters/_template/bootstrap-kit/01-cilium.yaml — adds
`cluster.name: ${CLUSTER_MESH_NAME:=}` and
`cluster.id: ${CLUSTER_MESH_ID:=0}` plus
`clustermesh.useAPIServer: true` + NodePort 32379. Empty defaults
= single-cluster Sovereign (no peer connects); the cilium subchart
accepts empty cluster.name when id=0.
2. infra/hetzner/cloudinit-control-plane.tftpl — adds
CLUSTER_MESH_NAME / CLUSTER_MESH_ID to the bootstrap-kit
Kustomization's postBuild.substitute block (alongside
SOVEREIGN_FQDN, MARKETPLACE_ENABLED, PARENT_DOMAINS_YAML).
3. infra/hetzner/variables.tf — declares cluster_mesh_name (string,
default "") and cluster_mesh_id (number, default 0, validated 0-255).
4. infra/hetzner/main.tf — primary cloud-init passes
var.cluster_mesh_{name,id} verbatim. Secondary regions (when
var.regions[i>0] is non-empty per slice G3) auto-derive each
peer's name as `<sovereign-stem>-<region-code-no-digits>` and
increment id from var.cluster_mesh_id+1. Per-region override via
the new RegionSpec.ClusterMeshName field.
5. products/catalyst/bootstrap/api/internal/provisioner/provisioner.go
— adds ClusterMeshName + ClusterMeshID to Request and threads them
into writeTfvars(); RegionSpec gains ClusterMeshName for per-peer
override.
Per docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode), the chart-side
default is intentionally empty — operator request OR per-Sovereign
overlay must supply the values when ClusterMesh is enabled. The
allocation registry lives at docs/CLUSTERMESH-CLUSTER-IDS.md
(introduced in #1223).
Refs: #1101 (EPIC-6), qa-loop iter-6 fix-33 follow-up to #1223
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(infra): escape $ in tftpl comments referencing envsubst placeholders
`tofu validate` reads `${CLUSTER_MESH_NAME}` inside YAML comments as a
template variable reference; the comment was meant to refer to the Flux
envsubst placeholder consumed downstream by the bootstrap-kit cilium
HelmRelease. Escaped both refs with `$$` per Terraform's templatefile
escape syntax so the comment renders verbatim.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(infra): replace coalesce with conditional in secondary_region_cluster_mesh_name
coalesce errors when every arg is empty (the not-in-mesh path). Switch
to a conditional that yields '' when both the per-region override AND
var.cluster_mesh_name are empty.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>