'Template.tf and user_data.yaml.tpl- loop through a variable of type list
I am new to templates, I am trying to change terraform modules to flex as many “nameservers” as needed.
How can iterate through the values of variable?
Right now I am doing:
template.tf
variable "nameserver" {
type = list(string)
}
nameservers = [
"174.15.22.20",
"174.15.12.21"
]
nameserver_1 = element(var.nameservers, 0) #nameserver_1=174.15.22.20
nameserver_2 = element(var.nameservers, 1) #nameserver_2=174.15.12.21
user_data.yaml.tpl
nameserver ${nameserver_1}
nameserver ${nameserver_2}
I want to do something like:
template.tf
vars = {
count = length(var.nameserver)
for nameserver in nameservers:
nameserver_$(count.index)= ${element(var.nameserver, count.index)}
}
user_data.yaml.tpl
for nameserver in nameservers:
nameserver ${nameserver_[count.index]}
But I am unable to figure out the right way to do this in template.tf and user_data.yaml.tpl
Any help would be appreciated !
Solution 1:[1]
From what you've shown of template.tf
I'm guessing that vars = { ... }
declaration is inside a data "template_file"
block. The template_file
data source is primarily there for Terraform 0.11 compatibility and it only supports string values for the template variables, but since you are using Terraform 0.12 you can use the new templatefile
function instead, which makes this easier by supporting values of any type.
From the template name you used I'm guessing that you intend to use this result to assign to user_data
, in which case the syntax for doing that in templatefile
would look something like this:
user_data = templatefile("${path.module}/user_data.yaml.tpl", {
nameservers = var.nameservers
})
In your user_data.yaml.tpl
file:
%{ for s in nameservers ~}
nameserver ${s}
%{ endfor ~}
The %{ ... }
sequences here are Terraform template syntax. That same syntax is also available directly in the main configuration file, so for a template this small you might prefer to just write the template inline to keep things simpler:
user_data = <<-EOT
%{ for s in var.nameservers ~}
nameserver ${s}
%{ endfor ~}
EOT
The template syntax is the same here, but because this is in the main .tf
configuration file rather than in a separate template file we can just refer directly to var.nameservers
here, rather than building a separate map of template variables.
The name you gave your template file seems to suggest that you are generating YAML, though the template you showed doesn't actually generate valid YAML. If you are intending the result to be YAML, you have some other options in Terraform that might be better depending on your goals:
Firstly, JSON is a subset of YAML, so you could ask Terraform to JSON-encode your data instead, and then the YAML parser in your instance (if it is YAML-spec-compliant) should be able to parse it:
user_data = jsonencode({
nameservers = var.nameservers
})
An advantage of this approach is that you can let Terraform's jsonencode
function worry about the JSON syntax, escaping, etc and you can just pass it the data structure you want to represent. Using templates instead might require you to handle quoting or escaping of values if they might contain significant punctuation.
Recent versions of Terraform also have a yamlencode
function, but at the time of writing it's experimental and the exact details of how it formats its output might change in future releases. I would not recommend to use it as user_data
right now because if the syntax details do change in a future version then that would cause your instance to be planned for replacement. In a future version of Terraform that output should be stabilized, once the team has enough feedback from real-world use to be confident that its YAML formatting decisions are acceptable for a broad set of use-cases.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Martin Atkins |