Hi @sveniu!
The for_each
argument inside a dynamic
block is expecting a collection to use as the basis for repetition. In your case it looks like each.value.alias
is a single object rather than a list, and so what you need for for_each
is either a single-item list when the object is set or a zero-length list when it is null.
Fortunately, that particular situation is a special power of the [*]
splat operator when used on something that isn’t a list:
dynamic "alias" {
for_each = each.value.alias[*]
content {
name = each.value.name
zone_id = each.value.zone_id
evaluate_target_health = each.value.evaluate_target_health
}
}
each.value.alias[*]
will return [each.value.alias]
if each.value.alias
is non-null, or []
if it is null.
The other tricky part in this case is that we need to ensure that the records you are iterating over always have the same object type, which means that either records
or alias
will need to be present and null
rather than absent. We can do that normalization with a for
expression to transform the result of loading the YAML:
locals {
zone_data_raw = yamldecode(file("${path.module}/zone_data.yaml"))
zone_data = {
zone_id = zone_data_raw.zone_id
records = [for r in zone_data_raw.records : {
name = r.name
type = r.type
ttl = lookup(r, "ttl", null)
alias = lookup(r, "alias", null)
records = lookup(r, "records", null)
}]
}
}
The local.zone_data
value should conform to the type constraint you originally wrote for variable "zone_data"
, and sets alias
up in a way that the above technique of using [*]
will work.
When working with data loaded from external files (in JSON or YAML format) it’s often a good idea to do something like the above just to ensure that the data in the file conforms to the expected shape and normalize where necessary. This helps ensure that any errors dealing with the file can get reported close to where the file is loaded, rather than downstream when the value is used, and that can be helpful for future maintainers that might not get the YAML structure right on the first try.