Hi @Danpatpang,
At the level of whole resources, Terraform distinguishes count
and for_each
because they each cause Terraform to track the individual instances differently: count
tracks instances by integers counting up from zero, while for_each
tracks the instances by strings.
dynamic
blocks are different in that they don’t require Terraform to do any special tracking of each individual block. Instead, it’s just as if you’d written multiple blocks out manually yourself, with the provider unable to tell the difference.
For that reason, for_each
inside a dynamic
block can work with any kind of collection, including lists as you’ve shown here. However, if you want to generate a different number of blocks in different cases then it’s important to ensure that your for_each
collection has a different number of elements in each case, which isn’t true in the first example you shared because [1]
and [0]
both have one element, and so will generate only one block.
Since this database_flags
block type seems to be representing a key/value pair, where multiple such blocks presumably represent multiple key/value pairs, you might find it easier to read and maintain if you factor out the database version condition into a more convenient data structure and then use that data structure in the dynamic
block.
For example, we can declare a map of maps that gives the “flags” for each database_version
as a Local Value:
locals {
database_flags = tomap({
MYSQL_5_7 = tomap({
# Note that the value argument in database_flags
# actually expects a string, so using a string here
# avoids type ambiguity that might cause Terraform
# to produce a type error here.
lower_case_table_names = "1"
})
})
}
Then your dynamic block can be based on whichever sub-map is appropriate for the selected database version:
dynamic "database_flags" {
for_each = try(local.database_flags[var.database_version], tomap({}))
content {
name = database_flags.key
value = database_flags.value
}
}
This uses try
to avoid generating an error if the selected database version has no entry in the local.database_flags
map. If there is such an element then it’ll use the elements of the nested map to generate zero or more database_flags
blocks. If you need to add, remove, or change flags in the future you can do so in the local value data structure and leave the dynamic
block unchanged.