You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Terraform中通过JSON配置结合for_each的data块正确引用资源?

使用JSON配置Terraform Data块并关联Resource的问题解答

问题描述

尝试通过传入JSON配置创建Terraform资源,让resource遍历该JSON配置,但JSON中的部分值需要用于data块的过滤器配置,询问是否可以实现并正确引用data块返回的对应VPC和子网项。

给出的JSON配置示例

[
{
  "username": "administrator",
  "password": "password",
  "domain_name": "test.io",
  "dns": "[10.10.1.6]",
  "vpc_name": "Sandbox*",
  "subnet_name": "*private*",
  "org_unit": "OU=test,DC=awstest,DC=io"
},
{
  "domain": "awstest.io",
  "username": "administrator",
  "password": "password2"
}
]

当前Terraform代码

locals {
  DirectoryServices = jsondecode(var.json)
}

data "aws_vpc" "this" {
  for_each = local.DirectoryServices
  filter {
    name   = "tag:Name"
    values = [each.value.vpc_name]
  }
}

data "aws_subnets" "this" {
  for_each = local.DirectoryServices
  filter {
    name   = "tag:Name"
    values = [each.value.subnet_name]
  }
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.this.id]
  }
}

locals {
  subnets = slice(data.aws_subnets.this.ids, 0, 2)
}

resource "aws_directory_service_directory" "connector" {
  for_each = local.DirectoryServices

  name     = each.value.domain_name
  password = each.value.password
  size     = each.value.size
  type     = "ADConnector"

  connect_settings {
    customer_dns_ips  = each.value.dns
    customer_username = each.value.username
    subnet_ids        = data.aws_subnets.this.ids
    vpc_id            = data.aws_vpc.this.id
  }
}

解答:可以实现,但需修正代码中的关键问题

当前代码存在几个核心问题,导致无法正确关联data块和resource,以下是修正方案和关键说明:

1. 处理JSON字段缺失问题

第二个JSON条目缺少vpc_name、subnet_name等必要字段,直接遍历会报错。需要先过滤出包含所有必要字段的条目,或给缺失字段设置默认值:

locals {
  # 解析JSON并过滤出包含必要字段的条目,避免报错
  DirectoryServices = [
    for item in jsondecode(var.json) : item
    if contains(keys(item), "vpc_name") && contains(keys(item), "subnet_name") && contains(keys(item), "domain_name") && contains(keys(item), "dns")
  ]
  # 转换为映射,用唯一的domain_name作为键,方便for_each关联
  DirectoryServices_map = {
    for item in local.DirectoryServices : item.domain_name => item
  }
}

2. 修正data块的引用方式

使用for_each后,data资源会变成映射类型,不能直接用data.aws_vpc.this.id,必须通过each.key关联对应的实例:

data "aws_vpc" "this" {
  for_each = local.DirectoryServices_map
  filter {
    name   = "tag:Name"
    values = [each.value.vpc_name]
  }
}

data "aws_subnets" "this" {
  for_each = local.DirectoryServices_map
  filter {
    name   = "tag:Name"
    values = [each.value.subnet_name]
  }
  filter {
    name   = "vpc-id"
    values = [data.aws_vpc.this[each.key].id] # 通过each.key匹配对应的VPC
  }
}

3. 修正resource块的格式和引用

  • JSON中的dns是字符串形式的列表,需要用jsondecode转成Terraform可识别的列表
  • 子网切片要针对每个实例单独处理,不能全局切片
  • 给缺失的size字段设置默认值:
resource "aws_directory_service_directory" "connector" {
  for_each = local.DirectoryServices_map

  name     = each.value.domain_name
  password = each.value.password
  size     = each.value.size != null ? each.value.size : "Small" # 默认小型实例
  type     = "ADConnector"

  connect_settings {
    customer_dns_ips  = jsondecode(each.value.dns) # 转换字符串列表为Terraform列表
    customer_username = each.value.username
    subnet_ids        = slice(data.aws_subnets.this[each.key].ids, 0, 2) # 取当前实例的前2个子网
    vpc_id            = data.aws_vpc.this[each.key].id
  }
}

关键注意事项

  • 确保JSON中用于遍历的条目有唯一标识(比如domain_name),避免for_each键冲突
  • 所有依赖字段必须存在或有默认值,否则Terraform会在计划阶段报错
  • 通过each.key关联data和resource实例,保证每个资源对应正确的VPC和子网

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:25:01