Suppose I have a Terragrunt configuration sitting on top of all the platform-boundary Databricks projects, that has a cluster module running. This module loops over the locals block which is defined in every PB main.tf
as such:
locals {
#... other local vars
clusters = {
clusterA = {
name = "clusterA"
#... other cluster config
},
clusterB = {
name = "clusterB"
#... other cluster config
}, ...
}
}
## main.tf
All the cluster names are unique. I wish now to delete every single cluster except for clusterX from a specific platform-boundary.
My goal is to basically set the for_each
within the cluster module to an empty set whenever I don't it doesn't loop over this specific cluster, but if it bumps into it I want the module to be executed.
I'm struggling to come up with the right conditional for this, the closest I got to a solution was the following:
locals{
run_cluster_module = contains(keys(local.clusters), "clusterX")
}
module "cluster" {
for_each = local.run_cluster_module ? local.clusters : {}
#... other module attributes
## terragrunt.hcl
This somehow raises inconsistency type errors. Any tips?
The { ... }
syntax in Terraform produces a value of an object type. In some cases Terraform is able to infer automatically that you intended to use a map value instead and convert it, but in this situation Terraform isn't sure enough about what you're intending to do, so it's not performing any automatic conversions.
The error message then describes the mismatch between the two different object types, in the hope that it will help you add the appropriate type conversions or other information to clarify what data type you intend the conditional expression to produce.
In this case I would suggest explicitly converting both values to maps. For example:
locals {
#... other local vars
clusters = tomap({
clusterA = {
name = "clusterA"
#... other cluster config
},
clusterB = {
name = "clusterB"
#... other cluster config
}, ...
})
}
module "cluster" {
for_each = local.run_cluster_module ? local.clusters : tomap({})
# ...
}
This tells Terraform that you intend local.clusters
to be a map of objects rather than an object itself. I can't predict exactly what that type would be with only the partial value of local.clusters
, but with only the name
attribute as you showed in your snippet local.clusters
would have the following type:
map(object({
name = string
}))
tomap({})
is special in that it produces "a map of unknown type" -- there's not enough information here to infer what the element type ought to be -- but the conditional expression should notice that one result has a known element type and the other does not, and thus it can automatically specialize the map of unknown element type into a map of known element type matching the type of local.clusters
.
Making this change might cause Terraform to begin complaining about a different part of your configuration instead. Giving Terraform more information will allow it to be more specific about where the problem is, and so it's likely that the new error will have the same root cause as the original error, but with additional information Terraform can make more confident assumptions about what you were intending to do and thus describe the problem more specifically.
In particular, note that all objects in a map of objects must have the same object type, which means that they must have the same attribute names and types. If there are some attributes that only apply to a subset of your clusters, you can set them to null
to make the types agree while still representing that some of the attributes are not populated.