Terraform获取AWS AMI报错:values需字符串列表类型的解决咨询
问题描述
我需要用Terraform获取每周创建的特定AMI(ID未知,可通过名称检索)来更新EC2实例,采用了AWS External数据源、bash脚本实现,但遇到了类型错误。
报错信息
Error: Incorrect attribute value type
on main.tf line 20, in data "aws_ami" "get_ami_id":
20: values = "{$data.external.get_ami_name.results}"Inappropriate value for attribute "values": list of string required.
现有代码
get_ami_name.sh
#!/bin/bash AMI_NAME=$(aws ec2 describe-images --owners 5555566666 --query 'Images[?Name>=`em`][]'|grep Name|grep -v DeviceName|sort -n|tail -5|sort -t- -nrk5,5|awk '{print $2}'|sed 's/"//g') jq -n --arg ami_name "$AMI_NAME" '{"ami_name":$ami_name}'
main.tf
# 获取最新AMI名称 data "external" "get_ami_name" { program = ["bash", "${path.root}/get_ami_name.sh"] } output "ami_name_out" { value = ["data.external.get_ami_name.results"] } # 根据检索到的名称获取AMI ID data "aws_ami" "get_ami_id" { most_recent = true owners = ["555556666"] filter { name = "name" values = "{$data.external.get_ami_name.results}" } }
解决方案
1. 修复现有代码的错误
修正Terraform变量引用错误
values字段要求是字符串列表,你当前的写法有两个问题:
- 变量引用语法错误:应该用
${...}而非{$...} - 没有正确提取
ami_name字段:data.external.get_ami_name.results是一个map,需要指定键ami_name - 要把值包装成列表形式
修改后的data "aws_ami" "get_ami_id"部分:
data "aws_ami" "get_ami_id" { most_recent = true owners = ["555556666"] filter { name = "name" values = [data.external.get_ami_name.results.ami_name] } }
另外,output部分的写法也有误,应该直接引用map的字段,而非字符串:
output "ami_name_out" { value = data.external.get_ami_name.results.ami_name }
确保bash脚本返回单个AMI名称
你的bash脚本可能返回多个名称(因为用了tail -5),这会导致Terraform的filter匹配多个AMI,建议调整脚本只输出最新的一个名称,比如优化aws cli的query参数直接获取最新的:
#!/bin/bash # 用aws cli的query直接排序并取最新的AMI名称,避免复杂的文本处理 AMI_NAME=$(aws ec2 describe-images --owners 5555566666 --query 'sort_by(Images[?starts_with(Name, `em`)], &CreationDate)[-1].Name' --output text) jq -n --arg ami_name "$AMI_NAME" '{"ami_name":$ami_name}'
2. 更优实现:完全用Terraform内置功能(无需外部脚本)
直接使用Terraform的aws_ami数据源结合内置函数,不需要依赖bash脚本和external数据源,更符合Terraform的声明式风格:
data "aws_ami" "latest_target_ami" { most_recent = true owners = ["555556666"] filter { name = "name" values = ["em*"] # 匹配名称以em开头的AMI,可根据实际规则调整 } # 可选:筛选近7天创建的AMI,实现每周更新需求 filter { name = "creation-date" values = ["${formatdate("YYYY-MM-dd", timeadd(timestamp(), "-7d"))}*"] } } output "latest_ami_id" { value = data.aws_ami.latest_target_ami.id } output "latest_ami_name" { value = data.aws_ami.latest_target_ami.name }
说明:
- 用
"em*"直接匹配名称符合规则的AMI,替代bash里的文本过滤 - 可选的
creation-date过滤器精准筛选近7天创建的AMI most_recent = true确保获取最新的那个AMI,无需额外排序
内容的提问来源于stack exchange,提问作者MDM
相关产品推荐
相关产品推荐

