Terraform Interpolation vs. Directives

hi_artem

Artem

Posted on July 1, 2022

Terraform Interpolation vs. Directives

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!"
}
Enter fullscreen mode Exit fullscreen mode

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
}

Enter fullscreen mode Exit fullscreen mode

You can see how list facts is used to generate HTML

elements:

%{for fact in var.facts}
  <p>Terraform is ${fact}</p>
%{endfor}
Enter fullscreen mode Exit fullscreen mode

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}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

That's all for today! Have fun hacking Terraform!

💖 💪 🙅 🚩
hi_artem
Artem

Posted on July 1, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related