Skip to content

Commit

Permalink
terraform: add var.content, see nix-community#413.
Browse files Browse the repository at this point in the history
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 nix-community#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 nix-community#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`)
  • Loading branch information
KiaraGrouwstra committed Oct 26, 2024
1 parent 51d347d commit bc717fc
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 1 deletion.
3 changes: 3 additions & 0 deletions terraform/all-in-one.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ No providers.
| -------------------------------------------------------------------------------------- | ---------------- | ------- |
| <a name="module_install"></a> [install](#module_install) | ../install | n/a |
| <a name="module_nixos-rebuild"></a> [nixos-rebuild](#module_nixos-rebuild) | ../nixos-rebuild | n/a |
| <a name="module_nixos-vars"></a> [nixos-vars](#module_nixos-vars) | ../nixos-vars | n/a |
| <a name="module_partitioner-build"></a> [partitioner-build](#module_partitioner-build) | ../nix-build | n/a |
| <a name="module_system-build"></a> [system-build](#module_system-build) | ../nix-build | n/a |

Expand All @@ -107,12 +108,14 @@ No resources.

| Name | Description | Type | Default | Required |
| --------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | ----------------------------------------------------------------------- | :------: |
| <a name="input_content"></a> [content](#input_content) | Content to expose to the NixOS build as a file. | `string` | `"{}"` | no |
| <a name="input_debug_logging"></a> [debug\_logging](#input_debug_logging) | Enable debug logging | `bool` | `false` | no |
| <a name="input_deployment_ssh_key"></a> [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 |
| <a name="input_disk_encryption_key_scripts"></a> [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 | <pre>list(object({<br> path = string<br> script = string<br> }))</pre> | `[]` | no |
| <a name="input_extra_environment"></a> [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 |
| <a name="input_extra_files_script"></a> [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 |
| <a name="input_file"></a> [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 |
| <a name="input_filename"></a> [filename](#input_filename) | Name of the file to which to dump `content`. Defaults to `nixos-vars.json`. | `string` | `"./nixos-vars.json"` | no |
| <a name="input_install_port"></a> [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 |
| <a name="input_install_ssh_key"></a> [install\_ssh\_key](#input_install_ssh_key) | Content of private key used to connect to the target\_host during initial installation | `string` | `null` | no |
| <a name="input_install_user"></a> [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 |
Expand Down
8 changes: 8 additions & 0 deletions terraform/all-in-one/main.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
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
}

module "partitioner-build" {
source = "../nix-build"
depends_on = [module.nixos-vars]
attribute = var.nixos_partitioner_attr
file = var.file
nix_options = var.nix_options
Expand Down
12 changes: 12 additions & 0 deletions terraform/all-in-one/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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`."
}
1 change: 1 addition & 0 deletions terraform/nix-build/nix-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
34 changes: 34 additions & 0 deletions terraform/nixos-vars.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

No requirements.

## Providers

| Name | Version |
|------|---------|
| <a name="provider_external"></a> [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 |
|------|-------------|------|---------|:--------:|
| <a name="input_content"></a> [content](#input\_content) | Content to expose to the NixOS build as a file. | `string` | `"{}"` | no |
| <a name="input_filename"></a> [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 |
|------|-------------|
| <a name="output_result"></a> [result](#output\_result) | n/a |
<!-- END_TF_DOCS -->
10 changes: 10 additions & 0 deletions terraform/nixos-vars/main.tf
Original file line number Diff line number Diff line change
@@ -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
}
12 changes: 12 additions & 0 deletions terraform/nixos-vars/nixos-vars.sh
Original file line number Diff line number Diff line change
@@ -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 '{}'
11 changes: 11 additions & 0 deletions terraform/nixos-vars/variables.tf
Original file line number Diff line number Diff line change
@@ -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`."
}
2 changes: 1 addition & 1 deletion terraform/update-docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down

0 comments on commit bc717fc

Please sign in to comment.