-
Notifications
You must be signed in to change notification settings - Fork 9.6k
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
tfvarsdecode/tfvarsencode encoding functions #25584
Comments
Hi @gw0, We don't have However, you mentioned For that reason, I'd suggest as a compromise a function A further "design hazard" here is that the tfvars language comes in two variants: one based on HCL native syntax and the other based on JSON. However, the FWIW, an existing pattern I've seen for "global values" is to write a data-only module and call it from each configuration using a output "aws_account_id" {
value = "235346456753456"
} module "globals" {
source = "../globals"
}
provider "aws" {
# ...
allowed_account_ids = [module.globals.aws_account_id]
} This works with Terraform today, and potentially allows the module to further encapsulate details that might make later refactoring easier, such as potentially obtaining some values via data resources later, or dynamically generating certain values based on input variables for situations where the patterns are systematic across different environments. |
Thank you for the explanation. If I understand correctly, it would then be possible to create Terraform-specific HCL functions Anyway, data-only modules for implementing "common values" are a viable option. But I ended up implementing "hierarchical common values" with the help of Terragrunt |
Hey @apparentlymart, apologies for bumping an old thread - I've recently run into a need for a Since we're using terraform (via |
hashicorp/terraform-provider-tfe#188 seems to speak to a different meaning of It's unfortunate that the Terraform Cloud API was defined to take variables in HCL syntax instead of a more convenient API-friendly format, and therefore in turn the Let's keep this issue about the original topic of a function for encoding and decoding the |
@apparentlymart I'm not sure I agree that this is different, but it may be the way I'm parsing (pun intended) the original poster.
When foo: bar
baz:
buzz: true ...which, when foo = "bar"
baz = {
buzz = true
} ...i.e. this could be The OP also asks for the counterpart ("...(and maybe even hclencode) ..."), which I would expect would be the exact same as I believe that there may be an objection that
It may be worth clarifying the the "subset of HCL Terraform Cloud is expecting", is, unless I'm missing something, the exact same subset of a single expression in a That is, // this code is non-functional, and only meant to be illustrative
func tfvarsencode_impl() {
for _, variable := range variables {
fmt.Sprintf("%s = %s\n", variable.name, tfvarencode_impl(variable))
}
} ...and then users like myself could call: resource "tfe_variable" "foo" {
key = "foo"
value = tfvarencode(local.foo)
category = "terraform"
hcl = true
// ...
} It may be that I'm not seeing this the same way as you, but if |
If it is unclear how to write a generic HCL decoding function (equivalent to |
As a user it feels weird that Terraform is able to decode JSON/YAML but not tfvars. Due to specific requirements we are trying to reference multiple tfvars files in multiple git submodules without adding them to the Terraform project input variables: locals {
git_submodule_vars = tfvarsdecode(file("../git_submodule_folder/git_submodule_vars.tfvars")),
} But it looks like we may need to switch the remote vars to YAML to achieve this as simply as above (which is not ideal). |
We have a usecase for Currently we use the following workaround (requires data "external" "hclencode" {
program = ["bash", "-c", "echo '${jsonencode(local.to_hcl)}' | jq | sed -r 's/\"(.*)\": /\\1 = /;s/^( [^ ].*),$/\\1/' | tail -n +2 | head -n -1 | terraform fmt - | jq --raw-input --slurp '{\"hcl\":.}'"]
}
locals {
to_hcl = { # some dynamically generated data stucture, this static data is an example
a = 1,
b = 2,
c = [
{
d = 4,
e = 5
},
{
f = [
6,
7,
8
]
}
]
}
hcl_string = data.external.hclencode.result["hcl"]
}
resource "github_repository_file" "tfvars" {
repository = ...
file = "something.auto.tfvars"
content = <<-EOF
################################################################################
# GENERATED BY TERRAFORM, DO NOT EDIT!!!!
# This file will be automatically loaded by terraform
################################################################################
some_static_var = ...
${data.external.hclencode.result["hcl"]}
EOF
...
}
Here is a module that does the same: variable "map" {
type = any
}
data "external" "hclencode" {
program = ["bash", "-c", "set -o pipefail; echo '${jsonencode(var.map)}' | jq | sed -r 's/^ \"(.*)\": / \\1 = /;s/^ ( *)\"([a-zA-z0-9_-]*)\": / \\1\\2 = /;s/^ ( *\".*\"): / \\1 = /;s/^( [^ ].*),$/\\1/' | tail -n +2 | head -n -1 | terraform fmt - | jq --raw-input --slurp '{\"hcl\":.}'"]
}
output "hcl" {
value = data.external.hclencode.result["hcl"]
} |
Another use-case here. We use complex variables in our modules (for good reason). In case we need to expose a complex module variable in the root module we have to re-define the same variable structure in the root and keep this in sync with the module. To overcome this limitation we have to define variables in the root module as |
Another very simple use-case. We use tfe_variable to manage variables for terraform cloud workspaces and it seems like there is simply no way to pass existing data to value parameter (it requires string). |
Maybe it helps you @giner, I've been using a |
I don't like its vague structure, but But even this has a limitation, at least from security perspective where you want to be sure that certain variables can't be tampered with from outside the environment. And it's a cheat anyways. I would much prefer an actual concept of state-wide For perspective, my usecase is this: I wish I could use the computer to do some work for me... And while I understand the importance of defining variable type at the What I could imagine though is.. variable of # subnet.tf
variable "complex" {
type = map(object({}))
}
# region.tf
variable "complex" {
type = inherit
}
module "subnet_1" {
source = "./subnet"
complex = var.complex
} How about this? Would it help with some of the use-cases above? |
Using the new possibility for providers to contribute their own functions to the Terraform language, coming in Terraform v1.8, the built-in "terraform" provider (which previously offered only the These are added as part of the provider, rather than as traditional built-in functions, as part of the new posture of using built-ins only for very broad, general features; moving forward, most new functions are likely to belong to providers, and so these are some early examples. Of course, since this provider is built-in itself Terraform will not need to download an external plugin to execute these ones. |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. |
Current Terraform Version
Use-cases
Built-in encoding functions are missing support for your HCL syntax format (missing
hcldecode
/hclencode
). Because only other formats are supported, it is impossible to have everything in the same syntax as Terraform modules.A common use case is to implement global/common values. The obvious option of using
common_vars.tfvars
is deprecated and results inWarning: Value for undeclared variable
and in future this will be an error (#22004). The alternative of preparing a wrapper Bash script to export env variables looks like a hack. So the only way is to implement something like globally defined locals incommon_vars.yaml
(idea from Terragrunt) with:In this situation it seems weird to use YAML for common values and HCL for everything else (Terraform files). The solution is to expose support for
hcldecode
(and maybe evenhclencode
), that are already implemented somewhere in Terraform source code.Attempted Solutions
As mentioned, for that use case the only solution is to use YAML or JSON.
Proposal
Support for
hcldecode
(and maybe evenhclencode
) in order to load globally defined locals like:The text was updated successfully, but these errors were encountered: