はじめに
今更ですが、 Terraform のループ構文である for_each を自分用備忘メモとしてまとめました。
基本的な使い方
for_each は、リストやマップを元にリソースを繰り返し生成する場合に使います。
for_each を指定すると、Terraform はリソースをループし、指定されたキーごとにリソースを作成します。
variable "buckets" {
type = list(string)
default = [
"test-bucket-1",
"test-bucket-2",
"test-bucket-3"
]
}
resource "aws_s3_bucket" "toset" {
for_each = toset(var.buckets)
bucket = each.key
}
# plan 結果
# aws_s3_bucket.toset["test-bucket-1"] will be created
+ resource "aws_s3_bucket" "toset" {
+ bucket = "test-bucket-1"
...
# aws_s3_bucket.toset["test-bucket-2"] will be created
+ resource "aws_s3_bucket" "toset" {
+ bucket = "test-bucket-2"
...
# aws_s3_bucket.toset["test-bucket-3"] will be created
+ resource "aws_s3_bucket" "toset" {
+ bucket = "test-bucket-3"
...
Plan: 3 to add, 0 to change, 0 to destroy.
マップでの使い方
マップを使うと、キーと値のペアでリソースを生成できます。
variable "bucket_map" {
type = map(string)
default = {
"test-bucket-1" : "dev"
"test-bucket-2" : "stg"
"test-bucket-3" : "prod"
}
}
resource "aws_s3_bucket" "map" {
for_each = var.bucket_map
bucket = "${each.key}-${each.value}"
}
# plan 結果
# aws_s3_bucket.map["test-bucket-1"] will be created
+ resource "aws_s3_bucket" "map" {
+ bucket = "test-bucket-1-dev"
...
# aws_s3_bucket.map["test-bucket-2"] will be created
+ resource "aws_s3_bucket" "map" {
+ bucket = "test-bucket-2-stg"
...
# aws_s3_bucket.map["test-bucket-3"] will be created
+ resource "aws_s3_bucket" "map" {
+ bucket = "test-bucket-3-prod"
...
Plan: 3 to add, 0 to change, 0 to destroy.
リストでのリソース生成(インデックス利用)
リストを使う場合、tolist()
で明示的に set 型から list 型に変換し、リストのインデックスを使ってユニークな ID を付けることができます。
以下では、インデックス idx
を利用してリソース ID をユニークにしています。
variable "buckets" {
type = list(string)
default = ["apple", "banana", "orange"]
}
resource "aws_s3_bucket" "list" {
for_each = { for idx, name in tolist(var.buckets) : idx => name }
bucket = "test-${each.value}-bucket-${each.key}"
}
# plan 結果
# aws_s3_bucket.list["0"] will be created
+ resource "aws_s3_bucket" "list" {
+ bucket = "test-apple-bucket-0"
...
# aws_s3_bucket.list["1"] will be created
+ resource "aws_s3_bucket" "list" {
+ bucket = "test-banana-bucket-1"
...
# aws_s3_bucket.list["2"] will be created
+ resource "aws_s3_bucket" "list" {
+ bucket = "test-orange-bucket-2"
...
Plan: 3 to add, 0 to change, 0 to destroy.
入れ子マップでの使い方
複雑なオブジェクトやマップの入れ子になったデータ構造を使うこともできます。
以下では、bucket_configs のそれぞれのオブジェクトから environment
と force_destroy
を抽出し、リソースに設定しています。
variable "bucket_configs" {
type = map(object({
environment = string
force_destroy = bool
}))
default = {
"apple" = { environment = "dev", force_destroy = true }
"banana" = { environment = "stg", force_destroy = true }
"orange" = { environment = "prod", force_destroy = false }
}
}
resource "aws_s3_bucket" "nest_map" {
for_each = var.bucket_configs
bucket = "test-${each.key}-bucket-${each.value.environment}"
force_destroy = each.value.force_destroy
}
# plan 結果
# aws_s3_bucket.nest_map["apple"] will be created
+ resource "aws_s3_bucket" "nest_map" {
+ bucket = "test-apple-bucket-dev"
+ force_destroy = true
...
# aws_s3_bucket.nest_map["banana"] will be created
+ resource "aws_s3_bucket" "nest_map" {
+ bucket = "test-banana-bucket-stg"
+ force_destroy = true
...
# aws_s3_bucket.nest_map["orange"] will be created
+ resource "aws_s3_bucket" "nest_map" {
+ bucket = "test-orange-bucket-prod"
+ force_destroy = false
...
Plan: 3 to add, 0 to change, 0 to destroy.
条件付き for_each
フィルタを使って条件付きで for_each を使うこともできます。
以下では deploy
が true
のリソースのみが作成されます。
variable "bucket_configs" {
type = map(object({
environment = string
force_destroy = bool
deploy = bool
}))
default = {
"apple" = { environment = "dev", force_destroy = true, deploy = true }
"banana" = { environment = "stg", force_destroy = true, deploy = true }
"orange" = { environment = "prod", force_destroy = false, deploy = false }
}
}
resource "aws_s3_bucket" "nest_map2" {
for_each = { for key, bucket in var.bucket_configs : key => bucket if bucket.deploy }
bucket = "test-${each.key}-bucket-${each.value.environment}"
force_destroy = each.value.force_destroy
}
# plan 結果
# aws_s3_bucket.nest_map2["apple"] will be created
+ resource "aws_s3_bucket" "nest_map2" {
+ bucket = "test-apple-bucket-dev"
+ force_destroy = true
...
# aws_s3_bucket.nest_map2["banana"] will be created
+ resource "aws_s3_bucket" "nest_map2" {
+ bucket = "test-banana-bucket-stg"
+ force_destroy = true
...
Plan: 2 to add, 0 to change, 0 to destroy.