我有以下tf文件:
locals {
schemas = {
"ODS" = {
usage_roles = ["TRANSFORMER"]
}
"EXT" = {
usage_roles = []
}
"INT" = {
usage_roles = ["REPORTER"]
}
"DW" = {
usage_roles = ["LOADER"]
}
}
}
resource "snowflake_schema" "schema" {
for_each = local.schemas
name = each.key
database = ???????
usage_roles = each.value.usage_roles
}
我想保持本地状态不变(每个模式使用不同的use_roles并在此处进行硬编码),同时为每个模式使用多个值作为数据库。用伪代码是:
for database in ['db_1', 'db_2', 'db_3']:
resource "snowflake_schema" "schema" {
for_each = local.schemas
name = each.key
database = database
usage_roles = each.value.usage_roles
}
以便我们在三个不同的数据库中拥有相同的架构资源。我已经阅读了一些文章,这些文章使我相信可以进行此循环但可以预先分配所有值,这意味着我必须将usage_roles放入列表或其他内容中,而不是在本地进行硬编码,我认为这是可读性较差。例如: Terraform - how to use for_each loop on a list of objects to create resources
甚至可能是我要的?如果是这样,怎么办?预先非常感谢
答案 0 :(得分:2)
对for_each
的主要要求是,您提供的地图每个要创建的资源实例必须具有一个元素。对于您而言,我认为这意味着您需要一种映射,每个映射和数据库与架构的每个组合都包含一个元素。
在两组中查找值的每个组合的操作被正式称为cartesian product,并且Terraform具有the setproduct
function来执行该操作。在您的情况下,要套用的两个集合是数据库名称的集合和模式映射中的键的集合,如下所示:
locals {
databases = toset(["db_1", "db_2", "db_3"])
database_schemas = [
for pair in setproduct(local.databases, keys(local.schemas)) : {
database_name = pair[0]
schema_name = pair[1]
usage_roles = local.schemas[pair[1]].usage_roles
}
]
}
然后local.database_schemas
值将为每个组合包含一个对象,如下所示:
[
{
database_name = "db_1"
schema_name = "ODS"
usage_roles = ["TRANSFORMER"]
},
{
database_name = "db_1"
schema_name = "EXT"
usage_roles = []
},
# ...
{
database_name = "db_2"
schema_name = "ODS"
usage_roles = ["TRANSFORMER"]
},
{
database_name = "db_2"
schema_name = "EXT"
usage_roles = []
},
# ...
{
database_name = "db_3"
schema_name = "ODS"
usage_roles = ["TRANSFORMER"]
},
{
database_name = "db_3"
schema_name = "EXT"
usage_roles = []
},
# ...
]
这符合您要创建的每个实例一个元素的要求,但是我们仍然需要将其转换为具有每个元素唯一键的地图,以为Terraform每个实例提供唯一的跟踪键,因此我们可以做一个for
参数中的更多for_each
投影:
resource "snowflake_schema" "schema" {
for_each = {
for s in local.database_schemas :
"${s.database_name}:${s.schema_name}" => s
}
name = each.value.schema_name
database = each.value.database_name
usage_roles = each.value.usage_roles
}
Terraform将使用以下地址跟踪这些实例:
snowflake_schema.schema["db_1:ODS"]
snowflake_schema.schema["db_1:EXT"]
snowflake_schema.schema["db_2:ODS"]
snowflake_schema.schema["db_2:EXT"]
snowflake_schema.schema["db_3:ODS"]
snowflake_schema.schema["db_3:EXT"]