From a5f198aba1a0f7071d3f973a52b35dad4d35f8a2 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Wed, 23 Oct 2024 21:43:45 +0200 Subject: [PATCH] terraform: add `var.content`, see #413. This PR adds a Terraform input variable I so far named `content`. This allows passing in a string from Terraform to expose to nixos-anywhere's build step to make available as a file (default: `./nixos-vars.json`) within a NixOS configuration, as suggested by @Mic92 at #414. Note the file is staged even if added to gitignore, making this less suited for development in case the file includes ephemeral content. As a result, I would consider this approach complementary rather than as superseding #414. Example usage: ```nix let servers = ...; variable = ...; data = ...; resource = ...; in { inherit variable data resource; module = lib.mapAttrs (server_name: _server_config: let in { # pin module version by nix flake inputs source = "github.com/numtide/nixos-anywhere?ref=${inputs.nixos-anywhere.sourceInfo.rev}/terraform/all-in-one"; ... content = lib.tfRef "jsonencode(${lib.strings.toJSON { # all variables # TF_VARS = lib.mapAttrs (k: _: lib.tfRef "jsonencode(var.${k})") variable; # non-sensitive variables TF_VARS = lib.mapAttrs (k: _: lib.tfRef "var.${k}") (lib.filterAttrs (_k: v: !(v ? sensitive && v.sensitive)) variable); TF_DATA = lib.mapAttrs (type: instances: lib.mapAttrs (k: _: tfRef "data.${type}.${k}") instances) data; TF_RESOURCES = lib.mapAttrs (type: instances: lib.mapAttrs (k: _: tfRef "resource.${type}.${k}") instances) resource; TF_SERVER = lib.tfRef "resource.hcloud_server.${server_name}"; SERVER_NAME = server_name; }})"; }) servers; } ``` You can then verify their contents from your `nixosConfigurations` like: ```nix lib.nixosSystem { inherit system; modules = [ { environment.etc."nixos-vars.json".source = ./nixos-vars.json; } ]; }; ``` -> `ls /etc/` -> `cat /etc/nixos-vars.json` (in practice one would instead probably parse these back to nix values to grab specific properties from, e.g. like: `lib.strings.fromJSON ./nixos-vars.json`) --- terraform/all-in-one.md | 3 +++ terraform/all-in-one/main.tf | 8 +++++++ terraform/all-in-one/variables.tf | 12 +++++++++++ terraform/nix-build/nix-build.sh | 1 + terraform/nixos-vars.md | 34 ++++++++++++++++++++++++++++++ terraform/nixos-vars/main.tf | 10 +++++++++ terraform/nixos-vars/nixos-vars.sh | 12 +++++++++++ terraform/nixos-vars/variables.tf | 11 ++++++++++ terraform/update-docs.sh | 2 +- 9 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 terraform/nixos-vars.md create mode 100644 terraform/nixos-vars/main.tf create mode 100755 terraform/nixos-vars/nixos-vars.sh create mode 100644 terraform/nixos-vars/variables.tf diff --git a/terraform/all-in-one.md b/terraform/all-in-one.md index c30e41b7..5ded2151 100644 --- a/terraform/all-in-one.md +++ b/terraform/all-in-one.md @@ -96,6 +96,7 @@ No providers. | -------------------------------------------------------------------------------------- | ---------------- | ------- | | [install](#module_install) | ../install | n/a | | [nixos-rebuild](#module_nixos-rebuild) | ../nixos-rebuild | n/a | +| [nixos-vars](#module_nixos-vars) | ../nixos-vars | n/a | | [partitioner-build](#module_partitioner-build) | ../nix-build | n/a | | [system-build](#module_system-build) | ../nix-build | n/a | @@ -107,12 +108,14 @@ No resources. | Name | Description | Type | Default | Required | | --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------- | :------: | +| [content](#input_content) | Content to expose to the NixOS build as a file. | `string` | `"{}"` | no | | [debug\_logging](#input_debug_logging) | Enable debug logging | `bool` | `false` | no | | [deployment\_ssh\_key](#input_deployment_ssh_key) | Content of private key used to deploy to the target\_host after initial installation. To ensure maximum security, it is advisable to connect to your host using ssh-agent instead of relying on this variable | `string` | `null` | no | | [disk\_encryption\_key\_scripts](#input_disk_encryption_key_scripts) | Each script will be executed locally. Output of each will be created at the given path to disko during installation. The keys will be not copied to the final system |
list(object({
path = string
script = string
}))
| `[]` | no | | [extra\_environment](#input_extra_environment) | Extra environment variables to be set during installation. This can be useful to set extra variables for the extra\_files\_script or disk\_encryption\_key\_scripts | `map(string)` | `{}` | no | | [extra\_files\_script](#input_extra_files_script) | A script that should place files in the current directory that will be copied to the targets / directory | `string` | `null` | no | | [file](#input_file) | Nix file containing the nixos\_system\_attr and nixos\_partitioner\_attr. Use this if you are not using flake | `string` | `null` | no | +| [filename](#input_filename) | Name of the file to which to dump `content`. Defaults to `nixos-vars.json`. | `string` | `"./nixos-vars.json"` | no | | [install\_port](#input_install_port) | SSH port used to connect to the target\_host, before installing NixOS. If null than the value of `target_port` is used | `string` | `null` | no | | [install\_ssh\_key](#input_install_ssh_key) | Content of private key used to connect to the target\_host during initial installation | `string` | `null` | no | | [install\_user](#input_install_user) | SSH user used to connect to the target\_host, before installing NixOS. If null than the value of `target_host` is used | `string` | `null` | no | diff --git a/terraform/all-in-one/main.tf b/terraform/all-in-one/main.tf index 5689c64d..db237ee5 100644 --- a/terraform/all-in-one/main.tf +++ b/terraform/all-in-one/main.tf @@ -1,5 +1,12 @@ +module "nixos-vars" { + source = "../nixos-vars" + content = var.content + filename = var.filename +} + module "system-build" { source = "../nix-build" + depends_on = [module.nixos-vars] attribute = var.nixos_system_attr file = var.file nix_options = var.nix_options @@ -7,6 +14,7 @@ module "system-build" { module "partitioner-build" { source = "../nix-build" + depends_on = [module.nixos-vars] attribute = var.nixos_partitioner_attr file = var.file nix_options = var.nix_options diff --git a/terraform/all-in-one/variables.tf b/terraform/all-in-one/variables.tf index 981c4f8c..a0677c72 100644 --- a/terraform/all-in-one/variables.tf +++ b/terraform/all-in-one/variables.tf @@ -131,3 +131,15 @@ variable "nixos_facter_path" { description = "Path to which to write a `facter.json` generated by `nixos-facter`." default = "" } + +variable "content" { + type = string + default = "{}" + description = "Content to expose to the NixOS build as a file." +} + +variable "filename" { + type = string + default = "./nixos-vars.json" + description = "Name of the file to which to dump `content`. Defaults to `nixos-vars.json`." +} diff --git a/terraform/nix-build/nix-build.sh b/terraform/nix-build/nix-build.sh index 8e5babca..c12e9ede 100755 --- a/terraform/nix-build/nix-build.sh +++ b/terraform/nix-build/nix-build.sh @@ -4,6 +4,7 @@ set -efu declare file attribute nix_options eval "$(jq -r '@sh "attribute=\(.attribute) file=\(.file) nix_options=\(.nix_options)"')" options=$(echo "${nix_options}" | jq -r '.options | to_entries | map("--option \(.key) \(.value)") | join(" ")') + if [[ -n ${file-} ]] && [[ -e ${file-} ]]; then # shellcheck disable=SC2086 out=$(nix build --no-link --json $options -f "$file" "$attribute") diff --git a/terraform/nixos-vars.md b/terraform/nixos-vars.md new file mode 100644 index 00000000..757b77a1 --- /dev/null +++ b/terraform/nixos-vars.md @@ -0,0 +1,34 @@ + +## Requirements + +No requirements. + +## Providers + +| Name | Version | +|------|---------| +| [external](#provider\_external) | n/a | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [external_external.nixos-vars](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [content](#input\_content) | Content to expose to the NixOS build as a file. | `string` | `"{}"` | no | +| [filename](#input\_filename) | Name of the file to which to dump `content`. Defaults to `nixos-vars.json`. | `string` | `"./nixos-vars.json"` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| [result](#output\_result) | n/a | + \ No newline at end of file diff --git a/terraform/nixos-vars/main.tf b/terraform/nixos-vars/main.tf new file mode 100644 index 00000000..a576ed42 --- /dev/null +++ b/terraform/nixos-vars/main.tf @@ -0,0 +1,10 @@ +data "external" "nixos-vars" { + program = [ "${path.module}/nixos-vars.sh" ] + query = { + content = var.content + filename = var.filename + } +} +output "result" { + value = data.external.nixos-vars.result +} diff --git a/terraform/nixos-vars/nixos-vars.sh b/terraform/nixos-vars/nixos-vars.sh new file mode 100755 index 00000000..c18ce4bc --- /dev/null +++ b/terraform/nixos-vars/nixos-vars.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -efu + +declare content filename +eval "$(jq -r '@sh "content=\(.content) filename=\(.filename)"')" + +echo "${content}" >"${filename}" +# ignores `Error Message: fatal: Unable to create '.../.git/index.lock': File exists.` +# Note this `--force` stages the file even if it is added to gitignore. +git add --intent-to-add --force -- "${filename}" >/dev/null 2>&1 || true +# TF dummy result output +printf '{}' diff --git a/terraform/nixos-vars/variables.tf b/terraform/nixos-vars/variables.tf new file mode 100644 index 00000000..9fb1038c --- /dev/null +++ b/terraform/nixos-vars/variables.tf @@ -0,0 +1,11 @@ +variable "content" { + type = string + default = "{}" + description = "Content to expose to the NixOS build as a file." +} + +variable "filename" { + type = string + default = "./nixos-vars.json" + description = "Name of the file to which to dump `content`. Defaults to `nixos-vars.json`." +} diff --git a/terraform/update-docs.sh b/terraform/update-docs.sh index b67d98ad..e408e970 100755 --- a/terraform/update-docs.sh +++ b/terraform/update-docs.sh @@ -4,7 +4,7 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" files=() -find "${SCRIPT_DIR}"/* -type d | while read -r i; do +find "${SCRIPT_DIR}"/* -maxdepth 1 -type d | while read -r i; do module_name=$(basename "$i") markdown_file="${SCRIPT_DIR}/${module_name}.md" terraform-docs --config "${SCRIPT_DIR}/.terraform-docs.yml" markdown table --output-file "${markdown_file}" --output-mode inject "${module_name}"