Terraform: Mastering Foreach with List of Maps within a List of Maps
Terraform, a popular Infrastructure as Code (IaC) tool, provides a powerful feature known as foreach
to iterate over collections such as lists, sets, and maps. However, when it comes to nested collections, like a list of maps within a list of maps, things can get a bit tricky. This blog post will guide you through the process of using foreach
with nested collections in Terraform.
Table of Contents
- Understanding Foreach in Terraform
- Foreach with List of Maps
- Foreach with List of Maps within a List of Maps
- Best Practices for Using
foreach
with List of Maps - Common Errors and Troubleshooting
- Conclusion
Understanding Foreach in Terraform
Before diving into nested collections, let’s first understand the foreach
construct in Terraform. Foreach
is used to create multiple instances of a resource or module. It takes a map or a set of strings, and creates a new instance for each item.
resource "aws_instance" "example" {
foreach = var.instances
ami = "ami-0c94855ba95c574c8"
instance_type = "t2.micro"
tags = {
Name = each.key
}
}
In this example, var.instances
is a map where each key-value pair represents an AWS instance. The each.key
and each.value
can be used to access the key and value of the current item, respectively.
Foreach with List of Maps
Now, let’s see how we can use foreach
with a list of maps. Suppose we have a variable var.subnets
that is a list of maps, where each map represents a subnet.
variable "subnets" {
description = "List of subnets"
type = list(map(string))
default = [
{
name = "subnet-1"
cidr = "10.0.1.0/24"
},
{
name = "subnet-2"
cidr = "10.0.2.0/24"
}
]
}
We can use foreach
to create a subnet for each map in the list.
resource "aws_subnet" "example" {
foreach = { for s in var.subnets : s.name => s }
vpc_id = aws_vpc.example.id
cidr_block = each.value.cidr
tags = {
Name = each.key
}
}
In this example, we use a for
expression to transform the list of maps into a map of maps, which can be used with foreach
.
Foreach with List of Maps within a List of Maps
Now, let’s tackle the main topic: using foreach
with a list of maps within a list of maps. Suppose we have a variable var.vpcs
that is a list of maps, where each map represents a VPC and contains a key subnets
that is a list of maps.
variable "vpcs" {
description = "List of VPCs"
type = list(map(any))
default = [
{
name = "vpc-1"
cidr = "10.0.0.0/16"
subnets = [
{
name = "subnet-1"
cidr = "10.0.1.0/24"
},
{
name = "subnet-2"
cidr = "10.0.2.0/24"
}
]
},
{
name = "vpc-2"
cidr = "10.0.0.0/16"
subnets = [
{
name = "subnet-3"
cidr = "10.0.3.0/24"
},
{
name = "subnet-4"
cidr = "10.0.4.0/24"
}
]
}
]
}
We can use foreach
to create a VPC and its subnets for each map in the list.
resource "aws_vpc" "example" {
foreach = { for v in var.vpcs : v.name => v }
cidr_block = each.value.cidr
tags = {
Name = each.key
}
}
resource "aws_subnet" "example" {
for_each = { for v in var.vpcs, s in v.subnets : "${v.name}-${s.name}" => s }
vpc_id = aws_vpc.example[split("-", each.key)[0]].id
cidr_block = each.value.cidr
tags = {
Name = each.key
}
}
In this example, we use a nested for
expression to flatten the list of maps within a list of maps into a map of maps. The key of the map is a combination of the VPC name and the subnet name, which ensures uniqueness.
Best Practices for Using foreach
with List of Maps
Naming Conventions
Maintain clear and descriptive variable and resource names to enhance code readability. Meaningful names help in understanding the purpose of each element in the data structure.
Variable Validation
Implement robust variable validation to ensure that the input data adheres to expected formats. This reduces the chances of encountering errors during resource provisioning.
Code Organization
Organize your Terraform code in a modular and structured manner. Group related resources and variables, making it easier to manage and maintain your infrastructure codebase.
Common Errors and Troubleshooting
Error: “Cannot iterate over null value”
This error occurs when attempting to iterate over a variable that is null. Ensure that the input data for the variable is properly formatted and contains valid values.
Error: “Index out of range”
When working with indices, it’s crucial to ensure that the index values are within the valid range of the list. This error can be addressed by validating the length of the list before accessing elements.
Error: “Type mismatch”
Ensure that the data types of variables match the expected types. Type mismatches can lead to runtime errors, so validating types is essential.
Conclusion
Terraform’s foreach
construct is a powerful tool for managing collections of resources. While it can be a bit tricky to use with nested collections, with a bit of practice and understanding, it becomes a valuable asset in your IaC toolbox. Remember to always ensure uniqueness of keys when using foreach
, as Terraform uses these keys to identify individual resources.
About Saturn Cloud
Saturn Cloud is your all-in-one solution for data science & ML development, deployment, and data pipelines in the cloud. Spin up a notebook with 4TB of RAM, add a GPU, connect to a distributed cluster of workers, and more. Request a demo today to learn more.
Saturn Cloud provides customizable, ready-to-use cloud environments for collaborative data teams.
Try Saturn Cloud and join thousands of users moving to the cloud without
having to switch tools.