Terraform
Development tricks
Deploying only parts of a configuration
To deploy only certain parts of a Terraform configuration, use the -target
flag, e.g.:
terraform apply -target module.my_module
# With a resource defined as: `resource "local_file" "foo" { }`
terraform apply -target=local_file.foo
Cookbook
Collections
Convert a map to a multi-line string with line delimiters
Convert a map of usernames and passwords into a multiline string in the format username:password
..
First you’ll need to define the variable in a variables.tf
file (You can’t define variables within Terraform console):
terminal_users = [
{
username = "dave"
password = "dav381919"
},
{
username = "lucy"
password = "lucy123211"
},
]
Then:
join("\r\n", [for user in var.terminal_users : "${user.username}:${user.password}"])
Convert a map of usernames into a space-separated list
join(" ", [for user in var.terminal_users : user.username])
Convert a map of usernames into a for_each input
{for user in var.terminal_users : user.username => user}
Looping
A poor round-robin
- Use the
element
function to get the element at a given index in a list - Use the
index
function to get the index of a given key in a map - Use the
values
function to get a list of values from a map
This allows us to loop around input structures and do a “round-robin” of the values. For example:
- assign each server to a network, from a known list of networks
- assign each user to a different server, from a known list of servers
module "some_module" {
for_each = { for idx, user in keys(var.servers) : server => var.servers[server] }
# Now let's pick a network for this server by doing a round-robin of the networks,
# using the index of the server in the map (0, 1, 2, 3, 4, 5, etc...)
# Assuming that module.vpc.networks returns something like:
# [
# {
# name = "network-01"
# },
# {
# name = "network-02"
# },
# ]
# And the var.servers map looks like:
# {
# "server-01" = {
# ...
# },
# "server-02" = {
# ...
# },
# }
# We use 'each.key' to get the current key in the map
# We then use this to get the index of the current key in the map
# And then use that index to get the element at that index, in another list
# The 'element' function returns the element at the given index in a list
# (and wraps around to the beginning of the list if the index is greater than
# the length of the list) - e.g. 0, 1, 2, 3, 0, 1, 2, 3...
# e.g. "network-01", "network-02", etc.
server_network_name = element(
values(module.vpc.networks),
index(keys(var.servers), each.key)
).name
}
Outputs
Output a map of maps
# e.g.:
# app_url = {
# "mydave" = "https://trcgotestjoe.example.com"
# "myjoe" = "https://trcgotestsusan.example.com"
# }
output "app_url" {
value = {
for key, stack in module.my_custom_module : key => stack.stacks.url
}
}
Output a map of maps
# e.g.:
# email_fields = {
# "joe@example.com" = {
# "url" = "https://trcgotestjoe.example.com"
# "username" = "joe"
# "password" = "hiyaaa"
# "webterminal" = "https://example.com"
# }
output "email_fields" {
value = {
for user in var.my_users : user.email => {
"url" = module.my_custom_module[user.id].stacks.url
"username" = user.username
"password" = user.password
"webterminal" = "https://example.com"
}
}
}
Output an entire submodule’s output
```hcl output “stacks” { value = module.my_custom_module sensitive = true }