Per docs/INVIOLABLE-PRINCIPLES.md Lesson #24 — the previous commits915c467+07b4bcfshipped bespoke Go code that called Hetzner Cloud API directly + exec'd helm/kubectl, which violates principle #3 (OpenTofu provisions Phase 0, Crossplane is the ONLY day-2 IaC, Flux is the ONLY GitOps reconciler, Blueprints are the ONLY install unit). This commit reverts all of that and replaces it with the canonical architecture. REVERTED (deleted): - products/catalyst/bootstrap/api/internal/hetzner/resources.go (379 lines bespoke Hetzner API client) - products/catalyst/bootstrap/api/internal/hetzner/cloudinit.go (bespoke cloud-init builder) - products/catalyst/bootstrap/api/internal/hetzner/provisioner.go (306 lines orchestrator) - products/catalyst/bootstrap/api/internal/bootstrap/bootstrap.go (helm-exec installer for 11 components) - products/catalyst/bootstrap/api/internal/bootstrap/exec.go (kubectl/helm exec wrappers) KEPT: - products/catalyst/bootstrap/api/internal/hetzner/client.go — fast token validity probe used by StepCredentials wizard step. NOT architectural drift; just a UX pre-flight check. - products/catalyst/bootstrap/api/internal/dynadot/dynadot.go — DNS API client. Will be invoked by the OpenTofu module via local-exec (the catalyst-dns helper binary). NEW (canonical architecture): infra/hetzner/ — OpenTofu module per docs/SOVEREIGN-PROVISIONING.md §3 Phase 0: - versions.tf: hetznercloud/hcloud provider ~> 1.49 - variables.tf: 17 typed variables matching wizard inputs (sovereign_fqdn, hcloud_token, region, control_plane_size, ssh_public_key, domain_mode, gitops_repo_url, etc.) — all runtime parameters, none hardcoded per principle #4 - main.tf: hcloud_network + subnet + firewall + ssh_key + control-plane server(s) with cloud-init + worker servers + load_balancer with services + null_resource calling /usr/local/bin/catalyst-dns for pool-domain DNS writes - outputs.tf: control_plane_ip, load_balancer_ip, sovereign_fqdn, console_url, gitops_repo_url - cloudinit-control-plane.tftpl: installs k3s with --flannel-backend=none --disable=traefik --disable=servicelb (Cilium replaces all of these), then installs Flux core, then applies a GitRepository pointing at clusters/${sovereign_fqdn}/ in the public OpenOva monorepo. From this point Flux is the GitOps engine — it reconciles bp-cilium → bp-cert-manager → bp-crossplane → ... → bp-catalyst-platform via the Kustomization tree the cluster directory ships. NO bespoke helm install from outside the cluster. NO direct kubectl apply. Flux is the install layer. - cloudinit-worker.tftpl: k3s agent join via private-IP control plane products/catalyst/bootstrap/api/internal/provisioner/provisioner.go — thin OpenTofu invoker: - Validates wizard inputs - Stages the canonical infra/hetzner/ module into a per-deployment workdir - Writes tofu.auto.tfvars.json from the wizard request - Execs `tofu init`, `tofu plan -out=tfplan`, `tofu apply tfplan`, streaming stdout/stderr lines as SSE events to the wizard - Reads tofu output -json for control_plane_ip + load_balancer_ip - Returns Result. Flux on the new cluster takes over from here. products/catalyst/bootstrap/api/internal/handler/deployments.go — rewritten: - Uses provisioner.Request and provisioner.New() (no more hetzner.Provisioner) - Same SSE/poll endpoints; same Dynadot env-var injection for pool-domain mode What this commit DOES NOT yet include (intentionally — separate work): - clusters/${sovereign_fqdn}/ Kustomization tree in the monorepo that Flux will reconcile (each Sovereign gets its own cluster directory). Tracked separately as part of the bp-catalyst-platform umbrella work. - /usr/local/bin/catalyst-dns helper binary in the catalyst-api Containerfile. Tracked as ticket [G] dns Dynadot client. - Crossplane Compositions for hcloud resources at platform/crossplane/compositions/. Tracked as part of [F] crossplane chart. Lesson #24 closed. Architecture now matches docs/ARCHITECTURE.md §10 + SOVEREIGN-PROVISIONING.md §3-§4 exactly.
28 lines
943 B
HCL
28 lines
943 B
HCL
# Outputs the catalyst-api provisioner reads after `tofu apply` completes
|
|
# and surfaces back to the wizard's success screen.
|
|
|
|
output "control_plane_ip" {
|
|
description = "Public IPv4 of the first control-plane node"
|
|
value = hcloud_server.control_plane[0].ipv4_address
|
|
}
|
|
|
|
output "load_balancer_ip" {
|
|
description = "Public IPv4 of the Hetzner load balancer (the address DNS A records point at)"
|
|
value = hcloud_load_balancer.main.ipv4
|
|
}
|
|
|
|
output "sovereign_fqdn" {
|
|
description = "Echo back the FQDN this Sovereign was provisioned for"
|
|
value = var.sovereign_fqdn
|
|
}
|
|
|
|
output "console_url" {
|
|
description = "URL where the new Sovereign's Catalyst console is reachable once Flux finishes bootstrapping"
|
|
value = "https://console.${var.sovereign_fqdn}"
|
|
}
|
|
|
|
output "gitops_repo_url" {
|
|
description = "Git URL Flux on the new cluster watches"
|
|
value = "${var.gitops_repo_url}//clusters/${var.sovereign_fqdn}"
|
|
}
|