From 6a4eb906581591043bca5e60e03970e2165a5d8c Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 13 Apr 2025 21:14:33 +0200 Subject: [PATCH] in-source tf deployment logic --- launch/.gitignore | 2 +- launch/README.md | 7 +- launch/default.nix | 2 +- launch/main.tf | 140 +++++++++++++++++++++------------ launch/module.auto.tfvars.json | 1 - launch/tf-env.nix | 12 +-- npins/sources.json | 12 --- panel/env.nix | 2 +- 8 files changed, 99 insertions(+), 79 deletions(-) delete mode 100644 launch/module.auto.tfvars.json diff --git a/launch/.gitignore b/launch/.gitignore index 42b97838..5ab952ce 100644 --- a/launch/.gitignore +++ b/launch/.gitignore @@ -1,5 +1,5 @@ .auto.tfvars.json -module.auto.tfvars.json +.npins.json .terraform/ .terraform.tfstate.lock.info terraform.tfstate* diff --git a/launch/README.md b/launch/README.md index 94cea9eb..4c24dae6 100644 --- a/launch/README.md +++ b/launch/README.md @@ -2,12 +2,13 @@ ## usage -### updating TF modules +<-- TODO: port to just --> + +### updating npins ```sh -$ npins update terraform-nixos $ cd launch/ -$ echo "{\"terraform-nixos\": $(nix-instantiate --eval --json -E '(import ../npins).terraform-nixos.outPath')}" > module.auto.tfvars.json +$ echo "$(nix eval --json -f ../npins)" > .npins.json ``` ### local development diff --git a/launch/default.nix b/launch/default.nix index 5194d628..bb96db72 100644 --- a/launch/default.nix +++ b/launch/default.nix @@ -16,7 +16,7 @@ in shell = pkgs.mkShellNoCC { packages = [ pkgs.npins - pkgs.gnugrep # used in terraform-nixos + pkgs.jaq # tf (import ./tf.nix { inherit lib pkgs; }) ]; }; diff --git a/launch/main.tf b/launch/main.tf index d620f3ac..de0cf60e 100644 --- a/launch/main.tf +++ b/launch/main.tf @@ -1,7 +1,3 @@ -variable "terraform-nixos" { - type = string -} - variable "domain" { type = string default = "fediversity.net" @@ -51,7 +47,6 @@ variable "initialUser" { } } -# TODO: could this straight-up be added in the child module instead? variable "ssh_private_key_file" { type = string description = "Path to private key used to connect to the target_host" @@ -66,11 +61,11 @@ variable "deploy_environment" { locals { system = "x86_64-linux" - pins = data.external.pins.result - peripheral_services = { + pins = jsondecode(file("${path.module}/.npins.json")) + peripheral_configs = { garage = "test01" } - applications = { + application_configs = { mastodon = { cfg = var.mastodon hostname = "test06" @@ -84,51 +79,98 @@ locals { hostname = "test03" } } - peripheral = { for name, inst in local.peripheral_services : name => { + peripherals = { for name, inst in local.peripheral_configs : name => { hostname = inst cfg = { - enable = anytrue([for _, app in local.applications: app.cfg.enable]) + enable = anytrue([for _, app in local.application_configs: app.cfg.enable]) } } } -} - -data "external" "pins" { - program = ["nix", "eval", "--json", "-f", "${path.root}/../npins"] -} - -module "deploy" { - source = "${var.terraform-nixos}//deploy_nixos" - for_each = {for name, inst in merge( - local.peripheral, - local.applications, - ) : name => inst if inst.cfg.enable} - ssh_private_key_file = var.ssh_private_key_file - target_host = "${each.value.hostname}.abundos.eu" - target_user= "root" # FIXME: #24 - target_system = local.system - NIX_PATH = join(":", [for name, path in local.pins : "${name}=${path}"]) - deploy_environment = var.deploy_environment - config_pwd = path.root - config = <<-EOT - { - terraform = builtins.fromJSON ''${jsonencode({ - domain = var.domain - hostname = each.value.hostname - initialUser = var.initialUser - })}''; - imports = [ - ${path.root}/options.nix - ${path.root}/shared.nix - ${path.root}/${each.key}.nix - # FIXME: get VM details from TF - ${path.root}./infra/test-machines/${each.value.hostname} - ]; - } - EOT - perform_gc = false - build_on_target = false - triggers = { - pins = jsonencode(local.pins) + applications = { for name, inst in local.application_configs : name => merge(inst, { + # depends_on = [for name in local.peripheral_configs : module.deploy[name]] + }) + } +} + +# FIXME settle for pwd when in /nix/store? +# FIXME calculate separately to reduce false positives +data "external" "hash" { + program = ["echo", "{\"hash\":\"$(nix-hash ..)\"}"] +} + +# merge instantiate/deploy, cuz i don't want 24+s instantiates when nothing changed. +# terraform-nixos separates these to only deploy if instantiate changed. +# FIXME find a better solution for this. current considerations were: +# - `resource null_resource` cannot have outputs, while we want info from the instantiation (unless built on host?). +# - `data external` always runs, which is undesirable for steps like deploy/instantiation. +# FIXME null_resource docs recommend terraform_data over null_resource +resource "null_resource" "deploy_nixos" { + for_each = {for name, inst in merge( + local.peripherals, + local.applications, + ) : name => inst if inst.cfg.enable} + + triggers = data.external.hash.result + + provisioner "local-exec" { + working_dir = path.root + environment = merge(var.deploy_environment, { + NIX_PATH = join(":", [for name, path in local.pins : "${name}=${path}"]), + }) + # TODO: refactor back to command="ignoreme" interpreter=concat([]) to protect sensitive data from error logs? + # TODO: build on target? + command = <<-EOF + set -euo pipefail + + # INSTANTIATE + command=( + nix-instantiate + --expr + 'let + os = import { + system = "${local.system}"; + configuration = { + terraform = builtins.fromJSON "${replace(jsonencode({ + domain = var.domain + hostname = each.value.hostname + initialUser = var.initialUser + }), "\"", "\\\"")}"; + imports = [ + ${path.root}/options.nix + ${path.root}/shared.nix + ${path.root}/${each.key}.nix + # FIXME: get VM details from TF + ${path.root}/../infra/test-machines/${each.value.hostname} + ]; + }; + }; + in { + substituters = builtins.concatStringsSep " " os.config.nix.binaryCaches; + trusted_public_keys = builtins.concatStringsSep " " os.config.nix.binaryCachePublicKeys; + drv_path = os.config.system.build.toplevel.drvPath; + out_path = os.config.system.build.toplevel; + }' + ) + "$${command[@]}" -A out_path + json="$("$${command[@]}" --eval --strict --json)" + + # DEPLOY + declare substituters trusted_public_keys drv_path + eval "export $(echo $json | jaq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" + host="root@${each.value.hostname}.abundos.eu" # FIXME: #24 + buildArgs=( + --option extra-binary-caches https://cache.nixos.org/ + --option substituters $substituters + --option trusted-public-keys $trusted_public_keys + ) + sshOpts=( + -o StrictHostKeyChecking=no + -o BatchMode=yes + -o "IdentityFile='${var.ssh_private_key_file}'" + ) + outPath=$(nix-store --realize "$drv_path" "$${buildArgs[@]}") + NIX_SSHOPTS="$${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes + ssh "$${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" + EOF } } diff --git a/launch/module.auto.tfvars.json b/launch/module.auto.tfvars.json deleted file mode 100644 index 131e4db7..00000000 --- a/launch/module.auto.tfvars.json +++ /dev/null @@ -1 +0,0 @@ -{"terraform-nixos": "/nix/store/7rx25dwsw2xv9462rk2vkwy4qv33w76x-source"} diff --git a/launch/tf-env.nix b/launch/tf-env.nix index 2c720795..9924a917 100644 --- a/launch/tf-env.nix +++ b/launch/tf-env.nix @@ -13,24 +13,14 @@ pkgs.stdenv.mkDerivation { buildPhase = '' runHook preBuild pushd launch/ - - # pass terraform-nixos path to TF through variable - # when switching TF to nix take this directly from `inputs` - # https://codeberg.org/kiara/e2ed-hetzner/commit/84b2a349d3e48ea2a17340bceff762d834fd4046 - - echo "{\"terraform-nixos\": \"${sources.terraform-nixos}\"}" > module.auto.tfvars.json - # point to the relevant providers + echo '${lib.strings.toJSON sources}' > .npins.json tofu init -input=false - popd runHook postBuild ''; - # FIXME: can the above even work without a connection? installPhase = '' runHook preInstall - cp -r . $out - runHook postInstall ''; } diff --git a/npins/sources.json b/npins/sources.json index 80035ee4..bedab8ae 100644 --- a/npins/sources.json +++ b/npins/sources.json @@ -71,18 +71,6 @@ "name": "nixpkgs-unstable", "url": "https://releases.nixos.org/nixpkgs/nixpkgs-25.05pre777917.b7ba7f9f45c5/nixexprs.tar.xz", "hash": "0jb6b7sv66bn06pchj2l88z0i5dlz0c2vb3z6pjjlq2p8q11zigg" - }, - "terraform-nixos": { - "type": "Git", - "repository": { - "type": "GitHub", - "owner": "KiaraGrouwstra", - "repo": "terraform-nixos" - }, - "branch": "fediversity", - "revision": "54c57ae2e8c312c1b9f69524462d588966ed23b4", - "url": "https://github.com/KiaraGrouwstra/terraform-nixos/archive/54c57ae2e8c312c1b9f69524462d588966ed23b4.tar.gz", - "hash": "1yxps17ac5sljd1ri2p1q1x9h8dcxfpcf0hh6wcpic8ydwy45qql" } }, "version": 3 diff --git a/panel/env.nix b/panel/env.nix index e98622a5..90d15d7a 100644 --- a/panel/env.nix +++ b/panel/env.nix @@ -10,7 +10,7 @@ pkgs.coreutils pkgs.openssh pkgs.git - pkgs.gnugrep # used in terraform-nixos + pkgs.jaq # tf (import ../launch/tf.nix { inherit lib pkgs; }) ]; SSH_PRIVATE_KEY_FILE = "";