Terraform setproduct创建CloudWatch告警报无id属性错误
Terraform创建EC2+EBS维度CloudWatch告警属性不存在报错修复
需求说明
遍历data.tf中定义的所有EC2实例,再匹配对应EBS卷ID,为每一组实例与卷的组合生成独立的CloudWatch告警。
现有配置
数据源定义(data.tf)
data "aws_instances" "instance_cloudwatch" { instance_tags = { Type = var.type } } data "aws_ebs_volumes" "cw_volumes" { tags = { Name = var.name } } data "aws_ebs_volume" "cw_volume" { for_each = toset(data.aws_ebs_volumes.cw_volumes.ids) filter { name = "volume-id" values = [each.value] } }
实例-卷映射关系定义
locals { vol_map = { for pair in setproduct(data.aws_instances.instance_cloudwatch.ids, data.aws_ebs_volume.cw_volume.*.id) : "${pair[0]}-${pair[1]}" => { id = pair[0] vol = pair[1] } } }
告警资源引用
resource "aws_cloudwatch_metric_alarm" "some_alarm" { for_each = local.vol_map # 其余告警配置省略 dimensions = { InstanceId = each.value.id VolumeId = each.value.vol } }
报错现象
执行terraform apply时抛出Unsupported attribute错误,报错指向setproduct遍历data.aws_ebs_volume.cw_volume.*.id的代码行,提示对象不存在名为id的属性,将id替换为volume_id后仍出现相同错误。
问题根因
使用for_each声明的数据源属于映射(map)类型,而非列表类型,无法直接使用旧版splat表达式.*批量提取属性。data.aws_ebs_volume.cw_volume的结构是以卷ID为键、单个EBS卷数据源对象为值的map,直接调用data.aws_ebs_volume.cw_volume.*.id时,Terraform会尝试在map结构本身查找id属性,自然会抛出属性不存在的错误,和属性名是id还是volume_id无关。
修复方案
先通过values()函数提取map中的所有数据源对象为列表,再批量提取卷ID,也可以用for表达式遍历map提取ID,兼容性更好。修改后的local配置如下:
locals { # 方式1:values提取map值后使用splat取ID ebs_volume_ids = values(data.aws_ebs_volume.cw_volume)[*].id # 方式2:for表达式遍历提取,适配更多Terraform版本 # ebs_volume_ids = [for vol in data.aws_ebs_volume.cw_volume : vol.id] vol_map = { for pair in setproduct(data.aws_instances.instance_cloudwatch.ids, local.ebs_volume_ids) : "${pair[0]}-${pair[1]}" => { id = pair[0] vol = pair[1] } } }
补充:
aws_ebs_volume单数据源的卷ID属性确实为id,不需要修改为volume_id。
内容的提问来源于stack exchange,提问作者Barak
相关产品推荐
相关产品推荐

