# Catalyst Blueprint umbrella metadata — the upstream chart is now resolved
# as a Helm subchart via Chart.yaml `dependencies:`. This values.yaml carries
# both:
#   1. The catalystBlueprint metadata block (provenance + version) so
#      observability/audit pipelines can inspect the artifact and report
#      which upstream chart + version is bundled.
#   2. The upstream subchart values overlay under the `external-dns:` key
#      (umbrella-chart convention — the dependency name from Chart.yaml is
#      the values namespace).
#   3. Catalyst overlay values consumed by templates/ (e.g. `externalDns:`
#      governs templates/networkpolicy.yaml + ServiceMonitor + ExternalSecret).
#
# Per docs/INVIOLABLE-PRINCIPLES.md #4 (never hardcode), every operationally-
# meaningful value is configurable; cluster overlays in clusters/<sovereign>/
# may override any of these without rebuilding the Blueprint OCI artifact.

catalystBlueprint:
  upstream:
    chart: external-dns
    version: "1.15.2"
    repo: "https://kubernetes-sigs.github.io/external-dns/"
    # Catalyst rationale for this upstream:
    # - kubernetes-sigs is the canonical publisher
    # - 1.15.x line — last release validated against Kubernetes 1.31
    # - Native `pdns` provider speaks PowerDNS REST API directly (no
    #   sidecar shim) — pairs with the in-cluster bp-powerdns Service
    #   and the powerdns-api-credentials Secret it creates
    # - Apache-2.0 licence

