微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 .tfvars 值的 terraform for_each 实现

如何解决使用 .tfvars 值的 terraform for_each 实现

我有一个 common.tfvars 文件,其中定义了一个变量:

bqtable_date_partition = [
  { dataset = "d1",table_name = "d1-t1",part_col = "partition_date",part_type = "DAY",schema_file = "data_tables/d1-t1.json" },{ dataset = "d1",table_name = "d1-t2",part_col = "tran_dt",schema_file = "data_tables/d1-t2.json" },{ dataset = "d2",table_name = "d2-t1",schema_file = "data_tables/d2-t1.json" },]

并且我在 main.tf 文件中使用以下资源定义引用此变量:

resource "google_bigquery_table" "bq_tables_dt_pt" {
  count      = length(var.bqtable_date_partition)
  project    = var.project_id
  dataset_id = "${var.bqtable_date_partition[count.index].dataset}_${var.env}"
  table_id   = var.bqtable_date_partition[count.index].table_name
  time_partitioning {
    type  = var.bqtable_date_partition[count.index].part_type
    field = var.bqtable_date_partition[count.index].part_col
  }
  schema     = file("${path.module}/tables/${var.bqtable_date_partition[count.index].schema_file}")
  depends_on = [google_bigquery_dataset.crte_bq_dataset]
  labels = {
    env        = var.env
    ind        = "corp"
  }
}

我想更改资源定义以使用“for_each”而不是“count”来循环遍历列表:

我从 count 更改为 for_each 的动机是消除对我编写变量“bqtable_date_partition”元素的顺序的依赖

我是这样做的:

resource "google_bigquery_table" "bq_tables_dt_pt" {
  for_each   = var.bqtable_date_partition
  project    = var.project_id
  dataset_id = "${each.value.dataset}_${var.env}"
  table_id   = each.value.table_name
  time_partitioning {
    type  = each.value.part_type
    field = each.value.part_col
  }
  schema     = file("${path.module}/tables/${each.value.schema_file}")
  depends_on = [google_bigquery_dataset.crte_bq_dataset]
  labels = {
    env        = var.env
    ind        = "corp"
  }
}

我按预期收到以下错误

给定的“for_each”参数值不合适:“for_each” 参数必须是一个映射或一组字符串,并且您提供了一个 字符串映射类型列表的值。

谁能帮助我在资源定义中进行哪些更改才能使用“for_each”?

terraform 版本 - 0.14.x

解决方法

错误说它只接受地图或字符串集。因此,我们必须将输入变量转换为映射或字符串集。

https://www.terraform.io/docs/language/expressions/for.html

resource "google_bigquery_table" "bq_tables_dt_pt" {
  for_each   = { for index,data_partition in var.bqtable_date_partition : index => data_partition }
  project    = var.project_id
  dataset_id = "${each.value.dataset}_${var.env}"
  table_id   = each.value.table_name
  time_partitioning {
    type  = each.value.part_type
    field = each.value.part_col
  }
  schema     = file("${path.module}/tables/${each.value.schema_file}")
  depends_on = [google_bigquery_dataset.crte_bq_dataset]
  labels = {
    env = var.env
    ind = "corp"
  }
}

所以基本上,这里我们将 for_each 输入转换为以下格式。并且只从新创建的地图中引用值。

{
  "0" = {
    "dataset" = "d1"
    "part_col" = "partition_date"
    "part_type" = "DAY"
    "schema_file" = "data_tables/d1-t1.json"
    "table_name" = "d1-t1"
  }
  "1" = {
    "dataset" = "d1"
    "part_col" = "tran_dt"
    "part_type" = "DAY"
    "schema_file" = "data_tables/d1-t2.json"
    "table_name" = "d1-t2"
  }
  "2" = {
    "dataset" = "d2"
    "part_col" = "tran_dt"
    "part_type" = "DAY"
    "schema_file" = "data_tables/d2-t1.json"
    "table_name" = "d2-t1"
  }
}
,

使用 for_each 有两个主要要求:

  • 对于要声明的每个资源实例,您必须拥有一个包含一个元素的集合。
  • 必须有某种方法可以从该集合的每个元素派生唯一标识符,然后 Terraform 将使用该标识符作为唯一实例键。

您的集合似乎满足这两个条件,假设 table_name 是所有这些值中的唯一字符串,因此剩下的就是将集合投影到地图中,以便 Terraform 可以从您打算将 table_name 用作唯一跟踪键的键:

resource "google_bigquery_table" "bq_tables_dt_pt" {
  for_each = {
    for o in var.bqtable_date_partition : o.table_name => o
  }

  # ...
}

在这里,我使用 for expression 将序列投影到映射,其中每个元素由其 table_name 属性中的值标识。


如果您处于能够更改此模块的接口的情况,那么您可以通过更改变量的声明以期望映射而不是列表来简化事情,这将避免对投影和向模块调用者明确表明表 ID 必须是唯一的:

variable "bqtable_date_partition" {
  type = map(object({
    dataset     = string
    part_col    = string
    part_type   = string
    schema_file = string
  }))
}

然后您可以像之前尝试的那样将 var.bqtable_date_partition 直接分配给 for_each,因为它已经是合适的类型了。但是还需要更改您的调用模块以传递映射值而不是列表值,因此如果您的模块有许多调用者都需要更新以保持兼容,这可能不切实际。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。