How to use for expression in Terraform ?
I come from background of C,C++, Java, C# and so on. In my initial days of using Terraform HCL , I felt quite restrictive when it comes to loops and building conditional logic and complex conditions. I then came across for expression and then I said this is quite handy.
This post focuses on some of the scenarios where I have used for expression !
Problem Statement
I have a list of instances (this is technically map of objects in terraform world) as outlined below.
# main.tf
locals {
instances = {
web_server = {
instance_type = "t3.micro"
os = "Linux"
description = "Web Server"
},
app_server = {
instance_type = "t3.micro"
os = "Linux"
description = "Application Server"
},
db_server = {
instance_type = "m5.lagre"
os = "Windows"
description = "DB Server"
}
}
}
output "instances" {
value = local.instances
}
Question ?
How should one get three different lists so as to get :
- List of instances with os =Windows
- List of instances with os =Linux
- List of instances grouped based on instance_type (t3.micro , m5.large and so on.)
If you come from programming background of Java , C# then you may struggle to come with the logic as HCL follows a paradigm of Declarative Language.
Let us look at how this could be achieved using for expression in Terraform.
Solution
If we look at the given configuration the given list is actually map of objects.
We would need mechanism to filter the instances based on os. This is where for expression comes in play.
Part I — Filter out the Linux instances
locals {
linux_instances = {
for k, v in local.instances : k => v
if v.os == "Linux"
}
}
output "linux_instances" {
value = local.linux_instances
}
- For each key (k) and value (v) in map (local.instances) — create another map with key (k) having value (v) object provided if v.os = ‘Linux”
- This skips all the objects with other os i.e. v.os = “Windows”
The terraform plan output shows the linux_instances as a separate output.
Part — II — Filter out the Windows Instances
Same mechanism is used to filter Windows instances as well.
locals {
windows_instances = {
for k, v in local.instances : k => v
if v.os == "Windows"
}
}
output "windows_instances" {
value = local.windows_instances
}
This is quite cool as one can dynamically build the local lists and manipulate the way we want. Here the trick is to use condition i.e. if condition with for expression. i.e. if v.os = = “Windows” and if v.os == “Linux” to have a different list.
Part III — Create a group of instances based on instance_type
This one is quite interesting and it shows the flexibility provided by the conditional logic where one can group the items in the map based on key.
locals {
instance_list_with_types = {
// There could be more than one instances of different type
//so ellipsis (...) is required
for k, v in local.instances : v.instance_type => v...
}
}
output "instance_list_with_types" {
value = local.instance_list_with_types
}
The above list creates a group based on the instance_type ! All the instance types with m5.large and t3.micro are grouped accordingly.
Quite handy isn’t it !
Appendix : Complete Code Listing
# main.tf
locals {
instances = {
web_server = {
instance_type = "t3.micro"
os = "Linux"
description = "Web Server"
},
app_server = {
instance_type = "t3.micro"
os = "Linux"
description = "Application Server"
},
db_server = {
instance_type = "m5.lagre"
os = "Windows"
description = "DB Server"
}
}
}
output "instances" {
value = local.instances
}
locals {
linux_instances = {
for k, v in local.instances : k => v
if v.os == "Linux"
}
}
output "linux_instances" {
value = local.linux_instances
}
locals {
windows_instances = {
for k, v in local.instances : k => v
if v.os == "Windows"
}
}
output "windows_instances" {
value = local.windows_instances
}
locals {
instance_list_with_types = {
for k, v in local.instances : v.instance_type => v... // There could be more than one instances of different type so ... is required
}
}
output "instance_list_with_types" {
value = local.instance_list_with_types
}
That is all for this post !