如何用for_each替代count实现SSM参数的条件式数据资源与创建?
用for_each替代count实现SSM参数的条件式创建与数据资源保留
问题描述
我需要为SSM参数创建条件式数据资源:账号中已有通过data资源获取的现有SSM参数,需创建新参数但保留遗留项的data资源;理想逻辑是检测SSM资源是否存在,不存在则创建。当前使用count会引发下游额外变更,能否用for_each替代count?
现有代码:
data "aws_ssm_parameter" "ssm_vpc_id" { count = var.somevar == true ? 1 : 0 name = "/network/${var.deployment}/vpc/id" } resource "aws_ssm_parameter" "ssm_vpc_id" { count = var.somevar == true ? 0 : 1 name = "/network/${var.deployment}/vpc/id" type = "String" value = "aws_vpc.vpc.id" }
为什么count会引发下游变更
count生成的资源以列表形式存在(例如aws_ssm_parameter.ssm_vpc_id[0]),当count值在0和1之间切换时,下游引用的索引会发生变化,Terraform会将其识别为资源的创建/销毁替换操作,进而触发不必要的下游变更。而for_each基于键值对生成资源,引用时使用固定的键名,能避免这类问题。
用for_each替代count的解决方案
方案1:基于var.somevar的条件控制
将count替换为for_each,通过布尔值转换为包含参数名称的集合(空集合则不创建/获取资源):
data "aws_ssm_parameter" "ssm_vpc_id" { for_each = var.somevar ? toset(["/network/${var.deployment}/vpc/id"]) : toset([]) name = each.key } resource "aws_ssm_parameter" "ssm_vpc_id" { for_each = var.somevar ? toset([]) : toset(["/network/${var.deployment}/vpc/id"]) name = each.key type = "String" value = aws_vpc.vpc.id # 修正原代码错误:直接引用资源属性,而非字符串 }
关键说明:
- for_each接收set类型参数,条件满足时集合包含目标参数名称,否则为空,以此控制data/resource的创建
- 下游引用时使用键名而非索引,例如
aws_ssm_parameter.ssm_vpc_id["/network/${var.deployment}/vpc/id"],即使条件切换,引用路径保持稳定,避免下游变更 - 修正了原代码中value的错误:原代码将
aws_vpc.vpc.id写为字符串,会导致SSM参数存储的是字面量而非实际VPC ID,需直接引用资源属性
方案2:自动检测参数是否存在(无需依赖var.somevar)
如果希望自动检测SSM参数是否存在,而非依赖外部变量,可以结合ignore_errors和exists属性实现:
data "aws_ssm_parameter" "ssm_vpc_id" { name = "/network/${var.deployment}/vpc/id" ignore_errors = true # 参数不存在时不报错,而是返回exists=false } resource "aws_ssm_parameter" "ssm_vpc_id" { for_each = data.aws_ssm_parameter.ssm_vpc_id.exists ? toset([]) : toset(["/network/${var.deployment}/vpc/id"]) name = each.key type = "String" value = aws_vpc.vpc.id }
逻辑说明:
- 先尝试获取目标SSM参数,开启
ignore_errors避免参数不存在时Terraform报错 - 根据data资源的
exists属性判断:如果参数已存在,则不创建资源;否则创建新的SSM参数
内容的提问来源于stack exchange,提问作者manoman687
相关产品推荐
相关产品推荐