# ─── Upstream chart values (subchart key: external-dns) ───────────────────
# `helm dependency build` resolves the upstream as a subchart; values here
# under the `external-dns:` key flow into that subchart unchanged.
external-dns:
  # Native PowerDNS provider — talks to the in-cluster bp-powerdns Service
  # (powerdns.openova-system.svc.cluster.local:8081) over the REST API.
  # Per the user-facing brief: PowerDNS webhook adapter or native `pdns`
  # provider — the native one ships in upstream 0.15.x and avoids running
  # a separate webhook sidecar for the OpenOva-managed PowerDNS path.
  # Per-Sovereign cluster overlays MAY replace this with `provider: webhook`
  # plus the Catalyst Dynadot webhook (platform/external-dns/policies/
  # dynadot-multi-domain.yaml) when the Sovereign owns Dynadot-registered
  # apex zones.
  provider:
    name: pdns

  # Extra args drive the native `pdns` provider. Per-Sovereign overlays
  # MAY replace --pdns-server with the cross-cluster hostname when
  # ExternalDNS runs on a node that doesn't co-locate PowerDNS.
  #
  # The bp-powerdns chart creates the `powerdns` Service in the
  # `powerdns` namespace exposing the webserver on port 8081.
  # ExternalDNS resolves that across-namespace via the FQDN.
  # NOTE: --pdns-api-version is NOT a valid flag for external-dns v0.15.1
  # native pdns provider — it causes `unknown long flag '--pdns-api-version'`
  # fatal on start. The provider auto-negotiates the API version. Removed.
  #
  # --request-timeout=120s — bumps the apiserver client RequestTimeout from
  # the upstream default of 30s. On every fresh Sovereign provision the
  # k3s apiserver is CPU-saturated for the first ~5 minutes (catalyst-api
  # kubeconfig PUT, Flux bootstrap, all 38 HelmReleases reconciling
  # concurrently). With the 30s default external-dns crashloops 10+ times
  # with `level=fatal msg="failed to sync *v1.Pod: context deadline exceeded"`
  # before the initial cluster cache sync completes. 120s lets the first
  # sync finish cleanly. Caught live on otech43–46.
  extraArgs:
    - --pdns-server=http://powerdns.powerdns.svc.cluster.local:8081
    - --request-timeout=120s

  # API key for the PowerDNS REST API — read from the `powerdns-api-
  # credentials` Secret rendered by bp-powerdns (templates/api-credentials-
  # secret.yaml). The native provider reads it from the
  # EXTERNAL_DNS_PDNS_API_KEY env var.
  #
  # Per-Sovereign overlays MAY override `secretKeyRef.name` when the
  # Secret is materialized by ExternalSecret/Crossplane from OpenBao
  # (templates/externalsecret.yaml in this chart) instead of being
  # rendered inline by bp-powerdns.
  env:
    - name: EXTERNAL_DNS_PDNS_API_KEY
      valueFrom:
        secretKeyRef:
          name: powerdns-api-credentials
          key: api-key

  # Sources — Service + Ingress per the user-facing brief. Gateway-API
  # sources (httproute, grpcroute, tlsroute) MAY be added by a per-Sovereign
  # overlay once Cilium Gateway is the chosen ingress on that cluster.
  sources:
    - service
    - ingress

  # `sync` policy — ExternalDNS owns the record set. Stale records on
  # resource removal are deleted, NOT left dangling. (Brief: policy: sync.)
  policy: sync

  # TXT-record ownership — must be unique per host cluster so two clusters
  # don't fight over the same record set. Per-Sovereign overlays SET this
  # to the Sovereign FQDN (e.g. "omantel.omani.works") so each Sovereign
  # owns its own ownership state.
  registry: txt
  txtOwnerId: openova
  txtPrefix: "_externaldns."

  # Domain filters — empty by default per the user-facing brief.
  # Per-Sovereign overlays write the zone list (e.g.
  # ["openova.io", "omantel.omani.works"]) at apply time.
  domainFilters: []

  # Resources — modest defaults for the per-cluster controller.
  resources:
    requests:
      cpu: 50m
      memory: 64Mi
    limits:
      cpu: 200m
      memory: 256Mi

  # ServiceMonitor — DEFAULT FALSE per the observability-toggle rule for
  # the bp-* family. Per-Sovereign overlays flip this on once Prometheus
  # Operator is installed on the cluster.
  serviceMonitor:
    enabled: false

  # Single replica — ExternalDNS uses leader election internally and the
  # workload is IO-bound on the DNS API, not CPU-bound.
  replicas: 1

  # ─── Probes — bumped initialDelaySeconds for cold-cluster cache-sync ────
  # Issue #700: external-dns has TWO timeouts. `RequestTimeout` (per-API-call,
  # bumped to 120s above via --request-timeout in extraArgs) covers individual
  # apiserver calls. The OTHER one is `WaitForCacheSync` — a HARDCODED 60s in
  # the upstream binary, NOT exposed as a flag. On a freshly-provisioned
  # Sovereign the k3s apiserver is CPU-saturated for the first ~2 min while
  # catalyst-api/Flux/all 38 HelmReleases reconcile concurrently; the initial
  # informer cache sync misses 60s → `fatal: failed to sync *v1.Node: context
  # deadline exceeded` → kubelet restarts the Pod → repeat 5–10 times until
  # apiserver settles. Caught live on otech49+ (2026-05-03).
  #
  # Fix: bump livenessProbe.initialDelaySeconds from upstream default 10s to
  # 180s (3 min) so kubelet does NOT restart the Pod while the initial cache
  # sync is in flight. The Sovereign apiserver reaches steady-state within
  # ~2 min, so 3 min comfortably covers cold starts. Once cache-sync completes
  # external-dns becomes a steady-state IO-bound process; periodSeconds=30 +
  # failureThreshold=3 still kills genuinely hung pods within ~90s.
  #
  # Helm overrides replace whole maps (not merge), so we MUST preserve the
  # upstream `httpGet.path: /healthz` + `port: http` shape.
  livenessProbe:
    httpGet:
      path: /healthz
      port: http
    initialDelaySeconds: 180
    periodSeconds: 30
    timeoutSeconds: 5
    failureThreshold: 3
    successThreshold: 1
  readinessProbe:
    httpGet:
      path: /healthz
      port: http
    initialDelaySeconds: 30
    periodSeconds: 15
    timeoutSeconds: 5
    failureThreshold: 3
    successThreshold: 1

  # RBAC — ExternalDNS needs read on Service/Ingress; cluster-scoped.
  rbac:
    create: true

  # Service account — ExternalDNS handles its own SA creation by default.
  serviceAccount:
    create: true
    name: external-dns

