How to use templates in Terraform
Tags: terraform, cloud, cloudnative, cloudskills
Published: 2022-12-18 14:45:34

Terraform has a `templatefile(path, vars)` function that can be used to render the content of a file into a string with variable substitution.

## Variable Substitution

The variable substitution has an interpolation syntax using `${..}` . So you can reference variables that you passed into the second map argument of the `templatefile` function.

```jsx
resource "aws_instance" "web_server" {
  ami           = data.aws_ami.amzn2.id
  instance_type = local.instance_type
  user_data     = templatefile("user-data.sh", {})
	...
}
```

The code above renders a shell script as a string without substituting any template variables.

The recommended file format is `*.tftpl` but the function does not enforce it.

We can pass additional variables from the terraform script to the user data example above.

```jsx
resource "aws_instance" "web_server" {
  ami           = data.aws_ami.amzn2.id
  instance_type = local.instance_type
  user_data     = templatefile("user-data.sh", { log_group = "test-server" })
	...
}
```

```jsx
#!/bin/bash
sudo chown $USER:$USER -R $cw_agent_config_folder
sudo mkdir -p $cw_agent_config_folder
sudo cat <<EOT >> $cw_agent_config_path
{
  "agent": {
    "metrics_collection_interval": $cw_agent_collection_interval,
    "run_as_user": "root"
  },
  "logs": {
    "logs_collected": {
      "files": {
        "collect_list": [
          {
            "file_path": "$http_access_logs",
            "log_group_name": "${log_group}",
            "log_stream_name": "{instance_id}-access-logs",
            "retention_in_days": $cw_agent_log_retention
          }
        ]
      }
    }
  },
  ...
}
EOT
sudo $cw_agent_ctl -a fetch-config -m ec2 -c file:$cw_agent_config_path -s
```

The example above shows how you can work both with shell variables and template variables at the same time since the syntax that you use to reference them differs.

## For Loop - Lists

Templates can also be used to dry up repeating sections.

This snippet prints “hello world” in 4 different variations.

```jsx
resource "aws_instance" "web_server" {
  ...
  user_data     = templatefile("hello-world.tfpl", { names = [ "world", "planet" ] })
	...
}
```

```jsx
#!/bin/bash
%{ for name in names }
echo "hello ${name}
%{ endfor ~}
```

The snippets above render the `hello-world.tfpl` into a string that contains to `echo` statements.

```jsx
echo "hello world"
echo "hello planet"
```

It is important that we add a shebang into the shell script if we do not use the `*.sh` file ending (or comparable) but the `*.tfpl` file ending instead. The shebang instructs the script caller which binary must be invoked for the script execution.

## For Loop - Maps

We can also loop through maps.

```jsx
resource "aws_instance" "web_server" {
  ...
  user_data     = templatefile("hello-world.tfpl", { names = { "firstname": "Max", "lastname": "Fischer" })
	...
}
```

```jsx
#!/bin/bash
%{ for config_key, config_value in names }
echo "hello to ${config_key}: ${config_value}"
%{ endfor ~}
```

Results of this output

```jsx
echo "hello to firstname Max"
echo "hello to lastname Fischer"
```