chore: refined control script

This commit is contained in:
2026-07-21 16:53:15 +01:00
parent aa3ea39ddf
commit 7ebd02f6b8
15 changed files with 144 additions and 30 deletions
+20 -6
View File
@@ -14,15 +14,29 @@ resource "hcloud_zone" "this" {
}
}
resource "hcloud_zone_rrset" "a" {
for_each = { for r in var.records : "${r.zone}/${r.name}" => r }
locals {
# Group flat var.records entries by zone/name/type into one set of values
# each, since a Hetzner RRSet is keyed on (zone, name, type) and can hold
# several values (e.g. an SPF and a google-site-verification TXT both live
# under the same "@" TXT RRSet).
rrsets = {
for key, items in { for r in var.records : "${r.zone}/${r.name}/${r.type}" => r... } : key => {
zone = items[0].zone
name = items[0].name
type = items[0].type
ttl = items[0].ttl
values = [for i in items : i.value]
}
}
}
resource "hcloud_zone_rrset" "this" {
for_each = local.rrsets
zone = hcloud_zone.this[each.value.zone].id
name = each.value.name
type = "A"
type = each.value.type
ttl = each.value.ttl
records = [
{ value = each.value.value }
]
records = [for v in each.value.values : { value = v }]
}
+60
View File
@@ -0,0 +1,60 @@
# Generalizing hcloud_zone_rrset.a (for_each keyed "zone/name", A records
# only) into hcloud_zone_rrset.this (keyed "zone/name/type", any record type)
# changed every existing instance's resource address. Without these, `tofu
# apply` would destroy and recreate every A record already in state instead of
# just adding the new mail records - these moved blocks make it a no-op rename
# for anything that already existed. Safe to delete once applied and merged.
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/@"]
to = hcloud_zone_rrset.this["luke-else.co.uk/@/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/dev"]
to = hcloud_zone_rrset.this["luke-else.co.uk/dev/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/metarius"]
to = hcloud_zone_rrset.this["luke-else.co.uk/metarius/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/traefik"]
to = hcloud_zone_rrset.this["luke-else.co.uk/traefik/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/status"]
to = hcloud_zone_rrset.this["luke-else.co.uk/status/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/bitwarden"]
to = hcloud_zone_rrset.this["luke-else.co.uk/bitwarden/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/rd"]
to = hcloud_zone_rrset.this["luke-else.co.uk/rd/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/git"]
to = hcloud_zone_rrset.this["luke-else.co.uk/git/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/traefik.cicd"]
to = hcloud_zone_rrset.this["luke-else.co.uk/traefik.cicd/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/vpn"]
to = hcloud_zone_rrset.this["luke-else.co.uk/vpn/A"]
}
moved {
from = hcloud_zone_rrset.a["luke-else.co.uk/traefik.vpn"]
to = hcloud_zone_rrset.this["luke-else.co.uk/traefik.vpn/A"]
}
+10 -1
View File
@@ -4,11 +4,20 @@ variable "zone_names" {
}
variable "records" {
description = "A records to create across the zones in var.zone_names. Use name = \"@\" for the zone apex."
description = <<-EOT
Records to create across the zones in var.zone_names. Use name = "@" for
the zone apex. Entries sharing the same zone/name/type become a single
Hetzner RRSet with multiple values (e.g. two TXT strings under the same
name) - Hetzner has no concept of separate same-type records otherwise.
For MX, embed the priority in value using standard zonefile syntax (e.g.
"10 mail.example.com."); Hetzner's API has no separate priority field.
For TXT, wrap value in escaped double quotes (e.g. "\"v=spf1 ...\"").
EOT
type = list(object({
zone = string
name = string
value = string
type = optional(string, "A")
ttl = optional(number, 300)
}))
default = []