具有来自 .tfvars 的值的 terraform for_each 实现
Posted
技术标签:
【中文标题】具有来自 .tfvars 的值的 terraform for_each 实现【英文标题】:terraform for_each implementation with values from .tfvars 【发布时间】:2021-08-20 19:48:36 【问题描述】:我有一个 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",
part_type = "DAY", schema_file = "data_tables/d1-t2.json" ,
dataset = "d2", table_name = "d2-t1", part_col = "tran_dt",
part_type = "DAY", schema_file = "data_tables/d2-t1.json" ,
]
我在 main.tf 文件中使用以下资源定义引用此 var:
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
【问题讨论】:
【参考方案1】:错误说它只接受映射或字符串集。所以我们必须将输入变量转换为映射或字符串集。
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"
【讨论】:
我从 count 更改为 for_each 的动机是消除对我编写变量“bqtable_date_partition”元素的顺序的依赖。我尝试了您的解决方案,但在这一点上,通过查看计划,我也觉得顺序很重要,在我的计划中,它说它将破坏 3 个资源并创建 3 个。【参考方案2】:使用for_each
有两个主要要求:
您的集合似乎符合这两个标准,假设 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
,因为它已经是合适的类型。但也需要更改您的调用模块以传递映射值而不是列表值,因此如果您的模块有许多调用者都需要更新以保持兼容,这可能不切实际。
【讨论】:
以上是关于具有来自 .tfvars 的值的 terraform for_each 实现的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 jquery 创建具有来自动态创建的表单字段的值的多维数组?
Spark和Scala,通过映射公用键添加具有来自另一个数据帧的值的新列[重复]