Mastering Loops in Terraform
✨This article, will explain in detail how to implement loops and variables in your Terraform code to create dynamic and efficient infrastructure deployments. ✨
❄️Synopsis:
🌿 Understand how loops can make your Terraform configurations more dynamic and flexible.
❄️Loops:
🌿 Terraform provides a few primitives namely, the meta-parameter count, for_each and for expressions, a ternary operator, a lifecycle block called create_before_destroy, and a large number of functions - that allow you to do certain types of loops, if-statements, and zero-downtime deployments.
count parameter, to loop over resources and modules
for_each expressions, to loop over resources, inline blocks within a resource, and modules
for expressions, to loop over lists and maps
for string directive, to loop over lists and maps within a string
❄️Loops with the count Parameter:
🌿Created an AWS Identity and Access Management (IAM) user by clicking around the Console. Now that you have this user, you can create and manage all future IAM users with Terraform.
For a single IAM user
provider "aws" {
region = "us-east-2"
}
resource "aws_iam_user" "example" {
name = "neo"
}
🌿However, every Terraform resource has a meta-parameter you can use called count. count is Terraform’s oldest, simplest, and most limited iteration construct: all it does is define how many copies of the resource to create. Here’s how you use count to create three IAM users:
variable "user_names" {
description = "Create IAM users with these names"
type = list(string)
default = ["neo", "trinity", "morpheus"]
}
resource "aws_iam_user" "example" {
count = length(var.user_names)
name = var.user_names[count.index]
}
output "all_arns" {
value = aws_iam_user.example[*].arn
description = "The ARNs for all users"
}
❄️Loops with for_each Expressions:
🌿The for_each expression allows you to loop over lists, sets, and maps to create
Multiple copies of an entire resource
Multiple copies of an inline block within a resource
Multiple copies of a module
Multiple copies of an entire resource
resource "aws_iam_user" "example" {
for_each = toset(var.user_names)
name = each.value
}
🌿Note the use of toset to convert the var.user_names list into a set. This is because for_each supports sets and maps only when used on a resource. When for_each loops over this set, it makes each username available in each. value. The username will also be available in each.key, though you typically use each.key only with maps of key-value pairs
output "all_arns" {
value = values(aws_iam_user.example)[*].arn
}
Multiple copies of a module
module "users" {
source = "../../../modules/landing-zone/iam-user"
for_each = toset(var.user_names)
user_name = each.value
}
output "user_arns" {
value = values(module.users)[*].user_arn
description = "The ARNs of the created IAM users"
}
🌿Ability to create multiple inline blocks within a resource. For example, you can use for_each to dynamically generate tag inline blocks for the ASG in the webserver-cluster module.
Multiple copies of an inline block within a resource
variable "custom_tags" {
description = "Custom tags to set on the Instances in the ASG"
type= map(string)
default= {}
}
module "webserver_cluster" {
source = "../../../../modules/services/webserver-cluster"
cluster_name = "webservers-prod"
db_remote_state_bucket = "(YOUR_BUCKET_NAME)"
db_remote_state_key = "prod/data-stores/mysql/terraform.tfstate"
instance_type= "m4.large"
min_size = 2
max_size = 10
custom_tags = {
Owner = "team-foo"
ManagedBy = "terraform"
}
}
resource "aws_autoscaling_group" "example" {
launch_configuration = aws_launch_configuration.example.name
vpc_zone_identifier = data.aws_subnets.default.ids
target_group_arns = [aws_lb_target_group.asg.arn]
health_check_type= "ELB"
min_size = var.min_size
max_size = var.max_size
tag {
key = "Name"
value = var.cluster_name
propagate_at_launch = true
}
dynamic "tag" {
for_each = var.custom_tags
content {
key= tag.key
value = tag.value
propagate_at_launch = true
}
}
}
❄️Loops with for Expressions:
🌿for
expressions are used to transform and filter lists and maps in Terraform.
variable "names" {
description = "A list of names"
type= list(string)
default = ["neo", "trinity", "morpheus"]
}
How could you convert all of these names to uppercase?
🌿where LIST is a list to loop over, ITEM is the local variable name to assign to each item in LIST, and OUTPUT is an expression that transforms ITEM in some way.
output "upper_names" {
value = [for name in var.names : upper(name)]
}
❄️Loops with the for String Directive:
🌿String directives allow you to use control statements (e.g., for-loops and if-statements) within strings using a syntax similar to string interpolations, but instead of a dollar sign and curly braces (${…}), you use a percent sign and curly braces (%{…}).
Terraform supports two types of string directives: for-loops and conditionals.
🌿where COLLECTION is a list or map to loop over, ITEM is the local variable name to assign to each item in COLLECTION, and BODY is what to render each iteration (which can reference ITEM)
variable "names" {
description = "Names to render"
type = list(string)
default = ["neo", "trinity", "morpheus"]
}
output "for_directive" {
value = "%{ for name in var.names }${name}, %{ endfor }"
}
🕵🏻I also want to express that your feedback is always welcome. As I strive to provide accurate information and insights, I acknowledge that there’s always room for improvement. If you notice any mistakes or have suggestions for enhancement, I sincerely invite you to share them with me.
🤩 Thanks for being patient and following me. Keep supporting 🙏
Clap👏 if you liked the blog.
For more exercises — please follow me below ✅!
https://vjraghavanv.hashnode.dev/
#aws #terraform #cloudcomputing #IaC #DevOps #tools #operations #30daytfchallenge #HUG #hashicorp #HUGYDE #IaC #developers #awsugmdu #awsugncr #automatewithraghavan
Subscribe to my newsletter
Read articles from vijayaraghavan vashudevan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
vijayaraghavan vashudevan
vijayaraghavan vashudevan
I'm Vijay, a seasoned professional with over 13 years of expertise. Currently, I work as a Quality Automation Specialist at NatWest Group. In addition to my employment, I am an "AWS Community Builder" in the Serverless Category and have served as a volunteer in AWS UG NCR Delhi and AWS UG MDU, a Pynt Ambassador (Pynt is an API Security Testing tool), and a Browserstack Champion. Actively share my knowledge and thoughts on a variety of topics, including AWS, DevOps, and testing, via blog posts on platforms such as dev.to and Medium. I always like participating in intriguing discussions and actively contributing to the community as a speaker at various events. This amazing experience provides me joy and fulfillment! 🙂