Hi,
I’m struggling with getting a local variable be parsed as a map (rather than an object) in a setproduct
that contains a for
expression, where the local variable defined below
locals {
external_location_service_principal_access = [
for pair in setproduct(
local.storage_accounts_flat,
[
for service_principal_key, service_principal_object in local.service_principals :
merge({ service_principal_key = service_principal_key }, service_principal_object)
]
) :
merge(pair[0], pair[1])
if pair[0].databricks_external_location == true
&& length(pair[1].databricks.privileges_external_location) > 0
]
}
leads to the following error:
│ Error: Invalid function argument
│
│ on imports.tf line 17, in locals:
│ 15: for pair in setproduct(
│ 16: local.storage_accounts_flat,
│ 17: [
│ 18: for service_principal_key, service_principal_object in local.service_principals :
│ 19: merge({ service_principal_key = service_principal_key }, service_principal_object)
│ 20: ]
│ 21: ) :
│ ├────────────────
│ │ while calling setproduct(sets...)
│ │ local.service_principals is object with 3 attributes
│
│ Invalid value for "sets" parameter: all elements must be of the same type.
Some clarifications are in order to understand why this is unexpected:
- The referenced local variable
storage_accounts_flat
is a list of objects (all of the same type). - The local variable
service_principals
is defined as a map of objects, although it seems Terraform interprets it as an object instead. - The second argument in the
setproduct
intends to build a list of objects out of a map (taking a key-value pair and merging the key into the value) - The set product should therefore build the cartesian product of the two lists of objects, merging the object pairs.
I’m already using essentially the same logic to define some resource’s iterated instances in a module, and it works with no problem. Notice that the only difference between the local variable below and the one above is that the one below refers to a module variable service_principals
that is explicitly defined as a map of objects via type constraints.
locals {
external_location_service_principal_access = [
for pair in setproduct(
var.storage_accounts_flat,
[
for service_principal_key, service_principal_object in var.service_principals :
merge({ service_principal_key = service_principal_key }, service_principal_object)
]
) :
merge(pair[0], pair[1])
if pair[0].databricks_external_location == true
&& length(pair[1].databricks.privileges_external_location) > 0
]
}
resource "databricks_grant" "external_location_service_principal" {
for_each = {
for v in local.external_location_service_principal_access :
"${v.storage_account}.${v.container_name}.${v.service_principal_key}" => v
}
external_location = databricks_external_location.this["${each.value.storage_account}.${each.value.container_name}"].id
principal = data.databricks_service_principal.this[each.value.service_principal_key].application_id
privileges = each.value.databricks.privileges_external_location
}
I need the definition at the top (the one using the local variable service_principals
), to iterate an import block targeting the databricks_grant
resource. Somehow Terraform is attempting to expand the setproduct
arguments too deep until it stumbles with the local.service_principals
variable, which does have a different type but is enclosed within a for expression of list type, which should actually be the operand for the setproduct
.