{{/*
Hetzner node-bootstrap config Secret consumed by cluster-autoscaler.

cluster-autoscaler 1.32.x's Hetzner provider exits at startup with FATAL
"`HCLOUD_CLUSTER_CONFIG` or `HCLOUD_CLOUD_INIT` is not specified" unless
at least one of these env vars is wired. The two are complementary
shapes per the upstream Hetzner provider docs:

  HCLOUD_CLUSTER_CONFIG — base64(JSON), modern per-pool node config
  HCLOUD_CLOUD_INIT     — base64(cloud-init.yaml), legacy shared bootstrap

The chart's values.yaml maps both keys via `extraEnvSecrets` against this
Secret so the upstream Deployment template emits both env vars
unconditionally; per-Sovereign overlays populate
`clusterAutoscalerHcloud.{clusterConfig,cloudInit}` via Flux `valuesFrom`
referencing the canonical `flux-system/cloud-credentials` Secret cloud-
init writes at Phase 0.

qa-loop Wave 5 Fix #79 (Gap D, prov #7 omantel.biz 2026-05-10): live
evidence showed `cluster-autoscaler-hetzner` CrashLoopBackOff with the
above FATAL because the Phase-0 cloud-init had not stamped the
`hcloud-cloud-init` key into `flux-system/cloud-credentials` (the worker
user_data was inlined into the Tofu module rather than re-exported as a
Secret key). Result: BOTH env vars resolved to empty strings, the
autoscaler hard-exited, scale-up was disabled.

Architectural fix: when the per-Sovereign overlay provides no
`clusterConfig` AND the chart can derive a valid one from
`cluster-autoscaler.autoscalingGroups[]` (already mandatory per chart
contract — it's the source of `--nodes` flags), the chart synthesises
the HCLOUD_CLUSTER_CONFIG JSON in-template and base64-encodes it. This
guarantees the autoscaler binary always finds a non-empty
HCLOUD_CLUSTER_CONFIG even when cloud-init lags — surfaces the real
"image misconfigured" / "no nodepool definitions" failures in autoscaler
logs rather than the generic "not specified" FATAL.

The synthesised JSON shape matches autoscaler/cluster-autoscaler/
cloudprovider/hetzner/README.md §"HCLOUD_CLUSTER_CONFIG":
  {
    "imagesForArch": { "amd64": "<image>", "arm64": "<image>" },
    "nodeConfigs": {
      "<pool>": {
        "cloudInit": "<base64-cloud-init or empty>",
        "labels":   {…},
        "taints":   [{…}]
      }
    }
  }

Per docs/INVIOLABLE-PRINCIPLES.md #4 every field is operator-tunable —
images per arch, per-pool labels/taints, and the per-pool cloudInit may
all be overridden via `clusterAutoscalerHcloud.derivedClusterConfig.*`
in the per-Sovereign overlay. When `clusterConfig` is non-empty (overlay
provided a fully-formed base64 blob) the chart honours it verbatim.

Issue #921. Mirrors the namespace-local-Secret pattern used by the
existing hetzner-token-secret.yaml template in this chart.
*/}}
{{- /* ── Compute the effective HCLOUD_CLUSTER_CONFIG ──────────────────── */ -}}
{{- $cfg := .Values.clusterAutoscalerHcloud.clusterConfig -}}
{{- if not $cfg -}}
  {{- /* Synthesise from autoscalingGroups[] when overlay didn't provide */ -}}
  {{- $derived := .Values.clusterAutoscalerHcloud.derivedClusterConfig | default dict -}}
  {{- $images := dict
        "amd64" (default "ubuntu-24.04" (dig "imagesForArch" "amd64" "ubuntu-24.04" $derived))
        "arm64" (default "ubuntu-24.04" (dig "imagesForArch" "arm64" "ubuntu-24.04" $derived))
  -}}
  {{- $defaultCloudInit := .Values.clusterAutoscalerHcloud.cloudInit -}}
  {{- $perPoolOverrides := default dict (dig "nodeConfigs" dict $derived) -}}
  {{- $nodeConfigs := dict -}}
  {{- $groups := default list (index .Values "cluster-autoscaler" "autoscalingGroups") -}}
  {{- range $g := $groups -}}
    {{- $poolName := $g.name | default "workers" -}}
    {{- $override := default dict (index $perPoolOverrides $poolName) -}}
    {{- $entry := dict
          "cloudInit" (default $defaultCloudInit (dig "cloudInit" $defaultCloudInit $override))
          "labels"    (default dict (dig "labels" dict $override))
          "taints"    (default list (dig "taints" list $override))
    -}}
    {{- $_ := set $nodeConfigs $poolName $entry -}}
  {{- end -}}
  {{- /* If no autoscalingGroups[] declared, register a single placeholder
        pool so the JSON is still well-formed. The autoscaler will refuse
        to scale (no `--nodes` flag) but won't FATAL on missing config. */ -}}
  {{- if eq (len $nodeConfigs) 0 -}}
    {{- $_ := set $nodeConfigs "workers" (dict
          "cloudInit" $defaultCloudInit
          "labels"    dict
          "taints"    list)
    -}}
  {{- end -}}
  {{- $jsonObj := dict "imagesForArch" $images "nodeConfigs" $nodeConfigs -}}
  {{- $cfg = toJson $jsonObj | b64enc -}}
{{- end -}}
---
apiVersion: v1
kind: Secret
metadata:
  name: hetzner-node-config
  namespace: {{ .Release.Namespace }}
  labels:
    {{- include "bp-cluster-autoscaler-hcloud.labels" . | nindent 4 }}
  annotations:
    catalyst.openova.io/cluster-config-source: {{ ternary "overlay" "chart-derived" (ne .Values.clusterAutoscalerHcloud.clusterConfig "") | quote }}
type: Opaque
stringData:
  cluster-config: {{ $cfg | quote }}
  cloud-init: {{ .Values.clusterAutoscalerHcloud.cloudInit | quote }}
