DEV Community

Cover image for Terraform For Expressions
Panchanan Panigrahi
Panchanan Panigrahi

Posted on

Terraform For Expressions

As infrastructure as code (IaC) continues to evolve, managing complex cloud environments efficiently is more important than ever. Terraform, a widely adopted IaC tool, simplifies cloud infrastructure provisioning, and its flexibility is further enhanced through expressions like the powerful for loop.

In this blog, we will explore how Terraform's for expression can help transform collections with ease, allowing you to streamline infrastructure configuration. By breaking down the syntax and providing real-world examples, you’ll learn how to filter, mutate, and group resources dynamically. Whether you're managing instances or organizing cloud environments, this guide will give you the tools to handle it all programmatically.

What is Terraform For Expression?

The for expression in Terraform is used to iterate over collections, such as lists or maps, to transform or filter elements. It helps create new lists or maps from existing ones by applying an expression to each element. This is especially useful for simplifying repetitive tasks and creating dynamic infrastructure configurations.

Syntax of a Terraform for Expression

for expressions in Terraform provide a flexible way to transform and filter collections, whether they are lists, sets, or maps. Below are the syntaxes for both types of outputs—lists and maps—with examples.

1. Syntax: When the Output is a List

[for item in var.collection : transformation if condition]
Enter fullscreen mode Exit fullscreen mode
  • var.collection: The list or set you are iterating over.
  • transformation: The operation or logic applied to each item in the collection, such as accessing properties, applying a function, or performing calculations.
  • if condition: (Optional) A filtering condition to include only the items that satisfy the condition.

Example:

[for instance in aws_instances : upper(instance.name) if instance.status == "running"]
Enter fullscreen mode Exit fullscreen mode

In this example, Terraform creates a list of instance names in uppercase, but only for instances where status is "running".

2. Syntax: When the Output is a Map

{for key, value in var.map : key => transformation if condition}
Enter fullscreen mode Exit fullscreen mode
  • var.map: The map being iterated over.
  • key => transformation: Defines the key-value pair for the new map. key remains unchanged, while transformation applies logic to the value.
  • if condition: (Optional) A filtering condition to include only key-value pairs that meet the condition.

Example:

{for name, instance in aws_instances : name => length(instance.tags) if instance.status == "running"}
Enter fullscreen mode Exit fullscreen mode

In this example, Terraform generates a new map where the name remains the same, but the value is the number of tags associated with each instance. This is only done for instances with a "running" status.

How to Use For Expressions in Terraform

In Terraform, for expressions are powerful tools used to transform collections. There are three main types of transformations that for expressions enable:

  1. Filtration
  2. Mutation
  3. Grouping

Let's explore each of these with examples to understand how they work.

1. Filtration of a Collection Based on a Condition

Filtration selectively includes only certain elements in a new collection based on a condition.

Variable Block with Defaults:

variable "aws_instances" {
  default = [
    { id = "i-001", status = "running" },
    { id = "i-002", status = "stopped" },
    { id = "i-003", status = "running" }
  ]
  type = list(object({
    id     = string
    status = string
  }))
}
Enter fullscreen mode Exit fullscreen mode

For Expression Example:

output "running_instance_ids" {
  value = [for instance in var.aws_instances : instance.id if instance.status == "running"]
}
Enter fullscreen mode Exit fullscreen mode

Explanation:
This filters the aws_instances variable, creating a list of ids only for instances that have the status "running". In this case, the output would be ["i-001", "i-003"].

2. Mutation of a Collection Based on a Condition

Mutation modifies each element in the collection, often based on a condition.

Variable Block with Defaults:

variable "users" {
  default = [
    { name = "Alice", is_active = true },
    { name = "Bob", is_active = false },
    { name = "Charlie", is_active = true }
  ]
  type = list(object({
    name      = string
    is_active = bool
  }))
}
Enter fullscreen mode Exit fullscreen mode

For Expression Example:

output "active_user_names" {
  value = [for user in var.users : upper(user.name) if user.is_active]
}
Enter fullscreen mode Exit fullscreen mode

Explanation:
This expression loops through the users collection, converts the name of active users (is_active == true) to uppercase, and returns a list of the transformed names. The result would be ["ALICE", "CHARLIE"].

3. Grouping of a Collection Based on a Condition

Grouping creates a map that organizes elements based on a specific key or condition.

Variable Block

First, define the variable for projects, holding the project details like region and environments.

variable "projects" {
  type = map(object({
    region       = string
    environments = list(string)
  }))

  default = {
    customer_api = {
      region       = "australiasoutheast"
      environments = ["dev", "uat", "prd"]
    }
    partner_api = {
      region       = "australiasoutheast"
      environments = ["dev", "prd"]
    }
    internal_api = {
      region       = "australiaeast"
      environments = ["prd"]
    }
    payments_api = {
      region       = "norwayeast"
      environments = ["dev", "tst", "uat", "sit", "stg", "prd"]
    }
    returns_api = {
      region       = "norwayeast"
      environments = ["dev", "uat", "prd"]
    }
    refunds_api = {
      region       = "norwayeast"
      environments = ["dev", "uat", "prd"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Grouping Projects by Region

Use a for expression to dynamically group projects based on their region, creating a map where the key is the region, and the value is a list of project names.

output "projects_grouped_by_region" {
  value = {
    for project, details in var.projects :
    details.region => concat(
      lookup({for project, details in var.projects : details.region => []}, details.region, []),
      [project]
    )
  }
}
Enter fullscreen mode Exit fullscreen mode
Explanation
  1. Variable Block: The projects variable is a map where the key is the project name, and the value is an object containing region and environments. This structure makes it flexible for real-world scenarios.

  2. for Expression in Output: The output groups the projects based on their region. We use concat() to collect all projects with the same region into a list. The expression is designed to ensure each region groups all relevant projects.

Example Output

This output will group the projects by region, showing something like this:

projects_grouped_by_region = {
  "australiaeast" = ["internal_api"]
  "australiasoutheast" = ["customer_api", "partner_api"]
  "norwayeast" = ["payments_api", "returns_api", "refunds_api"]
}
Enter fullscreen mode Exit fullscreen mode

Final Thoughts

Terraform’s for expression is a game-changer for anyone looking to automate complex infrastructure transformations. With its ability to filter, mutate, and group collections dynamically, you can tackle even the most intricate use cases with elegance and simplicity. From optimizing resource management to enhancing infrastructure readability, the examples we've discussed show how for expressions can transform not just collections, but also how you approach infrastructure as a whole. Happy Deploying!!!

Top comments (0)