Terraform Interpolation vs. Directives
Artem
Posted on July 1, 2022
Every Terraform user should be familiar with HashiCorp Language (HCL) aka Terraform interpolation syntax.
Let say I have a variable defined as filename
, then interpolation allows me to do stuff like that:
resource "local_file" "index" {
filename = "${var.filename}.txt"
content = "foo!"
}
The Terraform official website says:
[Interpolation] evaluates the expression given between the markers, converts the result to a string if necessary, and then inserts it into the final string.
In other words, it can do some elementary operation and dump result as a string.
This is neat, and can be helpful if we want to add suffix or prefix to an EC2 instance, but what if we are tasked with generating a config file dynamically with unknown number of nested blocks?
That's where directives come into play!
The Terraform docs have this short definition of the directive:
[It] allows for conditional results and iteration over collections.
It is kinda like for_each
, but inside of string rather than resource.
An example should make things clear!
variable "filename" {
default = "index.html"
}
variable "facts" {
default = ["fun", "hard"]
}
variable "complex_facts" {
default = [
{
element: "h2"
content: "FUN!"
},
{
element: "h1"
content: "EASY!"
}
]
}
resource "local_file" "index_html" {
filename = "${path.module}/${var.filename}"
content = <<EOT
<html>
%{for fact in var.facts}
<p>Terraform is ${fact}</p>
%{endfor}
%{for fact in var.complex_facts}
<${fact.element}>Terraform is ${fact.content}</${fact.element}>
%{endfor}
</html>
EOT
}
You can see how list facts
is used to generate HTML
elements:
%{for fact in var.facts}
<p>Terraform is ${fact}</p>
%{endfor}
The same syntax can be used on objects, like with in complex_facts
case:
%{for fact in var.complex_facts}
<${fact.element}>Terraform is ${fact.content}</${fact.element}>
%{endfor}
The resulting HTML file is pretty ugly:
<html>
<p>Terraform is fun</p>
<p>Terraform is hard</p>
<h2>Terraform is FUN!</h2>
<h1>Terraform is EASY!</h1>
</html>
This can be used to generate tiny and ugly HTMLs (although there are better tools for this purpose), but it can also be used for more complex configuration files!
It can also be used to replace ternary expression, which some people find hard to read.
This interpolation sequence:
resource "local_file" "txt" {
filename = "${path.module}/file.txt"
content = <<EOT
${ var.content != "" ? var.content : "NO CONTENT PROVIDED"}
EOT
}
can be replace by the following directives sequence:
resource "local_file" "txt" {
filename = "${path.module}/file.txt"
content = <<EOT
%{ if var.content != "" }${var.content}%{ else }NO CONTENT PROVIDED!%{ endif }
EOT
}
That's all for today! Have fun hacking Terraform!
Posted on July 1, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.