Introduction
Problem
When changing the values of a variable that is used by a for_each
the resource is re-created.
Prerequisites
Have the following code:
locals {
names = {
"my_index" = {
name = "my_name"
}
}
}
resource "terraform_data" "example" {
for_each = local.names
input = each.key
}
Observe that the input
value for the terraform_data
resource is using each.key
. This is referring to the index in the names
local.
If you now want to change the value of the input, you will need to change the key my_index
in the local
names
.
If we change the index my_index
to my_index_changed
and you run a terraform
plan
it will result in the following plan output:
terraform_data.example["my_index"]: Refreshing state... [id=9012385b-25d6-5fc0-403e-7cbb4291fe2d]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
- destroy
Terraform will perform the following actions:
# terraform_data.example["my_index"] will be destroyed
# (because key ["my_index"] is not in for_each map)
- resource "terraform_data" "example" {
- id = "9012385b-25d6-5fc0-403e-7cbb4291fe2d" -> null
- input = "my_index" -> null
- output = "my_index" -> null
}
# terraform_data.example["my_index_changed"] will be created
+ resource "terraform_data" "example" {
+ id = (known after apply)
+ input = "my_index_changed"
+ output = (known after apply)
}
Plan: 1 to add, 0 to change, 1 to destroy.
Cause
Terraform is using the index of a for_each
as a reference in the state file to keep track of the resource. By changing the index from my_index
to my_index_changed
, terraform determines that the resource with index my_index
is in the state file, but not in the code anymore. Therefore it will want to destroy this resource.
Likewise terraform will want to create the resource with index my_index_changed
, as it is not in the state file, but is present in the code.
It is the same effect as changing the resource name itself. If you would change the name of the terraform_data
resource example
to example_changed
, terraform will also want to re-create the resource because the name changed.
Solutions
The solution is not to use the index of a variable as input for a resource, but use value instead.
Have the following code:
locals {
names = {
"my_index" = {
name = "my_name"
}
}
}
resource "terraform_data" "example" {
for_each = local.names
input = each.value.name
}
Observe that input
in the terraform_data
resource now has the value: each.value.name
.
If we now change me_name
to my_name_changed
and run a plan, terraform will want to update the resource in place.
terraform_data.example["my_index"]: Refreshing state... [id=9012385b-25d6-5fc0-403e-7cbb4291fe2d]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# terraform_data.example["my_index"] will be updated in-place
~ resource "terraform_data" "example" {
id = "9012385b-25d6-5fc0-403e-7cbb4291fe2d"
~ input = "my_name" -> "my_name_changed"
~ output = "my_name" -> (known after apply)
}
Plan: 0 to add, 1 to change, 0 to destroy.
By leaving the index value in the local names
the same, terraform will not want to recreate the resource.