# ─── Catalyst overlay values (consumed by templates/ in this chart) ──────
# Knobs for the Catalyst-curated NetworkPolicy + ServiceMonitor +
# ExternalSecret rendered by templates/. Per INVIOLABLE-PRINCIPLES #4
# everything here is runtime-configurable; cluster overlays MAY override
# without rebuilding the Blueprint OCI artifact.
externalDns:
  # NetworkPolicy — locks the ExternalDNS pod down to: egress to the
  # in-cluster powerdns Service + DNS resolution + cluster API. Default
  # ON; per-Sovereign overlays MAY disable for debugging.
  networkPolicy:
    enabled: true
    # The egress allowlist resolves PowerDNS by namespace + Service name.
    # bp-powerdns deploys into the `powerdns` namespace (PR #556/#553).
    # Was incorrectly defaulted to `openova-system` — fixes issue #569.
    powerdnsNamespace: powerdns
    powerdnsServiceName: powerdns
    powerdnsApiPort: 8081

    # Companion CiliumNetworkPolicy that grants egress to the
    # `kube-apiserver` reserved Cilium entity. REQUIRED on Cilium —
    # see templates/ciliumnetworkpolicy.yaml header for the full
    # diagnosis (issue #770).
    #
    # Short version: the vanilla NetworkPolicy egress rule
    # `to: ipBlock: 0.0.0.0/0 ports: 443,6443` does NOT match traffic
    # to the kube-apiserver under Cilium with the default
    # `policy-cidr-match-mode: ""`. Cilium models the apiserver as a
    # reserved identity, not a CIDR range, so the ipBlock rule is
    # bypassed and the apiserver call is dropped. Without this CNP,
    # ExternalDNS fails its initial `*v1.Endpoints` informer cache
    # sync on every fresh Sovereign provision with:
    #   fatal: failed to sync *v1.Endpoints: context deadline exceeded
    # …and crashloops indefinitely.
    #
    # Default TRUE because Cilium is the canonical CNI per ADR-0001.
    # Cluster overlays running on a non-Cilium CNI (none today) MAY
    # set this to false; the vanilla NetworkPolicy 0.0.0.0/0 rule
    # covers them.
    ciliumApiserverEntity:
      enabled: true

  # ServiceMonitor (Catalyst overlay variant) — ALSO default FALSE per the
  # observability-toggle rule. The upstream subchart's ServiceMonitor block
  # above governs scraping of external-dns itself; this Catalyst-side
  # ServiceMonitor template is reserved for any auxiliary metrics endpoints
  # (e.g. webhook sidecars) that future per-Sovereign overlays may add.
  serviceMonitor:
    enabled: false
    interval: 30s
    namespace: ""

  # ExternalSecret — Phase 2+ target state pulls the PowerDNS API key from
  # OpenBao via the Catalyst ClusterSecretStore. DEFAULT FALSE — Phase 0
  # uses the inline Secret rendered by bp-powerdns. When OpenBao is
  # provisioned on the Sovereign and external-secrets-operator is running,
  # the operator flips this on.
  externalSecret:
    enabled: false
    # OpenBao path that holds the PowerDNS API key, populated by
    # pool-domain-manager / catalyst-api at zone-creation time. The path
    # MUST match the Vault/OpenBao layout documented in
    # docs/PLATFORM-OPENBAO.md.
    refreshInterval: 1h
    secretStoreRef:
      name: openbao
      kind: ClusterSecretStore
    target:
      name: powerdns-api-credentials
    data:
      - secretKey: api-key
        remoteRef:
          # Operator-overridable — per-Sovereign Composition writes the
          # actual remoteKey at apply time.
          key: "secret/data/sovereign/powerdns"
          property: api-key
