Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform: Pass a variable containing a list of strings to a jsonencode section

I want to set up a Terraform module that assigns a policy to an Azure resource according to Terraforms policy assignment example.

In order to assign the allowed locations policy, I want to pass the list of allowed locations as a list of strings from the variables.tf file to the main.tf, where the assignment is executed.

main.tf

#Allowed Locations Policy Assignment 
resource "azurerm_policy_assignment" "allowedlocations" {
  name                 = "allowed-locations"
  scope                = var.scope_allowedlocations
  policy_definition_id = var.policy_allowedlocations.id 
  description          = "This policy enables you to restrict the locations."
  display_name         = "Allowed Locations"

  parameters = <<PARAMETERS
  {
  "allowedLocations": {
    "value": ${var.listofallowedlocations}
    }
  } 
  PARAMETERS

}

variables.tf

# Scope of the Allowed Locations policy
variable "scope_allowedlocations" {
  description = "The scope of the allowed locations assignment."
  default     = "Subscription"
}

# Scope of the Allowed Locations policy
variable "policy_allowedlocations" {
  description = "The allowed locations policy (created by the policy-define module)."
  default     = "default"
}

# List of the Allowed Locations
variable "listofallowedlocations" {
  type = list(string)
  description = "The allowed locations list."
  default     = [ "West Europe", "North Europe", "East US" ]
}

Executing with terraform plan leads to the following error:

Error: Invalid template interpolation value

  on modules/policy-assign/main.tf line 16, in resource "azurerm_policy_assignment" "allowedlocations":
  12:
  13:
  14:
  15:
  16:     "value": ${var.listofallowedlocations}
  17:
  18:
  19:
    |----------------
    | var.listofallowedlocations is list of string with 3 elements

Cannot include the given value in a string template: string required.

Thus, I don't know how to exactly pass the list from the variables file to the PARAMETERS section of the policy assignment resource. In Terraforms policy assignment example the list is directly inline coded in the PARAMETERS section and it works. But there is no passing of variables...:

parameters = <<PARAMETERS
{
  "allowedLocations": {
    "value": [ "West Europe" ]
  }
}
PARAMETERS
like image 533
Peter Avatar asked Jul 26 '19 11:07

Peter


People also ask

How do you use list variables in Terraform?

tf file format will be automatically loaded during operations. Create a variables file, for example, variables.tf and open the file for edit. Add the below variable declarations to the variables file. Replace the SSH key private file path and the public key with our own.

How do you pass a variable in Terraform command line?

Using the -var Command-line Flag The -var flag is used to pass values for Input Variables to Terraform commands. This flag can be used with both of the Terraform plan and apply commands. The argument passed to the -var flag is a string surrounded by either single or double quotes.

How do you assign a value to a variable in Terraform?

To do so, simply set the environment variable in the format TF_VAR_<variable name> . The variable name part of the format is the same as the variables declared in the variables.tf file. For example, to set the ami variable run the below command to set its corresponding value.

What is Jsonencode in Terraform?

» jsonencode Function jsonencode encodes a given value to a string using JSON syntax. The JSON encoding is defined in RFC 7159. This function maps Terraform language values to JSON values in the following way: Terraform type. JSON type.

What is @jsonencode in TerraForm?

jsonencode encodes a given value to a string using JSON syntax. The JSON encoding is defined in RFC 7159. This function maps Terraform language values to JSON values in the following way: list (...) set (...) tuple (...) map (...) object (...)

How to map terraform language values to JSON values?

This function maps Terraform language values to JSON values in the following way: list (...) set (...) tuple (...) map (...) object (...)

Is it possible to pass variables from one terraform to another?

In Terraforms policy assignment example the list is directly inline coded in the PARAMETERS section and it works. But there is no passing of variables...: When you are interpolating a value into a string that value must itself be convertible to string, or else Terraform cannot join the parts together to produce a single string result.

Why does terraform have a ready-to-use JSON function?

Terraform provides a ready-to-use function for JSON because its a common need. If you need more control over the above decisions then you'd need to use more complex techniques to describe to Terraform what you need.


1 Answers

When you are interpolating a value into a string that value must itself be convertible to string, or else Terraform cannot join the parts together to produce a single string result.

There are a few different alternatives here, with different tradeoffs.


The option I personally would choose here is to not use the <<PARAMETERS syntax at all and to just build that entire value using jsonencode:

parameters = jsonencode({
  allowedLocations = {
    value = var.listofallowedlocations
  }
})

This avoids the need for your configuration to deal with any JSON syntax issues at all, and (subjectively) therefore makes the intent clearer and future maintenence easier.

In any situation where the result is a single valid JSON value, I would always choose to use jsonencode rather than the template language. I'm including the other options below for completeness in case a future reader is trying to include a collection value into a string template that isn't producing JSON.


A second option is to write an expression to tell Terraform a way to convert your list value into a string value in a suitable format. In your case you wanted JSON and so jsonencode again would probably be the most suitable choice:

parameters = <<PARAMETERS
{
  "allowedLocations": {
    "value": ${jsonencode(var.listofallowedlocations)}
  }
} 
PARAMETERS

In other non-JSON situations, when the result is a simple list of strings, the join function can be useful to just concatenate all of the strings together with a fixed delimiter.

Any of Terraform's functions that produce a single string as a result is a candidate here. The ones under "String Functions" and "Encoding Functions" are the most likely choices.


Finally, for situations where the mapping from the collection value to the resulting string is something custom that no standard function can handle, you can use the template repetition syntax:

parameters = <<CONFIG
%{ for port in var.ports ~}
listen 127.0.0.1:${port}
%{ endfor ~}
CONFIG

In this case, Terraform will evaluate the body of the repetition construct once for each element in var.ports and concatenate all of the results together in order to produce the result. You can generate all sorts of textual output formats using this approach, though if the template gets particularly complicated it could be better to factor it out into a separate file and use the templatefile function to evaluate it.

like image 148
Martin Atkins Avatar answered Sep 28 '22 02:09

Martin Atkins