Terraform HCL Intro 7: For In Loop Basics
In this post, we’ll cover the Terraform for in
loop construct. Though it performs looping, its primary purpose is really for manipulating data structures. You can do a few things to data structures with it:
- Transform: Change the data structure.
- Filter: Select only desired items.
- Group: Group elements together in a new List by a key.
Input Source and Output Result
The input source and output result can be either be a List or a Map. Then for
will either transform and or filter it. Here’s a diagram to help explain:
Simple Transformations Examples
Though the for
syntax is pretty straightforward in these examples, it can get confusing without understanding how different types work with it.
List to List
Here’s an example with a List input source:
locals {
list = ["a","b","c"]
}
output "list" {
value = [for s in local.list : upper(s)]
}
Returns in:
$ terraform apply
Outputs:
list = ["A", "B", "C"]
A straightforward upper transformation has been done. The resulting value is another List. This is indicated by the surrounding [...]
square brackets. Yes, the surrounding brackets indicate what value type is returned. So it’s important to pay attention to what they are.
Map to List
Here’s another example with a Map as the input source:
locals {
list = {a = 1, b = 2, c = 3}
}
output "result1" {
value = [for k,v in local.list : "${k}-${v}" ]
}
output "result2" {
value = [for k in local.list : k ]
}
Results in:
$ terraform apply
Outputs:
result1 = ["a-1", "b-2", "c-3"]
result2 = [1, 2, 3]
So when the input source is a Map, you can access the key and value. The resulting value is another List. This is indicated by the surrounding [...]
square brackets again.
List to Map
The examples we’ve been using have a resulting Output type of List due to the [...]
square brackets. To return a Map type instead, we would use the {...}
curly brackets. Here’s an example:
locals {
list = ["a","b","c"]
}
output "result" {
value = {for i in local.list : i => i }
}
Results in:
$ terraform apply
Outputs:
result = {
"a" = "a"
"b" = "b"
"c" = "c"
}
As you can see, the result output type is a Map now. It is important to note that we must provide an expression with the =>
when returning a Map. Otherwise, you’ll get this error:
Error: Invalid 'for' expression
on main.tf line 5, in output "result":
5: value = {for i in local.list : i }
Map to Map
Now a Map to Map example:
locals {
list = {a = 1, b = 2, c = 3}
}
output "result" {
value = {for k,v in local.list : k => v }
}
Results in:
$ terraform apply
Outputs:
result = {
"a" = 1
"b" = 2
"c" = 3
}
Review & Reiterate
The wrapping bracket indicates return value type:
- When a for expression is wrapped in square brackets
[...]
, the result type is a List. - When a for expression is wrapped in curly brackets
{...}
, the result type is a Map. - Also, when returning a Map, the expression elements are separated by
=>
.
We’ve only shown simple transformations to introduce things. You can do many more transformations with Terraform functions.
Multi-Line Expression
When the transformation logic gets more complicated, it can be nice to write for
expressions across multiple lines.
locals {
list = ["a","b","c"]
}
output "list" {
value = [
for s in local.list :
upper(s)
]
}
locals {
map = {a = 1, b = 2, c = 3}
}
output "map" {
value = {
for k,v in local.map :
k => v
}
}
Results in:
$ terraform apply
Outputs:
list = ["A", "B", "C"]
map = { "a" = 1, "b" = 2, "c" = 3 }
Simple Filtering Examples
We can also filter the Input to an Output result. This means filtering always results in a collection that is smaller or equal to the original Input size. Filtering is achieved by tacting on the if
clause to the end of the transformation expression. Let’s go through some examples:
Filter Simple Number Elements
In this example, we’ll filter for numbers that are less than 3.
locals {
list = [1,2,3,4,5]
}
output "list" {
value = [for i in local.list : i if i < 3]
}
Results in:
$ terraform apply
Outputs:
list = [1, 2]
Filter Map Elements
In this example, the elements are Maps. We’ll transform the data to only return the values, but only if the b key’s value is greater than 6.
locals {
list = [
{a = 1, b = 5},
{a = 2, b = 6},
{a = 3, b = 7},
{a = 4, b = 8},
]
}
output "list" {
value = [for m in local.list : values(m) if m.b > 6 ]
}
Results in:
$ terraform apply
Outputs:
list = [
[3,7]
[4,8],
]
Filter Inconsistent Map Elements
Let’s say the Map elements are a little bit inconsistent, like some of them lack the b key. We can filter for that.
locals {
list = [
{a = 1, b = 5},
{a = 2},
{a = 3},
{a = 4, b = 8},
]
}
output "list" {
value = [for m in local.list : m if contains(keys(m), "b") ]
}
Results in:
$ terraform apply
Outputs:
list = [
{"a" = 1, "b" = 5},
{"a" = 4, "b" = 8},
]
Splats
Let’s cover splats also. Splats are a shorthand way to write for in
expressions. These 2 expressions produce the same result:
for in expression
[for minion in local.minions : minion.name ]
splat expression
local.minions[*].name
Here’s a working example:
locals {
minions = [{
name: "bob"
},{
name: "kevin",
},{
name: "stuart"
}]
}
output "minions" {
value = local.minions[*].name
}
Results in:
$ terraform apply
Outputs:
minions = [
"bob",
"kevin",
"stuart",
]
Group Mode
The final form of for
we’ll cover is group mode. The syntax is a little weird for this one. You use it by adding ...
to the end of the value expression. Example:
locals {
list = [
"mr bob",
"mr kevin",
"mr stuart",
"ms anna",
"ms april",
"ms mia",
]
}
output "list" {
value = {for s in local.list : substr(s, 0, 2) => s...}
}
Results in:
$ terraform apply
Outputs:
list = {
"mr" = [
"mr bob",
"mr kevin",
"mr stuart",
]
"ms" = [
"ms anna",
"ms april",
"ms mia",
]
}
Group mode works kind of like SQL group by
. The key is used as the group by
and groups items together in a List.
Summary
In this post, we covered the basics of the for in
loop construct. It is useful for data manipulation. The source code for these examples is available for BoltOps Learn subscribers: terraform-hcl-tutorials/7-for-in-loop-basics
In the next post, we’ll cover more practical examples of the for
construct, Terraform HCL Intro 8: For In and Removing Duplication.
Want It to be Easier to Work with Terraform?
Check out Terraspace: The Terraform Framework.
The Terraform HCL Language Intro Tutorials
Thanks for reading this far. If you found this article useful, I'd really appreciate it if you share this article so others can find it too! Thanks 😁 Also follow me on Twitter.
Got questions? Check out BoltOps.
You might also like
More tools:
-
Kubes
Kubes: Kubernetes Deployment Tool
Kubes is a Kubernetes Deployment Tool. It builds the docker image, creates the Kubernetes YAML, and runs kubectl apply. It automates the deployment process and saves you precious finger-typing energy.
-
Jets
Jets: The Ruby Serverless Framework
Ruby on Jets allows you to create and deploy serverless services with ease, and to seamlessly glue AWS services together with the most beautiful dynamic language: Ruby. It includes everything you need to build an API and deploy it to AWS Lambda. Jets leverages the power of Ruby to make serverless joyful for everyone.
-
Lono
Lono: The CloudFormation Framework
Building infrastructure-as-code is challenging. Lono makes it much easier and fun. It includes everything you need to manage and deploy infrastructure-as-code.