04. Loops, iterations and conditions
Count and count index
In resource blocks where the count is set, an additional count object (count.index) is available in expressions, so that you can modify the configuration of each instance.
resource "aws_instance" "myec2" { count = 3 ami = "ami-0dab0800aa38826f2" instance_type = "t2.micro" tags = { Name = "myinstance-${count.index}" } }
output "arns" { value = aws_instance.myec2[*].arn }
List iteration
variable "users" { type = list(string) description = "user names" default = ["alice", "bob"] } resource "aws_iam_user" "myuser" { count = length(var.users) name = element(var.users, count.index) path = "/system/" tags = { tag-key = "tag-value" } }
Count vs for_each
- If your resources are almost identical, count is appropriate.
- If distinctive values are needed in the arguments, usage of for_each is recommended.
Set
SET items are unordered and no duplicates allowed.
Convert a list to a set : toset function (which removes ordering and duplicates)
for_each
With a set → each.key (which equals each.value)
resource "aws_iam_user" "iam" { for_each = toset(["user-0", "user-01", "user-02", "user-03"]) name = each.key }
→ each.key value is used to reference a given instance: aws_iam_user.iam["user-0"].
With a map → each.key / each.value
resource "aws_instance" "myec2" { ami = "ami-0cea098ed2ac54925" for_each = { little_instance = "t2.micro" big_instance = "t2.medium" } instance_type = each.value tags = { Name = each.key } }
→ each.key value is used to reference a given instance: aws_instance.myec2["little_instance"].
Conditional Expression
variable "istest" {} resource "aws_instance" "dev" { ami = "ami-082b5a644766e0e6f" instance_type = "t2.micro" count = var.istest == true ? 3 : 0 } resource "aws_instance" "prod" { ami = "ami-082b5a644766e0e6f" instance_type = "t2.large" count = var.istest == false ? 1 : 0 }
Dynamic block
Dynamic Block allows to dynamically construct repeatable nested blocks inside resource, data, provider, and provisioner blocks.
Note: this feature is a bit difficult to read and therefore, alternatives should be used when it is possible.
variable "sg_ports" { type = list(number) description = "list of ingress ports" default = [8200, 8201, 8300, 9200, 9500] } resource "aws_security_group" "dynamicsg" { name = "dynamic-sg" description = "Ingress for Vault" # with an iterator dynamic "ingress" { for_each = var.sg_ports iterator = port content { from_port = port.value to_port = port.value protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } # without iterator, the variable is the label dynamic "egress" { for_each = var.sg_ports content { from_port = egress.value to_port = egress.value protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } }
Remember!
count → count.index
for_each
- with a set → each.key == each.value
- with a map → each.key / each.value
dynamic_bloc
- by default: label of the dynamic block
- with an iterator: the iterator name