From 19fb650b8dba484a425855ebf76856b46f6b5c3b Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Fri, 21 Aug 2026 20:36:53 +0200 Subject: [PATCH] infra: remove stale old kube files, infra/kube is new truth --- infra/p330/kube/main.tf | 187 ------------- infra/p330/kube/variables.tf | 96 ------- infra/r740/kube/main.tf | 365 ------------------------- infra/r740/kube/values/components.yaml | 34 --- infra/r740/kube/variables.tf | 16 -- infra/rpi4/kube/main.tf | 223 --------------- infra/rpi4/kube/variables.tf | 146 ---------- 7 files changed, 1067 deletions(-) delete mode 100644 infra/p330/kube/main.tf delete mode 100644 infra/p330/kube/variables.tf delete mode 100644 infra/r740/kube/main.tf delete mode 100644 infra/r740/kube/values/components.yaml delete mode 100644 infra/r740/kube/variables.tf delete mode 100644 infra/rpi4/kube/main.tf delete mode 100644 infra/rpi4/kube/variables.tf diff --git a/infra/p330/kube/main.tf b/infra/p330/kube/main.tf deleted file mode 100644 index 99ba70e..0000000 --- a/infra/p330/kube/main.tf +++ /dev/null @@ -1,187 +0,0 @@ -# Talos node for the P330 — joins the r740 "kube" cluster. -terraform { - required_providers { - talos = { - source = "siderolabs/talos" - version = "0.9.0" - } - null = { - source = "hashicorp/null" - version = "3.2.3" - } - } -} - -# Read the r740 kube module state to reuse the cluster secrets & endpoint. -# The r740 module exposes: client_configuration, machine_secrets, cluster_name, -# cluster_endpoint, kube_host. -data "terraform_remote_state" "r740_kube" { - backend = var.r740_backend - - config = var.r740_backend == "local" ? { - path = "${var.r740_state_path}/terraform.tfstate" - } : var.r740_backend_config -} - -locals { - cluster_name = data.terraform_remote_state.r740_kube.outputs.cluster_name - cluster_endpoint = data.terraform_remote_state.r740_kube.outputs.cluster_endpoint - machine_secrets = data.terraform_remote_state.r740_kube.outputs.machine_secrets - client_config = data.terraform_remote_state.r740_kube.outputs.client_configuration - - # kubeconfig produced by the r740 kube module — used to wait for the node and - # apply labels. There is no in-tree kubernetes provider here on - # purpose: managing a `kubernetes_node` resource conflicts with the node - # object that kubelet itself creates, so we use a null_resource with kubectl - # to wait + label idempotently. - kubeconfig_path = "${var.r740_state_path}/kubeconfig" - - # Network config: static if node_subnet is provided, otherwise Talos DHCPs. - static_network = var.node_subnet == null ? {} : { - interfaces = [{ - interface = var.network_interface - addresses = [var.node_subnet] - routes = var.node_gateway == null ? [] : [{ gateway = var.node_gateway }] - }] - } - - network_patch = { - nameservers = var.nameservers - } - network_patch_merged = merge(local.network_patch, local.static_network) - - machine_patch = { - install = { - image = var.installer_image - disk = var.install_disk - } - network = merge(local.network_patch_merged, { - # Pin the Kubernetes node name. Talos otherwise auto-generates a hostname - # (e.g. "talos-8ec-vd1"), so the node registers with that random name - # instead of var.p330_node_name — and our label null_resource waits - # for the wrong node. Setting machine.network.hostname fixes the node name. - hostname = var.p330_node_name - }) - # Kernel modules required by Longhorn (iSCSI + ext4) — must match the - # control-plane nodes so Longhorn can schedule replicas on the failover node. - kernel = { - modules = [ - { name = "iscsi_tcp" }, - { name = "libiscsi" }, - { name = "scsi_transport_iscsi" }, - { name = "ext4" }, - ] - } - sysctls = { - "fs.inotify.max_user_instances" = "1024" - "fs.inotify.max_user_watches" = "1048576" - } - } -} - -# Control-plane machine configuration. machine_type = "controlplane" makes -# Talos generate a join config that runs the apiserver/controller-manager/ -# scheduler AND joins the existing etcd cluster as a new member (the cluster -# was already bootstrapped by the r740 module's talos_machine_bootstrap). -data "talos_machine_configuration" "p330" { - cluster_name = local.cluster_name - machine_type = "controlplane" - cluster_endpoint = local.cluster_endpoint - machine_secrets = local.machine_secrets - config_patches = [ - yamlencode({ - machine = local.machine_patch - }), - yamlencode({ - cluster = { - network = { - cni = { - name = "none" - } - } - } - }) - ] -} - -# Rendered config is written to disk so it can also be applied manually with -# `talosctl apply-config --nodes --file p330.yaml` if needed. -resource "local_file" "p330_machine_config" { - filename = "${path.module}/p330.yaml" - content = data.talos_machine_configuration.p330.machine_configuration -} - -# Apply the machine config to the running (maintenance-mode) node over the -# Talos API. Because the config patch contains a `machine.install` block, when -# Talos receives this config on a node booted from the USB (maintenance) image -# it installs itself to install.disk and reboots into the installed system. -# For a controlplane node it then joins the existing etcd cluster as a new -# member and runs the control-plane components; for a worker it just registers -# via kubelet. -resource "talos_machine_configuration_apply" "p330" { - client_configuration = local.client_config - machine_configuration_input = data.talos_machine_configuration.p330.machine_configuration - node = var.p330_host - depends_on = [local_file.p330_machine_config] -} - -# Emit a talosconfig scoped to this node for ad-hoc `talosctl` use. -data "talos_client_configuration" "p330" { - cluster_name = local.cluster_name - client_configuration = local.client_config - nodes = [var.p330_host] -} - -resource "local_file" "talosconfig" { - content = data.talos_client_configuration.p330.talos_config - filename = "${path.module}/talosconfig" - depends_on = [data.talos_client_configuration.p330] -} - -# Wait for the node to register with Kubernetes (kubelet creates the Node -# object after Talos installs and reboots), then label it. This is idempotent: -# kubectl exits 0 if the label already exists. -resource "null_resource" "p330_node_label" { - triggers = { - node = var.p330_node_name - kubeconfig = local.kubeconfig_path - } - - provisioner "local-exec" { - # Wait for the node to show up, then label. The wait loop is bounded - # by kubectl --timeout; tune it via TF_LOG / re-run if the node is slow to - # join (a controlplane node must first complete the etcd join handshake). - command = <<-EOT - set -euo pipefail - KUBECONFIG="${local.kubeconfig_path}" - export KUBECONFIG - NODE="${var.p330_node_name}" - - echo "Waiting for node $NODE to be registered (kubelet creates the Node object once Talos has installed, rebooted and joined etcd)..." - # kubectl wait --for=condition=Ready fails instantly with NotFound if the - # node object doesn't exist yet, so poll for existence first. - # /bin/sh (dash) has no $SECONDS, so count iterations with a bounded loop. - tries=240 # 240 * 5s = 20 minutes max - until kubectl get node "$NODE" >/dev/null 2>&1; do - tries=$((tries - 1)) - if [ "$tries" -le 0 ]; then - echo "Timed out waiting for node $NODE to register." >&2 - exit 1 - fi - sleep 5 - done - echo "Node $NODE registered. Waiting for it to become Ready..." - - # Now wait for Ready (a controlplane node needs etcd joined + apiserver up). - kubectl wait --for=condition=Ready "node/$NODE" --timeout=20m || \ - kubectl wait --for=jsonpath='{.status.conditions[?(@.reason=="KubeletReady")].status}'=True "node/$NODE" --timeout=20m - - # Failover marker label (applied to both controlplane and worker nodes). - kubectl label --overwrite node "$NODE" homeprod.io/failover=true - - echo "Node $NODE ready and labeled for failover scheduling." - EOT - } - - depends_on = [talos_machine_configuration_apply.p330] -} diff --git a/infra/p330/kube/variables.tf b/infra/p330/kube/variables.tf deleted file mode 100644 index 072d986..0000000 --- a/infra/p330/kube/variables.tf +++ /dev/null @@ -1,96 +0,0 @@ -# Variables for the P330 Talos worker node that joins the r740 cluster. - -variable "p330_host" { - description = "Reachable IP/hostname of the P330 Talos node (for Talos API access)." - type = string -} - -variable "p330_node_name" { - description = "Kubernetes/Talos node name for the P330 (e.g. p330)." - type = string - default = "p330" -} - -variable "r740_state_path" { - description = < --file rpi4.yaml` if needed. -resource "null_resource" "rpi4_machine_config_file" { - triggers = { - # Re-run only when the (non-secret) inputs that shape the config change. - node = var.rpi4_node_name - install_disk = var.install_disk - installer_image = var.installer_image - taint = "${var.quorum_taint_key}=${var.quorum_taint_value}:${var.quorum_taint_effect}" - } - - provisioner "local-exec" { - command = <<-EOT - set -euo pipefail - cat > "${path.module}/rpi4.yaml" <<'YAMLEOF' -${ephemeral.talos_machine_configuration.rpi4.machine_configuration} -YAMLEOF - echo "Wrote ${path.module}/rpi4.yaml" - EOT - } - - depends_on = [talos_machine_configuration_apply.rpi4] -} - -# --- Wait for the node, then label + taint --------------------------------- -# -# Wait for the node to register with Kubernetes (kubelet creates the Node -# object after Talos installs and reboots), then label it and (re)apply the -# quorum taint. This is idempotent: kubectl exits 0 if the label/taint already -# exists. The taint is also set via kubelet `register-with-taints`, so this -# null_resource is a safety net for manual edits / drift. The kubeconfig path -# is only used inside the provisioner (not persisted to state). -resource "null_resource" "rpi4_node_label_and_taint" { - triggers = { - node = var.rpi4_node_name - key = var.quorum_taint_key - value = var.quorum_taint_value - effect = var.quorum_taint_effect - kubeconfig = var.kubeconfig_path - } - - provisioner "local-exec" { - # Wait for the node to show up, then label + taint. The wait loop is bounded - # by kubectl --timeout; tune it via TF_LOG / re-run if the node is slow to - # join (a controlplane node must first complete the etcd join handshake). - command = <<-EOT - set -euo pipefail - KUBECONFIG="${var.kubeconfig_path}" - export KUBECONFIG - NODE="${var.rpi4_node_name}" - - echo "Waiting for node $NODE to be registered (kubelet creates the Node object once Talos has installed, rebooted and joined etcd)..." - # kubectl wait --for=condition=Ready fails instantly with NotFound if the - # node object doesn't exist yet, so poll for existence first. - # /bin/sh (dash) has no $SECONDS, so count iterations with a bounded loop. - tries=240 # 240 * 5s = 20 minutes max - until kubectl get node "$NODE" >/dev/null 2>&1; do - tries=$((tries - 1)) - if [ "$tries" -le 0 ]; then - echo "Timed out waiting for node $NODE to register." >&2 - exit 1 - fi - sleep 5 - done - echo "Node $NODE registered. Waiting for it to become Ready..." - - # Now wait for Ready (a controlplane node needs etcd joined + apiserver up). - kubectl wait --for=condition=Ready "node/$NODE" --timeout=20m || \ - kubectl wait --for=jsonpath='{.status.conditions[?(@.reason=="KubeletReady")].status}'=True "node/$NODE" --timeout=20m - - # Quorum marker + taint (applied to the controlplane node). - kubectl label --overwrite node "$NODE" homeprod.io/quorum=true - - # Apply the taint idempotently (kubectl taint --overwrite is a no-op if it exists). - kubectl taint --overwrite node "$NODE" \ - "${var.quorum_taint_key}=${var.quorum_taint_value}:${var.quorum_taint_effect}" - - echo "Node $NODE ready, labeled and tainted for quorum-only scheduling." - EOT - } - - depends_on = [talos_machine_configuration_apply.rpi4] -} diff --git a/infra/rpi4/kube/variables.tf b/infra/rpi4/kube/variables.tf deleted file mode 100644 index 657907b..0000000 --- a/infra/rpi4/kube/variables.tf +++ /dev/null @@ -1,146 +0,0 @@ -# Variables for the Raspberry Pi 4 Talos control-plane node that joins the r740 -# "kube" cluster as a third etcd member to restore quorum (2-of-3 majority). -# -# Secret handling: the cluster machine secrets (cluster id/secret, etcd/k8s -# certs, bootstrap token) are NOT read from terraform state (the r740 state is -# stale) and are NOT generated here (that would create a new, incompatible -# cluster). Instead they are provided via `machine_secrets_file` — a local, -# gitignored JSON file in the Talos provider's machine_secrets format. The -# file is produced once from the live r740 node (see -# scripts/extract-talos-secrets.sh) and stored in a real secret manager -# (Bitwarden); you paste it back to disk when running this module. Ephemeral -# resources + write-only attributes ensure the secrets never land in Terraform -# state. - -variable "rpi4_host" { - description = "Reachable IP/hostname of the rpi4 Talos node (for Talos API access). With DHCP this is the leased IP (e.g. 10.1.2.135)." - type = string -} - -variable "rpi4_node_name" { - description = "Kubernetes/Talos node name for the rpi4 (e.g. rpi4). Pinned via machine.network.hostname so the node registers with this name regardless of DHCP." - type = string - default = "rpi4" -} - -# --- Cluster identity (no terraform_remote_state — state is stale) ---------- - -variable "cluster_name" { - description = "Name of the existing Talos cluster the rpi4 joins. Must match the cluster the r740 bootstrapped (kube-r740)." - type = string - default = "kube-r740" -} - -variable "cluster_endpoint" { - description = "Endpoint (host:port) of the Talos/Kubernetes API on the cluster. Must match the r740 bootstrap endpoint." - type = string - default = "https://kube-r740.lan:6443" -} - -# --- Secrets (provided manually, never in state) --------------------------- - -variable "machine_secrets_file" { - description = <