-
-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
terraform: add var.extra_build_env_vars
, closes #413
#414
terraform: add var.extra_build_env_vars
, closes #413
#414
Conversation
terraform/nix-build/nix-build.sh
Outdated
if [[ -n ${file-} ]] && [[ -e ${file-} ]]; then | ||
# shellcheck disable=SC2086 | ||
out=$(nix build --no-link --json $options -f "$file" "$attribute") | ||
out=$(eval "env ${vars} nix build --no-link --json --impure $options -f '$file' '$attribute'") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhm --impure
by default is not so nice.
Have you considered the following approach?
https://github.com/NixOS/nixos-wiki-infra/blob/main/terraform/nixos-wiki/nixos_vars.tf
Basically one can use terraform to generate a json file and using git add
to make sure it's recognized by the flake. Maybe we can encode this pattern into the terraform module instead of using builtins.getEnv
?
The big upside on this is that, you are no longer forced to always have to use terraform to build or deploy your nixos configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just imagine you want your machines to be build by CI. Before you could just do nixos-rebuild build --flake .mymachine
, now you have to do some sort of terraform plan
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interface wise I would propose a nix-file
module that would use git add --intent-to-add --force -- ./file >/dev/null 2>&1 || true
to make sure that it is added to your git repository (if one exists). It would take content
as a parameter:
module "nixos_vars" {
source = "../nix-file"
content = jsonencode({})
filename = "${path.module}/nixos-vars.json"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm. if one could make a file without terraform, why couldn't one similarly make env vars, if the nixos configuration is indeed made to require them?
locally such a nix-file
module might give some noise in version control, tho one could opt to just never use git add .
anymore. whereas deploying from CI might circumvent that, it would seem a bit annoying in a development setting. going by file may have use-cases as well, tho it'd be nice to see a route more amenable to the common use-case of git + flakes + development supported as well.
on --impure
, maybe a conditional could be added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed it's possible to achieve your goal without impure evaluation. Check how to import json into a nixos configuration: https://github.com/nix-community/disko/blob/09a776702b004fdf9c41a024e1299d575ee18a7d/install-cli.nix#L56
disko-install still adds --impure
. However it's possible to use getFlake also in a pure evaluation: Check out this code in clan: https://git.clan.lol/clan/clan-core/src/commit/bcf2cd1814bbef57c74b0b4eec8f6a7cc0479475/pkgs/clan-cli/clan_cli/machines/machines.py#L229
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KiaraGrouwstra@75e09d1 also looks good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mic92 thanks for elaborating - i originally hadn't quite figured out the tempfile thing. i'll try and see if I can use your mentioned approach to resolve the flake+git friction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
notes to self to reconcile the PRs, before i forget: info may be passed purely without staging to git thru nix build --expr
, reading a file by builtins.fetchTree
to pass the content as file to avoid stack overflows based on content size. the original lib.nixosSystem
can then be wrapped so as to e.g. write the extra info to some file.
edit: potential alternative: nix build path:.
@@ -14,3 +14,9 @@ variable "nix_options" { | |||
description = "the options of nix" | |||
default = {} | |||
} | |||
|
|||
variable "extra_build_env_vars" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in general it would be fine to have environment variables or flags passed to nixos-rebuild. This could be used for injecting binary cache configuration.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, i'll check it out. i still got a few question marks around say how that would handle conditionals based on environment variables, but i guess i can just try that.
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`)
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`)
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`)
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`)
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`)
This PR adds a Terraform input variable named `content`. This allows passing in a string from Terraform to expose to NixOS's run-time to make available as a file (default: `/etc/nixos-vars.json`) as suggested by @Mic92 at nix-community#414. This third iteration wraps the original `lib.nixosSystem` call to allow passing info without either use of `--impure` or having to stage to Git. 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: `cat /etc/nixos-vars.json` However, so far I did not yet manage to reach my goal: - On this attempt I have so far just exposed the content to run-time, rather than to the intended NixOS build-time. To address this, I consider looking into injecting thru `specialArgs`, tho I am not sure yet this would work, and feel open to suggestions. - When putting the content file into `.gitignore`, the build currently errors on same NAR hash mismatch on the file.
This PR adds a Terraform input variable named `content`. This allows passing in a string from Terraform to expose to NixOS's run-time to make available as a file (default: `/etc/nixos-vars.json`) as suggested by @Mic92 at nix-community#414. This third implementation wraps the original `lib.nixosSystem` call to allow passing info without either use of `--impure` or having to stage to Git. 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 "jsonencode(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` thru the `tf` argument. Status: - [ ] resolve occasional NAR hash mismatches - [ ] Test putting the content file into `.gitignore`.
This PR adds a Terraform input variable named `content`. This allows passing in a string from Terraform to expose to NixOS's run-time to make available as a file (default: `/etc/nixos-vars.json`) as suggested by @Mic92 at nix-community#414. This third implementation wraps the original `lib.nixosSystem` call to allow passing info without either use of `--impure` or having to stage to Git. 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 "jsonencode(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` thru the `tf` argument. Status: - [ ] Resolve occasional NAR hash mismatches - [ ] Test putting the content file into `.gitignore`. - [ ] Let the user pass in a TF map rather than string.
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.
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.
This PR adds a Terraform input variable named `special_args`. This allows passing in a JSON 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.
…lows passing in a JSON 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, in this case presuming deployment to a Hetzner Cloud server (`resource.hcloud_server`): ```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. This implementation differs from my previous attempts in neither being impure, nor adding files. An advantage of this is it is a relatively simple implementation that should work while getting out of your way. An [alternative design](nix-community/nixos-anywhere@main...KiaraGrouwstra:nixos-anywhere:tf-info-to-wrapper#diff-2e2429dde4812f0b50c784e8d4c8b93cc9faeb52cce4747733200f65ea5c2bbb) suggested by @Mic92 involved passing the information not directly, but rather thru a file. The idea would be that this might help reduce the risk of stack overflows, tho I have imagined (perhaps naively) that TF info has tended not to get too big, whereas I also had a bit more trouble getting that approach to work properly so far (involving both NARs that would suddenly mismatch again, while I'd also yet to test if one could put such files in `.gitignore`). As a note on security, information passed this way _will_ hit `/nix/store/`. As such, the above usage example has defaulted to omitting TF variables marked as sensitive. Note that, while from a UX perspective I would have preferred to allow directly passing nested structures without serializing, TF seemed to allow passing variables just as string or as map of strings - in which case I figured, if we have to manually serialize anyway, it would be a nicer experience to just serialize once (to a string-type variable) than to do so for each special argument (to use a map-of-strings TF variable).
This allows passing in a map from Terraform to expose to NixOS's `specialArgs` at build-time. Example usage, in this case presuming deployment to a Hetzner Cloud server (`resource.hcloud_server`): ```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 = { 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. As a note on security, information passed this way _will_ hit `/nix/store/`. As such, the above usage example has defaulted to omitting TF variables marked as sensitive. This PR incorporates ideas from: - @aanderse, who implemented a similar feature in [teraflops](https://github.com/aanderse/teraflops) that inspired this PR. - @Mic92, who suggested (see nix-community#414) to extend the original `lib.nixosSystem` call to pass in info without `--impure` or staging to Git. - @getchoo, who suggested getting the NAR hash by `nix flake prefetch` over `getFlake`, fixing an 'unlocked flake reference' error on (non-Lix) Nix. - @threddast, who suggested to use TF's `any` type to automate serializing. An [alternative design](nix-community/nixos-anywhere@main...KiaraGrouwstra:nixos-anywhere:tf-info-to-wrapper#diff-2e2429dde4812f0b50c784e8d4c8b93cc9faeb52cce4747733200f65ea5c2bbb) suggested by @Mic92 involved passing the information not directly, but rather thru a file. The idea would be that this might help reduce the risk of stack overflows, tho I have imagined (perhaps naively) that TF info has tended not to get too big, whereas I also had a bit more trouble getting that approach to work properly so far (involving both NARs that would suddenly mismatch again, while I'd also yet to test if one could put such files in `.gitignore`).
This allows passing in a map from Terraform to expose to NixOS's `specialArgs` at build-time. Example usage, in this case presuming deployment to a Hetzner Cloud server (`resource.hcloud_server`): ```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 = { 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. As a note on security, information passed this way _will_ hit `/nix/store/`. As such, the above usage example has defaulted to omitting TF variables marked as sensitive. This PR incorporates ideas from: - @aanderse, who implemented a similar feature in [teraflops](https://github.com/aanderse/teraflops) that inspired this PR. - @Mic92, who suggested (see nix-community#414) to extend the original `lib.nixosSystem` call to pass in info without `--impure` or staging to Git. - @getchoo, who suggested getting the NAR hash by `nix flake prefetch` over `getFlake`, fixing an 'unlocked flake reference' error on (non-Lix) Nix. - @threddast, who suggested to use TF's `any` type to automate serializing. An [alternative design](nix-community/nixos-anywhere@main...KiaraGrouwstra:nixos-anywhere:tf-info-to-wrapper#diff-2e2429dde4812f0b50c784e8d4c8b93cc9faeb52cce4747733200f65ea5c2bbb) suggested by @Mic92 involved passing the information not directly, but rather thru a file. The idea would be that this might help reduce the risk of stack overflows, tho I have imagined (perhaps naively) that TF info has tended not to get too big, whereas I also had a bit more trouble getting that approach to work properly so far (involving both NARs that would suddenly mismatch again, while I'd also yet to test if one could put such files in `.gitignore`).
This allows passing in a map from Terraform to expose to NixOS's `specialArgs` at build-time. Example usage, in this case presuming deployment to a Hetzner Cloud server (`resource.hcloud_server`): ```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 = { 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. As a note on security, information passed this way _will_ hit `/nix/store/`. As such, the above usage example has defaulted to omitting TF variables marked as sensitive. This PR incorporates ideas from: - @aanderse, who implemented a similar feature in [teraflops](https://github.com/aanderse/teraflops) that inspired this PR. - @Mic92, who suggested (see #414) to extend the original `lib.nixosSystem` call to pass in info without `--impure` or staging to Git. - @getchoo, who suggested getting the NAR hash by `nix flake prefetch` over `getFlake`, fixing an 'unlocked flake reference' error on (non-Lix) Nix. - @threddast, who suggested to use TF's `any` type to automate serializing. An [alternative design](main...KiaraGrouwstra:nixos-anywhere:tf-info-to-wrapper#diff-2e2429dde4812f0b50c784e8d4c8b93cc9faeb52cce4747733200f65ea5c2bbb) suggested by @Mic92 involved passing the information not directly, but rather thru a file. The idea would be that this might help reduce the risk of stack overflows, tho I have imagined (perhaps naively) that TF info has tended not to get too big, whereas I also had a bit more trouble getting that approach to work properly so far (involving both NARs that would suddenly mismatch again, while I'd also yet to test if one could put such files in `.gitignore`).
This is obsolete now. |
This PR adds a Terraform input variable I so far named
extra_build_env_vars
(suggestions welcome).This allows passing in a map of attributes from Terraform to expose to nixos-anywhere's build step to make them available as environment variables within a NixOS configuration.
For this implementation I opted to leave actually passing the info to the user, so people stay in control over what info gets exposed where.
I opted to focus on allowing to pass info thru environment variables here figuring that would be less prone to fighting flakes over what is staged to Git, as committing info to be passed here may be undesirable both for ephemeral noise (if not also over sensitive info - tho any info passed this way lands in
/nix/store/
as well).To pull this off I used
--impure
pluseval
- feedback on this would be great.On the Terraform side as a consumer, to best enjoy this I have had to resort to some more involved logic as well, that gets easy when using Terraform from Nix. As an example (based on Hetzner Cloud), using the
lib.tfRef
function from Terranix I would use something like:You can then verify their contents from your
nixosConfigurations
like:->
ls /etc/
->cat /etc/TF_SERVER
(in practice one would instead probably parse these back to nix values to grab specific properties from, e.g. like:
lib.strings.fromJSON (builtins.getEnv "TF_SERVER")
)