How to make sense of Terraform's for_each index
TL;DR
Using a map's key for indexing is not always preferred from a maintainability standpoint. Therefore, considering using the map's value is often a viable option.
Problem Statement
When iterating over a list of objects in Terraform using for_each
there is a pattern of using the index as an identifier as shown in this snippet:
resource "null_resource" "compile_dsc_configuration" {
for_each = {for k, v in local.dsc_configuration_data_path[*].data_file_path : k => v}
provisioner "local-exec" {
command = ". ./Invoke-AzDscCompilationJob.ps1 -AutomationAccountName ${var.aa_name} -ResourceGroupName ${var.aa_resource_group_name} -ConfigurationName SqlServerNode -ConfigurationDataPath ${each.value}"
interpreter = [
"pwsh", "-command"
]
}
}
This pattern will result in state references where the object in question is not easy to identify hen running state operations like taint or import:
terraform taint null_resource.compile_dsc_configuration["0"] # I have no clue which configuration will be tainted
Using the Value as Identifier
Alternatively, you can use a value (or a transposed version of it):
resource "null_resource" "compile_dsc_configuration" {
for_each = {for k, v in local.dsc_configuration_data_path[*].data_file_path : "${replace(basename(v), ".psd1", "")}" => v}
provisioner "local-exec" {
command = ". ./Invoke-AzDscCompilationJob.ps1 -AutomationAccountName ${var.aa_name} -ResourceGroupName ${var.aa_resource_group_name} -ConfigurationName SqlServerNode -ConfigurationDataPath ${each.value}"
interpreter = [
"pwsh", "-command"
]
}
}
Here, the loop will use a configuration data file name as index which makes it a lot easier to work with the resulting state:
terraform taint null_resource.compile_dsc_configuration["prod-vm"] # I will recompile the configuration for my prod-vm
Conclusion
I will try to update my internal wiring to use the updated pattern more often, as I struggled a lot in the past making sense of a loop's index.
For more content on Azure DSC with Terraform, hit me up on LinkedIn or Mastodon.