From 43ccdaac9ad7148a94b6f038402157f1802a386a Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sun, 24 Mar 2024 13:38:36 -0700 Subject: [PATCH] feat(tf): generate records --- ci/generate.sh | 1 + generate.nix | 37 +++++++- systems/freeipa/default.nix | 2 + systems/freepbx/default.nix | 3 + systems/reisen/systems.json | 159 +++++++++++++++++++++++++++++++++++ tf/cloudflare_records.tf | 31 +++---- tf/proxmox_reisen.tf | 3 +- tf/system/records/records.tf | 55 +++++++++++- 8 files changed, 266 insertions(+), 25 deletions(-) create mode 100644 systems/reisen/systems.json diff --git a/ci/generate.sh b/ci/generate.sh index 57f24c03..971dcbb4 100644 --- a/ci/generate.sh +++ b/ci/generate.sh @@ -3,6 +3,7 @@ set -eu for node in reisen; do nix eval --json "${NF_CONFIG_ROOT}#lib.generate.$node.users" | jq -M . > "$NF_CONFIG_ROOT/systems/$node/users.json" + nix eval --json "${NF_CONFIG_ROOT}#lib.generate.$node.systems" | jq -M . > "$NF_CONFIG_ROOT/systems/$node/systems.json" done for ciconfig in "${NF_CONFIG_FILES[@]}"; do diff --git a/generate.nix b/generate.nix index d77c0139..a58049c1 100644 --- a/generate.nix +++ b/generate.nix @@ -3,8 +3,10 @@ tree, }: let nixlib = inputs.nixpkgs.lib; - inherit (nixlib.attrsets) filterAttrs mapAttrsToList; - inherit (nixlib.lists) sortOn; + inherit (nixlib.attrsets) mapAttrs filterAttrs mapAttrsToList; + inherit (nixlib.lists) elem sortOn; + inherit (nixlib.strings) removeSuffix; + inherit (nixlib.trivial) mapNullable warn; inherit (inputs.self.lib.lib) userIs; templateSystem = inputs.self.nixosConfigurations.reimu; templateUsers = filterAttrs (_: userIs "peeps") templateSystem.config.users.users; @@ -16,8 +18,39 @@ inherit (user) name uid; authorizedKeys = user.openssh.authorizedKeys.keys; }; + nodeSystems = let + matchesNode = nodeName: system: system.config.proxmox.enabled && system.config.proxmox.node.name == nodeName; + in nodeName: filterAttrs (_: matchesNode nodeName) inputs.self.lib.systems; + mkNodeSystem = system: { + network = let + inherit (system.config.proxmox) network; + inherit (network) internal; + inherit (network.interfaces) net0; + mapAddress6 = prefix: interface: + if interface.address6 == "dhcp" then null + else if interface.address6 == "auto" then "${prefix}${interface.slaac.postfix}" + else mapNullable (removeSuffix "/64") interface.address6; + mapAddress4 = interface: + if elem interface.address4 [ "dhcp" "auto" ] then null + else mapNullable (removeSuffix "/24") interface.address4; + in { + int = if internal.interface != null then { + inherit (internal.interface) macAddress; + address6 = mapAddress6 "fd0c::" internal.interface; + address4 = mapAddress4 internal.interface; + } else null; + local = if network.interfaces.net0.bridge or null == "vmbr0" then { + inherit (net0) macAddress; + address6 = mapAddress6 "fd0a::" net0; + address4 = mapAddress4 net0; + } else null; + tail = warn "TODO: generate network.tail" null; + }; + }; + mkNodeSystems = systems: mapAttrs (_: mkNodeSystem) systems; mkNode = {name}: { users = mkNodeUsers templateUsers; + systems = mkNodeSystems (nodeSystems name); }; in { reisen = mkNode {name = "reisen";}; diff --git a/systems/freeipa/default.nix b/systems/freeipa/default.nix index fd1281d6..995bc7ba 100644 --- a/systems/freeipa/default.nix +++ b/systems/freeipa/default.nix @@ -9,6 +9,8 @@ _: { net0 = { name = "ens18"; macAddress = "BC:24:11:3D:39:91"; + address4 = "10.1.1.46/24"; + address6 = "auto"; }; net1.internal.enable = true; }; diff --git a/systems/freepbx/default.nix b/systems/freepbx/default.nix index b7138b6c..1209b1da 100644 --- a/systems/freepbx/default.nix +++ b/systems/freepbx/default.nix @@ -7,7 +7,10 @@ _: { }; network.interfaces = { net0 = { + name = "ens18"; macAddress = "BC:24:11:33:19:04"; + address4 = "dhcp"; + address6 = "auto"; }; }; }; diff --git a/systems/reisen/systems.json b/systems/reisen/systems.json new file mode 100644 index 00000000..9a1aa5cc --- /dev/null +++ b/systems/reisen/systems.json @@ -0,0 +1,159 @@ +{ + "aya": { + "network": { + "int": { + "address4": "10.9.1.73", + "address6": "fd0c::49", + "macAddress": "BC:24:19:C4:66:A9" + }, + "local": { + "address4": "10.1.1.47", + "address6": "fd0a::be24:11ff:fec4:66a9", + "macAddress": "BC:24:11:C4:66:A9" + }, + "tail": null + } + }, + "freeipa": { + "network": { + "int": { + "address4": "10.9.1.170", + "address6": "fd0c::aa", + "macAddress": "BC:24:19:3D:39:91" + }, + "local": { + "address4": "10.1.1.46", + "address6": "fd0a::be24:11ff:fe3d:3991", + "macAddress": "BC:24:11:3D:39:91" + }, + "tail": null + } + }, + "freepbx": { + "network": { + "int": null, + "local": { + "address4": null, + "address6": "fd0a::be24:11ff:fe33:1904", + "macAddress": "BC:24:11:33:19:04" + }, + "tail": null + } + }, + "hakurei": { + "network": { + "int": { + "address4": "10.9.1.71", + "address6": "fd0c::47", + "macAddress": "BC:24:19:C4:66:A7" + }, + "local": { + "address4": "10.1.1.41", + "address6": "fd0a::be24:11ff:fec4:66a7", + "macAddress": "BC:24:11:C4:66:A7" + }, + "tail": null + } + }, + "keycloak": { + "network": { + "int": { + "address4": "10.9.1.75", + "address6": "fd0c::4b", + "macAddress": "BC:24:19:C4:66:AC" + }, + "local": { + "address4": "10.1.1.48", + "address6": "fd0a::be24:11ff:fec4:66ac", + "macAddress": "BC:24:11:C4:66:AC" + }, + "tail": null + } + }, + "kuwubernetes": { + "network": { + "int": null, + "local": { + "address4": "10.1.1.42", + "address6": "fd0a::be24:11ff:fe49:fedc", + "macAddress": "BC:24:11:49:FE:DC" + }, + "tail": null + } + }, + "litterbox": { + "network": { + "int": { + "address4": "10.9.1.74", + "address6": "fd0c::4a", + "macAddress": "BC:24:19:C4:66:AB" + }, + "local": { + "address4": null, + "address6": "fd0a::be24:11ff:fec4:66ab", + "macAddress": "BC:24:11:C4:66:AB" + }, + "tail": null + } + }, + "mediabox": { + "network": { + "int": { + "address4": "10.9.1.70", + "address6": "fd0c::46", + "macAddress": "BC:24:19:34:F4:A8" + }, + "local": { + "address4": "10.1.1.44", + "address6": "fd0a::be24:11ff:fe34:f4a8", + "macAddress": "BC:24:11:34:F4:A8" + }, + "tail": null + } + }, + "reimu": { + "network": { + "int": { + "address4": "10.9.1.72", + "address6": "fd0c::48", + "macAddress": "BC:24:19:C4:66:A8" + }, + "local": { + "address4": "10.1.1.45", + "address6": "fd0a::be24:11ff:fec4:66a8", + "macAddress": "BC:24:11:C4:66:A8" + }, + "tail": null + } + }, + "tei": { + "network": { + "int": { + "address4": "10.9.1.69", + "address6": "fd0c::45", + "macAddress": "BC:24:19:CC:66:57" + }, + "local": { + "address4": "10.1.1.39", + "address6": "fd0a::be24:11ff:fecc:6657", + "macAddress": "BC:24:11:CC:66:57" + }, + "tail": null + } + }, + "utsuho": { + "network": { + "int": { + "address4": "10.9.1.76", + "address6": "fd0c::4c", + "macAddress": "BC:24:19:C4:66:A6" + }, + "local": { + "address4": "10.1.1.38", + "address6": "fd0a::be24:11ff:fec4:66a6", + "macAddress": "BC:24:11:C4:66:A6" + }, + "tail": null + } + } +} diff --git a/tf/cloudflare_records.tf b/tf/cloudflare_records.tf index 2a0a9a75..230dc35f 100644 --- a/tf/cloudflare_records.tf +++ b/tf/cloudflare_records.tf @@ -4,6 +4,8 @@ module "reisen_system_records" { zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone local_v4 = "10.1.1.40" + int_v4 = "10.9.1.2" + int_v6 = "fd0c::2" } module "hakurei_system_records" { @@ -11,10 +13,9 @@ module "hakurei_system_records" { name = "hakurei" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone + net_data = local.proxmox_reisen_systems.hakurei.network tailscale_v4 = "100.71.65.59" tailscale_v6 = "fd7a:115c:a1e0::9187:413b" - local_v4 = "10.1.1.41" - local_v6 = "fd0a::be24:11ff:fec4:66a7" local_subdomains = [ "prox", "id", @@ -49,9 +50,9 @@ module "reimu_system_records" { name = "reimu" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone + net_data = local.proxmox_reisen_systems.reimu.network tailscale_v4 = "100.113.253.48" tailscale_v6 = "fd7a:115c:a1e0::f1b1:fd30" - local_v6 = "fd0a::be24:11ff:fec4:66a8" local_subdomains = [ "nfs", ] @@ -62,8 +63,7 @@ module "keycloak_system_records" { name = "keycloak" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v4 = "10.1.1.48" - local_v6 = "fd0a::be24:11ff:fec4:66ac" + net_data = local.proxmox_reisen_systems.keycloak.network } module "utsuho_system_records" { @@ -71,8 +71,7 @@ module "utsuho_system_records" { name = "utsuho" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v4 = "10.1.1.38" - local_v6 = "fd0a::be24:11ff:fec4:66a6" + net_data = local.proxmox_reisen_systems.utsuho.network } module "aya_system_records" { @@ -80,10 +79,9 @@ module "aya_system_records" { name = "aya" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone + net_data = local.proxmox_reisen_systems.aya.network tailscale_v4 = "100.109.213.94" tailscale_v6 = "fd7a:115c:a1e0::eaed:d55e" - local_v4 = "10.1.1.47" - local_v6 = "fd0a::be24:11ff:fec4:66a9" local_subdomains = [ "nixbld", ] @@ -94,10 +92,9 @@ module "tewi_system_records" { name = "tei" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone + net_data = local.proxmox_reisen_systems.tei.network tailscale_v4 = "100.74.104.29" tailscale_v6 = "fd7a:115c:a1e0::fd8a:681d" - local_v4 = "10.1.1.39" - local_v6 = "fd0a::be24:11ff:fecc:6657" local_subdomains = [ "mqtt", "postgresql", @@ -109,8 +106,7 @@ module "mediabox_system_records" { name = "mediabox" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v4 = "10.1.1.44" - local_v6 = "fd0a::be24:11ff:fe34:f4a8" + net_data = local.proxmox_reisen_systems.mediabox.network local_subdomains = [ "plex", ] @@ -121,7 +117,7 @@ module "litterbox_system_records" { name = "litterbox" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v6 = "fd0a::be24:11ff:fec4:66ab" + net_data = local.proxmox_reisen_systems.litterbox.network } module "idp_system_records" { @@ -129,8 +125,7 @@ module "idp_system_records" { name = "idp" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v4 = "10.1.1.46" - local_v6 = "fd0a::be24:11ff:fe3d:3991" + net_data = local.proxmox_reisen_systems.freeipa.network } module "kubernetes_system_records" { @@ -138,7 +133,7 @@ module "kubernetes_system_records" { name = "kubernetes" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v6 = "fd0a::be24:11ff:fe49:fedc" + net_data = local.proxmox_reisen_systems.kuwubernetes.network } module "freepbx_system_records" { @@ -146,7 +141,7 @@ module "freepbx_system_records" { name = "freepbx" zone_id = cloudflare_zone.gensokyo-zone_zone.id zone_zone = cloudflare_zone.gensokyo-zone_zone.zone - local_v6 = "fd0a::be24:11ff:fe33:1904" + net_data = local.proxmox_reisen_systems.freepbx.network } module "kitchencam_system_records" { diff --git a/tf/proxmox_reisen.tf b/tf/proxmox_reisen.tf index 7690d564..9c2869c7 100644 --- a/tf/proxmox_reisen.tf +++ b/tf/proxmox_reisen.tf @@ -16,7 +16,8 @@ locals { proxmox_reisen_udev_dri = file("${path.root}/../systems/reisen/udev.90-dri.rules") proxmox_reisen_udev_z2m = file("${path.root}/../systems/reisen/udev.90-z2m.rules") - proxmox_reisen_users = jsondecode(file("${path.root}/../systems/reisen/users.json")) + proxmox_reisen_users = jsondecode(file("${path.root}/../systems/reisen/users.json")) + proxmox_reisen_systems = jsondecode(file("${path.root}/../systems/reisen/systems.json")) } resource "terraform_data" "proxmox_reisen_etc" { diff --git a/tf/system/records/records.tf b/tf/system/records/records.tf index 5999c910..03d560f5 100644 --- a/tf/system/records/records.tf +++ b/tf/system/records/records.tf @@ -10,6 +10,15 @@ variable "name" { type = string } +variable "net_data" { + type = map(map(any)) + default = { + local = null + int = null + tail = null + } +} + variable "tailscale_name" { type = string default = null @@ -25,6 +34,21 @@ variable "tailscale_v6" { default = null } +variable "int_name" { + type = string + default = null +} + +variable "int_v4" { + type = string + default = null +} + +variable "int_v6" { + type = string + default = null +} + variable "local_name" { type = string default = null @@ -57,20 +81,39 @@ variable "global_v6" { locals { local_name = coalesce(var.local_name, "${var.name}.local") + local_net = coalesce(var.net_data.local, local.empty_net) + local_v4 = coalesce(var.local_v4, local.local_net.address4, local.empty_address) + local_v6 = coalesce(var.local_v6, local.local_net.address6, local.empty_address) + int_name = coalesce(var.int_name, "${var.name}.int") + int_net = coalesce(var.net_data.int, local.empty_net) + int_v4 = coalesce(var.int_v4, local.int_net.address4, local.empty_address) + int_v6 = coalesce(var.int_v6, local.int_net.address6, local.empty_address) tailscale_name = coalesce(var.tailscale_name, "${var.name}.tail") + tailscale_net = coalesce(var.net_data.tail, local.empty_net) + tailscale_v4 = coalesce(var.tailscale_v4, local.tailscale_net.address4, local.empty_address) + tailscale_v6 = coalesce(var.tailscale_v6, local.tailscale_net.address6, local.empty_address) global_name = coalesce(var.global_name, var.name) has_tailscale = var.tailscale_v4 != null || var.tailscale_v6 != null + empty_address = "EMPTY" + empty_net = { + address4 = null + address6 = null + } a_records = [ { name = local.local_name, - value = var.local_v4, + value = local.local_v4, }, { name = local.global_name, value = var.global_v4, }, + { + name = local.int_name, + value = local.int_v4, + }, { name = local.tailscale_name, value = var.tailscale_v4, @@ -80,12 +123,16 @@ locals { aaaa_records = [ { name = local.local_name, - value = var.local_v6, + value = local.local_v6, }, { name = local.global_name, value = var.global_v6, }, + { + name = local.int_name, + value = local.int_v6, + }, { name = local.tailscale_name, value = var.tailscale_v6, @@ -94,7 +141,7 @@ locals { } resource "cloudflare_record" "a_records" { - for_each = { for i, a in local.a_records : a.name => i if a.value != null } + for_each = { for i, a in local.a_records : a.name => i if a.value != null && a.value != local.empty_address } name = local.a_records[each.value].name proxied = false ttl = 3600 @@ -104,7 +151,7 @@ resource "cloudflare_record" "a_records" { } resource "cloudflare_record" "aaaa_records" { - for_each = { for i, aaaa in local.aaaa_records : aaaa.name => i if aaaa.value != null } + for_each = { for i, aaaa in local.aaaa_records : aaaa.name => i if aaaa.value != null && aaaa.value != local.empty_address } name = local.aaaa_records[each.value].name proxied = false ttl = 3600