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