Terraform 循环:for_each

Terraform loop : for_each

我需要帮助 运行 for_each 在 terraform 上使用以下变量集

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"]
      }
    }
  }

db_type两者都可以看情况。如果我们有多个 db_type 那么两个值都应该与最终资源相关联。

我还尝试了 flatten 变量

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
        }
      }
    ]
  ]
])

扁平化后的输出

[
  {
    "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"
  },
   ...
]

查看值的类型,如下

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,
    }),
])

问题: 我想达到什么目的???

负责此的资源如下。 在同一块中可以有尽可能多的 rolesscopes 。为此,我们可以为您提供动态块设置

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
  }
  ...
}

资源最终应该类似于以下值。

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"
}

使用了准确的源代码。 (我知道这是不正确的)。 这里 usernamedatabase_namerole_namenametype 都应该是一个字符串值

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: 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:考虑到上面的flatten value没有用。如何使用相同的 db_users 内容解决此问题?

PPS:我也可以使用 flatten value 只要它符合我的目的。

您的 db_users 应该以不同的方式展平,即:

locals {
 
    db_users_flat = merge([
    for username, clusters in local.db_users : 
      {
         for clustername, cluster in clusters : 
           "${username}-${clustername}" => {
                 username = username
                 clustername = clustername
                 cluster = cluster
            }
       }
  ]...) # please do NOT remove the dots
 
}

然后

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]
    }
  }
}