Reference: original question Terraform loop : for_each
Similar to the question I have few changes which needs to be processed using the same method as well.
Changes
The value of db_type
could be between any of these two
db_type = [["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"]]
OR
db_type = ["CLUSTER", "CLUSTER", "CLUSTER"]
In this case, when I try to use the same example (changes on db_type only), as per the solution original question following error is observed
╷
│ Error: Incorrect attribute value type
│
│ on database_users.tf line 143, in resource "user" "user":
│ 143: type = each.value.cluster.db_type[scopes.key]
│ ├────────────────
│ │ each.value.cluster.db_type is tuple with 3 elements
│
│ Inappropriate value for attribute "type": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│ on database_users.tf line 143, in resource "user" "user":
│ 143: type = each.value.cluster.db_type[scopes.key]
│ ├────────────────
│ │ each.value.cluster.db_type is tuple with 3 elements
│
│ Inappropriate value for attribute "type": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│ on database_users.tf line 143, in resource "user" "user":
│ 143: type = each.value.cluster.db_type[scopes.key]
│ ├────────────────
│ │ each.value.cluster.db_type is tuple with 3 elements
│
│ Inappropriate value for attribute "type": string required.
Question: What I actually want? How do I achieve that?
db_type
as explained above following should be the outcome # mongodbatlas_database_user.user["test_user2-test_cluster2"] will be created
+ resource "mongodbatlas_database_user" "user" {
+ auth_database_name = "admin"
+ aws_iam_type = "NONE"
+ id = (known after apply)
+ ldap_auth_type = "NONE"
+ password = (sensitive value)
+ project_id = "6216f27d3f350c275ea78efb"
+ username = "test_user2"
+ x509_type = "NONE"
+ labels {
+ key = (known after apply)
+ value = (known after apply)
}
+ roles {
+ collection_name = (known after apply)
+ database_name = "db_d"
+ role_name = "readWrite"
}
+ roles {
+ collection_name = (known after apply)
+ database_name = "db_e"
+ role_name = "readWrite"
}
+ roles {
+ collection_name = (known after apply)
+ database_name = "db_f"
+ role_name = "read"
}
+ scopes {
+ name = "test_cluster2"
+ type = "CLUSTER"
}
+ scopes {
+ name = "test_cluster2"
+ type = "LAKE"
}
}
If the value of db_type = [["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"]]
, the Expected Output should be
Resource No. 1
username=test_user1
role = {
db_name=db_a
role=readWrite
}
role = {
db_name=db_b
role=read
}
role = {
db_name=db_c
role=readWrite
}
scope = {
name = test_cluster1
type = "cluster"
}
scope = {
name = test_cluster1
type = "lake"
}
Resource No. 2
username=test_user1
role = {
db_name=db_d
role=readWrite
}
role = {
db_name=db_e
role=read
}
role = {
db_name=db_f
role=readWrite
}
scope = {
name = test_cluster2
type = "cluster"
}
scope = {
name = test_cluster2
type = "lake"
}
...
If the value of db_type = db_type = ["CLUSTER", "CLUSTER", "CLUSTER"]
, the Expected Output should be
Resource No. 1
username=test_user1
role = {
db_name=db_a
role=readWrite
}
role = {
db_name=db_b
role=read
}
role = {
db_name=db_c
role=readWrite
}
scope = {
name = test_cluster1
type = "cluster"
}
Resource No. 2
username=test_user1
role = {
db_name=db_d
role=readWrite
}
role = {
db_name=db_e
role=read
}
role = {
db_name=db_f
role=readWrite
}
scope = {
name = test_cluster2
type = "cluster"
}
...
If I understand correctly, its better to use db_users
in the following form:
db_users = {
test_user1 = { #user
test_cluster1 = { #cluster
db_name = ["db_a", "db_b", "db_c"]
db_role = ["readWrite", "read", "readWrite"]
db_type = [["CLUSTER"], ["CLUSTER"], ["CLUSTER"]]
},
test_cluster2 = {
db_name = ["db_a", "db_b", "db_c"]
db_role = ["readWrite", "read", "readWrite"]
db_type = [["CLUSTER"], ["CLUSTER"], ["CLUSTER"]]
}
},
test_user2 = {
test_cluster1 = {
db_name = ["db_d", "db_e", "db_f"]
db_role = ["readWrite", "readWrite", "read"]
db_type = [["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"], ["CLUSTER", "LAKE"]]
},
test_cluster2 = {
db_name = ["db_d", "db_e", "db_f"]
db_role = ["readWrite", "readWrite", "read"]
db_type = [["CLUSTER"], ["CLUSTER"], ["CLUSTER"]]
}
}
}
then you flatten as:
db_users_flat = merge(flatten([
for username, clusters in local.db_users :
[
for clustername, cluster in clusters :
{
for idx, db_types in cluster.db_type:
"${username}-${clustername}-${idx}" => {
username = username
clustername = clustername
cluster = {
db_name = cluster.db_name
db_role = cluster.db_role
db_type = db_types
}
}
}
]
])...)
and use as:
resource "users" "user" {
for_each = local.db_users_flat
username = each.value.username
dynamic "roles" {
for_each = range(length(each.value.cluster.db_name))
content {
database_name = each.value.cluster.db_name[roles.key]
role_name = each.value.cluster.db_role[roles.key]
}
}
dynamic "scopes" {
for_each = range(length(each.value.cluster.db_type))
content {
name = each.value.clustername
type = each.value.cluster.db_type[scopes.key]
}
}
}