Skip to content

Commit

Permalink
DRAFT: terraform: add var.special_args, see nix-community#413.
Browse files Browse the repository at this point in the history
This PR adds a Terraform input variable named `special_args`.
This allows passing in a string from Terraform to expose to
NixOS's `specialArgs` at build-time.

This implementation extends the original `lib.nixosSystem`
call to allow passing info without either use of `--impure`
or having to stage to Git, thanks to @Mic92's suggestion at 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";
      ...
      special_args = lib.tfRef "jsonencode(${lib.strings.toJSON {
        tf = {
          inherit server_name;
          # all variables
          # var = lib.mapAttrs (k: _: lib.tfRef
  "var.${k}") variable;
          # non-sensitive variables
          var = lib.mapAttrs (k: _: lib.tfRef "var.${k}")
  (lib.filterAttrs (_k: v: !(v ? sensitive && v.sensitive)) variable);
          data = lib.mapAttrs (type: instances: lib.mapAttrs (k: _:
  tfRef "data.${type}.${k}") instances) data;
          resource = lib.mapAttrs (type: instances: lib.mapAttrs (k:
  _: tfRef "resource.${type}.${k}") instances) resource;
          server = lib.tfRef "resource.hcloud_server.${server_name}";
        };
      }})";
    })
    servers;
}
```

You can then use these in your `nixosConfigurations`,
in this example thru the `tf` argument.
  • Loading branch information
KiaraGrouwstra committed Oct 31, 2024
1 parent 51d347d commit d98bb2b
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 11 deletions.
1 change: 1 addition & 0 deletions terraform/all-in-one.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ No resources.
| <a name="input_nixos_system_attr"></a> [nixos\_system\_attr](#input_nixos_system_attr) | The nixos system to deploy i.e. your-flake#nixosConfigurations.your-evaluated-nixos.config.system.build.toplevel or just your-evaluated-nixos.config.system.build.toplevel if you are not using flakes | `string` | n/a | yes |
| <a name="input_no_reboot"></a> [no\_reboot](#input_no_reboot) | DEPRECATED: Use `phases` instead. Do not reboot after installation | `bool` | `false` | no |
| <a name="input_phases"></a> [phases](#input_phases) | Phases to run. See `nixos-anywhere --help` for more information | `set(string)` | <pre>[<br> "kexec",<br> "disko",<br> "install",<br> "reboot"<br>]</pre> | no |
| <a name="input_special_args"></a> [special\_args](#input_special_args) | A map exposed as NixOS's `specialArgs` thru a file. | `string` | `"{}"` | no |
| <a name="input_stop_after_disko"></a> [stop\_after\_disko](#input_stop_after_disko) | DEPRECATED: Use `phases` instead. Exit after disko formatting | `bool` | `false` | no |
| <a name="input_target_host"></a> [target\_host](#input_target_host) | DNS host to deploy to | `string` | n/a | yes |
| <a name="input_target_port"></a> [target\_port](#input_target_port) | SSH port used to connect to the target\_host after installing NixOS. If install\_port is not set than this port is also used before installing. | `number` | `22` | no |
Expand Down
2 changes: 2 additions & 0 deletions terraform/all-in-one/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ module "system-build" {
attribute = var.nixos_system_attr
file = var.file
nix_options = var.nix_options
special_args = var.special_args
}

module "partitioner-build" {
source = "../nix-build"
attribute = var.nixos_partitioner_attr
file = var.file
nix_options = var.nix_options
special_args = var.special_args
}

locals {
Expand Down
6 changes: 6 additions & 0 deletions terraform/all-in-one/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,9 @@ variable "nixos_facter_path" {
description = "Path to which to write a `facter.json` generated by `nixos-facter`."
default = ""
}

variable "special_args" {
type = string
default = "{}"
description = "A map exposed as NixOS's `specialArgs` thru a file."
}
11 changes: 6 additions & 5 deletions terraform/nix-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,12 @@ No modules.

## Inputs

| Name | Description | Type | Default | Required |
| ------------------------------------------------------------------- | -------------------------------------------------- | ------------- | ------- | :------: |
| <a name="input_attribute"></a> [attribute](#input_attribute) | the attribute to build, can also be a flake | `string` | n/a | yes |
| <a name="input_file"></a> [file](#input_file) | the nix file to evaluate, if not run in flake mode | `string` | `null` | no |
| <a name="input_nix_options"></a> [nix\_options](#input_nix_options) | the options of nix | `map(string)` | `{}` | no |
| Name | Description | Type | Default | Required |
| ---------------------------------------------------------------------- | --------------------------------------------------- | ------------- | ------- | :------: |
| <a name="input_attribute"></a> [attribute](#input_attribute) | the attribute to build, can also be a flake | `string` | n/a | yes |
| <a name="input_file"></a> [file](#input_file) | the nix file to evaluate, if not run in flake mode | `string` | `null` | no |
| <a name="input_nix_options"></a> [nix\_options](#input_nix_options) | the options of nix | `map(string)` | `{}` | no |
| <a name="input_special_args"></a> [special\_args](#input_special_args) | A map exposed as NixOS's `specialArgs` thru a file. | `string` | `"{}"` | no |

## Outputs

Expand Down
1 change: 1 addition & 0 deletions terraform/nix-build/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ data "external" "nix-build" {
attribute = var.attribute
file = var.file
nix_options = local.nix_options
special_args = var.special_args
}
}
output "result" {
Expand Down
31 changes: 25 additions & 6 deletions terraform/nix-build/nix-build.sh
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
#!/usr/bin/env bash
set -efu

declare file attribute nix_options
eval "$(jq -r '@sh "attribute=\(.attribute) file=\(.file) nix_options=\(.nix_options)"')"
declare file attribute nix_options special_args
eval "$(jq -r '@sh "attribute=\(.attribute) file=\(.file) nix_options=\(.nix_options) special_args=\(.special_args)"')"
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")
printf '%s' "$out" | jq -c '.[].outputs'
else
# shellcheck disable=SC2086
out=$(nix build --no-link --json $options "$attribute")
printf '%s' "$out" | jq -c '.[].outputs'
# pass the args in a pure fashion by extending the original config
if [[ ${special_args-} != "{}" ]]; then
rest="$(echo "${attribute}" | cut -d "#" -f 2)"
# e.g. config_path=nixosConfigurations.aarch64-linux.myconfig
config_path="${rest%.config.*}"
# e.g. config_attribute=config.system.build.toplevel
config_attribute="config.${rest#*.config.}"

# grab flake nar from error message
flake_rel="$(echo "${attribute}" | cut -d "#" -f 1)"
# e.g. flake_rel="."
flake_dir="$(readlink -f "${flake_rel}")"
flake_nar="$(nix build --expr "builtins.getFlake ''git+file://${flake_dir}?narHash=sha256-0000000000000000000000000000000000000000000=''" 2>&1 | grep -Po "(?<=got ')sha256-[^']*(?=')")"
# substitute variables into the template
nix_expr="(builtins.getFlake ''file://${flake_dir}/flake.nix?narHash=${flake_nar}'').${config_path}.extendModules { specialArgs = builtins.fromJSON ''${special_args}''; }"
# inject `special_args` into nixos config's `specialArgs`
# shellcheck disable=SC2086
out=$(nix build --no-link --json ${options} --expr "${nix_expr}" "${config_attribute}")
else
# shellcheck disable=SC2086
out=$(nix build --no-link --json ${options} "$attribute")
fi
fi
printf '%s' "$out" | jq -c '.[].outputs'
6 changes: 6 additions & 0 deletions terraform/nix-build/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ variable "nix_options" {
description = "the options of nix"
default = {}
}

variable "special_args" {
type = string
default = "{}"
description = "A map exposed as NixOS's `specialArgs` thru a file."
}

0 comments on commit d98bb2b

Please sign in to comment.