使用timestamp()的Terraform for_each无法执行plan的解决方法
问题解决:Terraform for_each 依赖 timestamp() 导致计划阶段报错
错误原因
Terraform 的 for_each 要求在计划(plan)阶段就能明确集合的元素数量和每个元素的唯一标识,而 timestamp() 属于「应用(apply)阶段函数」——它的实际值只有在执行 apply 操作时才能确定,这直接导致 local.alert_policies_ext_vars 的内容在 plan 阶段无法固定,Terraform 无法提前预判要创建多少个 null_resource.test 实例,因此抛出错误。
解决方案
根据实际需求,有以下几种可行的处理方式:
方式一:将时间判断移至 Provisioner 内部
保持 for_each 遍历固定的策略组集合,把时间筛选逻辑放到 local-exec 中,仅在 apply 阶段执行符合时间条件的操作:
resource "null_resource" "test" { # 遍历固定的alert_policies_groups,plan阶段可确定实例数量 for_each = { for idx, group in local.alert_policies_groups : idx => group } provisioner "local-exec" { interpreter = ["bash", "-c"] command = <<EOT CURRENT_DAY="${formatdate("EEEE", timestamp())}" # 判断当前日期是否在当前组的timeslot范围内 if [[ " ${join(" ", each.value.timeslot)} " =~ " \$CURRENT_DAY " ]]; then echo "Processing policy group: ${jsonencode(each.value)}" fi EOT } }
方式二:用静态变量传入目标日期
如果可以接受基于「计划执行时的日期」而非「应用执行时的日期」筛选,可将目标日期定义为变量,让其在 plan 阶段即可确定值:
# 定义变量,可手动指定目标日期,默认值为计划执行时的日期 variable "target_day" { type = string default = formatdate("EEEE", timestamp()) } locals { alert_policies_groups = [ { version = "v2" timeslot = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"] }, { version = "v2" timeslot = ["Saturday", "Sunday"] }, ] # 基于变量筛选,plan阶段即可确定结果集合 alert_policies_ext_vars = distinct(flatten([ for key, value in local.alert_policies_groups : [ merge(value, { timeslot = null }) ] if contains(value.timeslot, var.target_day) ])) } resource "null_resource" "test" { # 用map形式遍历,避免列表索引变动导致资源重建 for_each = { for idx, group in local.alert_policies_ext_vars : idx => group } provisioner "local-exec" { command = "echo ${jsonencode(each.value)}" } }
执行 plan 时可手动指定日期:
terraform plan -var target_day="Saturday"
方式三:外部脚本提前确定筛选条件
如果必须基于「apply 时的准确时间」动态创建资源,可通过外部脚本提前计算目标日期,生成 Terraform 变量文件后再执行操作:
- 编写 shell 脚本(比如
prepare.sh):
#!/bin/bash # 获取当前日期(apply时的日期) TARGET_DAY=$(date +%A) # 生成terraform.tfvars文件 cat > terraform.tfvars <<EOF target_day = "$TARGET_DAY" EOF # 执行Terraform terraform apply
- 修改 Terraform 代码,读取变量文件中的
target_day进行筛选(同方式二的变量定义和本地逻辑)。
额外注意点
原代码中 local.alert_policies_ext_vars[0] 的写法存在问题:当使用 for_each 时,应通过 each.value 访问当前实例对应的元素,而非固定索引 0,否则所有实例都会输出同一个元素的值。
内容的提问来源于stack exchange,提问作者DISCO
相关产品推荐
相关产品推荐

