variable "domain" { type = string default = "fediversity.net" } variable "mastodon" { type = object({ enable = bool }) default = { enable = false } } variable "pixelfed" { type = object({ enable = bool }) default = { enable = false } } variable "peertube" { type = object({ enable = bool }) default = { enable = false } } variable "initialUser" { type = object({ displayName = string username = string email = string # TODO: mark (nested) credentials as sensitive # https://discuss.hashicorp.com/t/is-it-possible-to-mark-an-attribute-of-an-object-as-sensitive/24649/2 password = string }) default = { displayName = "Testy McTestface" username = "test" email = "test@test.com" password = "testtest" } } variable "ssh_private_key_file" { type = string description = "Path to private key used to connect to the target_host" default = "" } variable "deploy_environment" { type = map(string) description = "Extra environment variables to be set during deployment." default = {} } locals { system = "x86_64-linux" pins = jsondecode(file("${path.module}/.npins.json")) peripheral_configs = { garage = "test01" } application_configs = { mastodon = { cfg = var.mastodon hostname = "test06" } pixelfed = { cfg = var.pixelfed hostname = "test04" } peertube = { cfg = var.peertube hostname = "test05" } } peripherals = { for name, inst in local.peripheral_configs : name => { hostname = inst cfg = { enable = anytrue([for _, app in local.application_configs: app.cfg.enable]) } } } 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 = ["sh", "-c", "echo '{\"hash\":\"$(nix-hash ..)\"}'"] } # merged instantiate/deploy to prevent 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: # - generic resources cannot have outputs, while we want info from the instantiation (unless built on host?). # - `data` always runs, which is slow for deploy/instantiation. resource "terraform_data" "nixos" { for_each = {for name, inst in merge( local.peripherals, local.applications, ) : name => inst if inst.cfg.enable} triggers_replace = [ data.external.hash.result, var.deploy_environment, var.domain, var.initialUser, local.system, each.key, each.value, ] 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.settings.substituters; trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; 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 } }