如何遍历本地人并同时列出资源以生成资源

时间:2020-11-09 17:44:18

标签: 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
}

我想保持本地状态不变(每个模式使用不同的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

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

1 个答案:

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