如何同时循环本地和列出来生成资源

Jav*_*más 2 terraform

我有以下 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
}
Run Code Online (Sandbox Code Playgroud)

我想按原样维护本地变量(每个模式有不同的 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
    }
Run Code Online (Sandbox Code Playgroud)

这样我们在三个不同的数据库中就有相同的模式资源。我读过一些文章,这些文章让我相信可以进行此循环,但预先分配所有值,这意味着我必须将 use_roles 放入列表或其他内容中,而不是在本地中进行硬编码,我认为这是可读性较差。例如: Terraform - 如何在对象列表上使用 for_each 循环来创建资源

我所要求的甚至可能吗?如果是这样,怎么办?预先非常感谢

Mar*_*ins 6

主要要求for_each是您提供的映射必须为您要创建的资源的每个实例包含一个元素。就您而言,我认为这意味着您需要一张映射,其中每个数据库和模式组合都有一个元素。

查找两个集合中值的每个组合的操作正式称为笛卡尔积,Terraform 具有执行该操作的函数setproduct在您的情况下,要应用它的两个集合是数据库名称集和模式映射中的键集,如下所示:

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
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

然后,该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   = []
  },
  # ...
]
Run Code Online (Sandbox Code Playgroud)

这满足了要创建的每个实例有一个元素的要求,但我们仍然需要将其转换为每个元素具有唯一键的地图,以便为 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
}
Run Code Online (Sandbox Code Playgroud)

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"]
  • ...