Terraform 12 Tutorial - Loops with count, for_each, and for
Here are the files.
main.tf:
terraform { required_version = ">= 0.12" } provider "aws" { region = "us-east-1" } resource "aws_iam_user" "users" { count = length(var.user_names) name = var.user_names[count.index] }
variables.tf:
variable "user_names" { description = "Create IAM users with these names" type = list(string) default = ["Paul_Dirac", "Erwin_Schrodinger", "Wolfgang_Pauli"] }
outputs.tf:
output "dirac_arn" { value = aws_iam_user.users[0].arn description = "The ARN for user Paul Dirac" } output "all_arns" { value = aws_iam_user.users[*].arn description = "The ARNs for all users" }
The following splat expression:
value = aws_iam_user.users[*].arn
is equivalent to:
[for u in aws_iam_user.users : u.arn]
The special [*] symbol iterates over all of the elements of the "users" given to its left and accesses from each one the attribute name given on its right.
Let's create the users:
$ terraform apply -auto-approve aws_iam_user.users[0]: Creating... aws_iam_user.users[2]: Creating... aws_iam_user.users[1]: Creating... aws_iam_user.users[2]: Creation complete after 1s [id=Wolfgang_Pauli] aws_iam_user.users[1]: Creation complete after 1s [id=Erwin_Schrodinger] aws_iam_user.users[0]: Creation complete after 1s [id=Paul_Dirac] Apply complete! Resources: 3 added, 0 changed, 0 destroyed. Outputs: all_arns = [ "arn:aws:iam::526262051452:user/Paul_Dirac", "arn:aws:iam::526262051452:user/Erwin_Schrodinger", "arn:aws:iam::526262051452:user/Wolfgang_Pauli", ] dirac_arn = "arn:aws:iam::526262051452:user/Paul_Dirac"
Clean up:
$ terraform destroy -auto-approve
Here are the files.
main.tf:
terraform { required_version = ">= 0.12" } provider "aws" { region = "us-east-1" } data "aws_availability_zones" "all" {} resource "aws_autoscaling_group" "example" { launch_configuration = aws_launch_configuration.example.id availability_zones = data.aws_availability_zones.all.names min_size = 2 max_size = 2 # Use for_each to loop over var.custom_tags dynamic "tag" { for_each = var.custom_tags content { key = tag.key value = tag.value propagate_at_launch = true } } } resource "aws_launch_configuration" "example" { image_id = "ami-07ebfd5b3428b6f4d" instance_type = "t2.nano" lifecycle { create_before_destroy = true } }
variables.tf:
variable "custom_tags" { description = "Custom tags to set on the Instances in the ASG" type = map(string) default = { "foo" = "bar" "faz" = "baz" } }
$ terraform apply $ aws autoscaling describe-auto-scaling-groups ... { ... "Tags": [ { "ResourceId": "tf-asg-20210331190752813400000002", "ResourceType": "auto-scaling-group", "Key": "faz", "Value": "baz", "PropagateAtLaunch": true }, { "ResourceId": "tf-asg-20210331190752813400000002", "ResourceType": "auto-scaling-group", "Key": "foo", "Value": "bar", "PropagateAtLaunch": true } ], ... } ]
Clean up:
$ terraform destroy
Here are the files.
main.tf:
terraform { required_version = ">= 0.12" } provider "aws" { region = "us-east-1" } resource "aws_instance" "server" { count = var.instances ami = "ami-07ebfd5b3428b6f4d" instance_type = "t2.nano" tags = { Name = "Server ${count.index}" } }
variables.tf:
variable "instances" { description = "number of ec2 instances" default = 2 }
outputs.tf:
output "instance_ip_addresses" { # Result is a map from instance id to private and public IP addresses, such as: # {"i-1234" = ["192.168.1.2","54.234.188.251,] "i-5678" = ["192.168.1.5","3.90.189.190",] } value = { for instance in aws_instance.server: instance.id => instance.private_ip } }
$ terraform apply aws_instance.server[0]: Creating... aws_instance.server[1]: Creating... ... Apply complete! Resources: 2 added, 0 changed, 0 destroyed. Outputs: instance_ip_addresses = { "i-03c52ae61c503c139" = [ "172.31.46.221", "3.90.189.190", ] "i-0c20197741dc3f9c9" = [ "172.31.33.73", "54.234.188.251", ] }
$ tree . ├── main.tf └── user.tfvars
main.tf:
provider "aws" { region = var.aws_region } variable "user_names" { description = "Create IAM users with these names" type = list(string) #default = ["jupiter", "saturn", "uranus"] } variable "aws_region" { description = "The AWS region in which the AWS infrastructure is created." type = string #default = "us-west-2" } resource "aws_iam_user" "example_count" { count = length(var.user_names) name = "${var.user_names[count.index]}-${count.index+1}" } resource "aws_iam_user" "example_for_each" { for_each = toset(var.user_names) name = each.value } output "all_user_arns_count" { value = aws_iam_user.example_count[*].arn description = "The ARNs for all count users" } output "all_users_for_each" { value = aws_iam_user.example_for_each[*] description = "All for_each users" } output "all_users_for_each_just_names" { value = values(aws_iam_user.example_for_each)[*].name description = "All for_each users just names" } output "names_in_uppercase" { value = [for n in var.user_names : upper(n)] } // map output "all_users_for_each_name_unique_id" { value = { for user in aws_iam_user.example_for_each: user.name => user.unique_id } }
user.tfvars:
user_names = [ "jupiter", "saturn", "uranus", ] aws_region = "us-west-2"
Let's run our terraform configuration:
$ terraform apply -var-file="user.tfvars" ... Outputs: all_user_arns_count = [ "arn:aws:iam::4***:user/jupiter-1", "arn:aws:iam::4***:user/saturn-2", "arn:aws:iam::4***:user/uranus-3", ] all_users_for_each = [ { "jupiter" = { "arn" = "arn:aws:iam::4***:user/jupiter" "force_destroy" = false "id" = "jupiter" "name" = "jupiter" "path" = "/" "permissions_boundary" = tostring(null) "tags" = tomap(null) /* of string */ "tags_all" = tomap({}) "unique_id" = "AIDAVPSFGBEED62MILPY6" } "saturn" = { "arn" = "arn:aws:iam::4***:user/saturn" "force_destroy" = false "id" = "saturn" "name" = "saturn" "path" = "/" "permissions_boundary" = tostring(null) "tags" = tomap(null) /* of string */ "tags_all" = tomap({}) "unique_id" = "AIDAVPSFGBEEOJ2FTUWJE" } "uranus" = { "arn" = "arn:aws:iam::4***:user/uranus" "force_destroy" = false "id" = "uranus" "name" = "uranus" "path" = "/" "permissions_boundary" = tostring(null) "tags" = tomap(null) /* of string */ "tags_all" = tomap({}) "unique_id" = "AIDAVPSFGBEEPMFD3FKSW" } }, ] all_users_for_each_just_names = [ "jupiter", "saturn", "uranus", ] all_users_for_each_name_unique_id = { "jupiter" = "AIDAVPSFGBEED62MILPY6" "saturn" = "AIDAVPSFGBEEOJ2FTUWJE" "uranus" = "AIDAVPSFGBEEPMFD3FKSW" } names_in_uppercase = [ "JUPITER", "SATURN", "URANUS", ]
Note that we keep the variables in main.tf to avoid any errors such as "Error: Reference to undeclared input variable"
To read the variables without specifying the "tfvars" file, we can rename it to "terraform.tfvars" and just issue "terraform apply" commmand. To get more information about the variable precedence, please check out : Variable Definition Precedence
Terraform
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization