I need help to run for_each on terraform for following variable set
locals {
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"]]
db_type = ["CLUSTER", "CLUSTER", "CLUSTER"]
},
test_cluster2 = {
db_name = ["db_d", "db_e", "db_f"]
db_role = ["readWrite", "readWrite", "read"]
db_type = ["CLUSTER", "CLUSTER", "CLUSTER"]
}
}
}
The db_type can be both based on the situation. If we have multiple db_type then both value should be associated with the final resource.
I also tried flatten of the variable with following
value = flatten([
for ip_key, ip in local.db_users : [
for a, b in ip : [
for index in range(length(b.db_name)) : {
username = ip_key
user_index = index
roles = {
role_name = b.db_role[index]
database_name = b.db_name[index]
}
scopes = {
type = b.db_type[index]
name = a
}
}
]
]
])
Output after flattening the value
[
{
"roles" = {
"database_name" = "db_a"
"role_name" = "readWrite"
}
"scopes" = {
"name" = "test_cluster1"
"type" = "CLUSTER"
}
"username" = "test_user1"
},
{
"roles" = {
"database_name" = "db_b"
"role_name" = "read"
}
"scopes" = {
"name" = "test_cluster1"
"type" = "CLUSTER"
}
"username" = "test_user1"
},
...
{
"roles" = {
"database_name" = "db_d"
"role_name" = "readWrite"
}
"scopes" = {
"name" = "test_cluster1"
"type" = "CLUSTER"
}
"username" = "test_user2"
},
{
"roles" = {
"database_name" = "db_e"
"role_name" = "readWrite"
}
"scopes" = {
"name" = "test_cluster1"
"type" = "CLUSTER"
}
"username" = "test_user2"
},
...
]
Looking into the type of the value, it is as follows
tuple([
object({
roles: object({
database_name: string,
role_name: string,
}),
scopes: object({
name: string,
type: string,
}),
username: string,
}),
...
object({
roles: object({
database_name: string,
role_name: string,
}),
scopes: object({
name: string,
type: string,
}),
username: string,
}),
])
Question: What I want to achieve???
- I want to create the resource from this particular variable
The resource which is responsible for this is the following. There can be as many roles and scopes in the same block as possible. For this we can you dynamic block setup
resource "users" "user" {
username = var.username
roles {
database_name = var.database_name
role_name = var.role_name
}
roles {
database_name = var.database_name
role_name = var.role_name
}
...
scopes {
name = var.cluster
type = var.type
}
scopes {
name = var.cluster
type = var.type
}
...
}
and the resource should finally look like the following value.
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"
}
Resource No. 3
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. 4
username=test_user2
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"
}
Exact Source code used. ( I know this is not correct).
here username, database_name, role_name, name, and type all should be a string value
resource "users" "user" {
for_each = local.db_users
username = each.key
dynamic "roles" {
for_each = each.value
content {
database_name = each.value.db_name
role_name = each.value.db_role
}
}
dynamic "scopes" {
for_each = each.value
content {
name = each.key
type = each.value.db_type
}
}
}
Error
│ Error: Unsupported attribute
│
│ on database_users.tf line 25, in resource "mongodbatlas_database_user" "user":
│ 25: database_name = each.value.db_name
│ ├────────────────
│ │ each.value is object with 2 attributes
│
│ This object does not have an attribute named "db_name".
╷
│ Error: Unsupported attribute
│
│ on database_users.tf line 26, in resource "mongodbatlas_database_user" "user":
│ 26: role_name = each.value.db_role
│ ├────────────────
│ │ each.value is object with 2 attributes
│
│ This object does not have an attribute named "db_role".
╵
╷
│ Error: Unsupported attribute
│
│ on database_users.tf line 33, in resource "mongodbatlas_database_user" "user":
│ 33: type = each.value.db_type
│ ├────────────────
│ │ each.value is object with 2 attributes
│
│ This object does not have an attribute named "db_type".
╵
PS: considering the above flatten value is not used. How to solve this using the same db_users contents?
PPS: I am also okay with using of flatten value as long as it serves my purpose.
for_eachorcountto create yourresource "users" "user"?type = "lake"? Your localdb_usersdoes not have anylakein it?for_eachbut I did not succeed while trying to get the exact output as I required as shown in the resource section. thetype = lakeis the type of cluster. so basically if I have a clusterA withtype=clusterand clusterBtype=lakeboth the cluster should be added on the scope of the database.