terraform-provider-aws 中 aws_ami_ids 数据源详解:AMI 批量检索的参数、实现与测试验证
2026/9/17 19:07:08 网站建设 项目流程

terraform-provider-aws 中 aws_ami_ids 数据源详解:AMI 批量检索的参数、实现与测试验证

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

本篇围绕 Terraform AWS Provider 的aws_ami_ids数据源展开:它会按ownersfilter等条件调用 EC2DescribeImagesAPI 批量查找 AMI,并将匹配到的镜像 ID 列表以ids属性输出。读完本文,你将掌握该数据源全部参数(含name_regex本地正则过滤、sort_ascending排序、include_deprecated等)的正确用法,并能从源码层面理解其分页查询、错误处理与 ID 排序的完整链路。

典型用法:按属主与名称模式筛选 AMI

aws_ami_ids的定位是“获取一组 AMI ID 列表”(官方文档见 website/docs/d/ami_ids.html.markdown)。最典型的场景是只查某一个属主(如 Ubuntu 官方账户099720109477)名下符合名称模式的全部镜像:

data "aws_ami_ids" "ubuntu" { owners = ["099720109477"] filter { name = "name" values = ["ubuntu/images/ubuntu-*-*-amd64-server-*"] } }

此时data.aws_ami_ids.ubuntu.ids即返回所有匹配的 AMI ID 列表。需要强调的是:owners是必填项,且至少提供一个值——源码中该属性声明为Required: true, MinItems: 1,并对每个元素附加了validation.NoZeroValues校验(不允许空字符串),定义位于 ec2_ami_ids_data_source.go。

参数参考(Argument Reference)

结合官方文档与源码 schema 定义(dataSourceAMIIDs),该数据源支持以下参数:

参数必填类型/默认值说明
region字符串查询所在区域。默认使用 provider 配置中的 Region,与其他 provider 资源的 region 语义一致
owners字符串列表,至少 1 项限定搜索范围的 AMI 属主列表。合法取值为:AWS 账户 ID、self(当前账户)、AWS 属主别名(如amazonaws-marketplacemicrosoft)。元素禁止为空值(NoZeroValues校验)
executable_users字符串列表仅保留对镜像具有显式启动权限的用户可见的镜像。取值为数值的账户 ID 或self
filterfilter块,可多个名称/取值对的过滤条件,完整可用过滤器名称以 EC2 APIDescribeImages的 Filters 参考为准
include_deprecated布尔,默认falsetrue时返回结果包含已弃用(deprecated)的 AMI;为false或未指定时不包含
name_regex正则字符串对 AWS 返回的 AMI 名称做本地正则匹配,可实现 AWS API 过滤器不支持的更复杂模式;因过滤在本地执行,结果集过大时有性能影响,建议配合其他参数缩小返回范围
sort_ascending布尔,默认false按创建时间排序方向。默认降序(最新的在前),设为true则升序

几点源码级的补充细节:

  • name_regex在 schema 层通过validation.StringIsValidRegExp校验,保证配置的字符串是合法正则(源码),非法正则在 plan 阶段即报错,而不是等到 read 时才失败。
  • include_deprecatedsort_ascending均使用Default: false声明默认值,与文档描述一致(源码)。

filter

filter块包含两个字段:

  • name— 过滤器名称(必填)。合法名称即 EC2 APIDescribeImages所接受的所有 Filter 名称,例如namecreation-datearchitecturevirtualization-typestateimage-type等。
  • values— 该过滤器接受的取值集合(必填,字符串集合)。

从源码看,filter属性复用了 EC2 服务包统一的customFiltersSchemaTypeSet+name/values两个 Required 字段,定义在 filters.go),read 时经 newCustomFilterList 转换为 EC2 API 的Filters结构。这意味着aws_ami_ids的过滤语义与 AWS CLI/API 完全对齐:多个 filter 之间是 AND 关系,同一 filter 的多个 values 之间是 OR 关系。

输出属性与 ID 生成机制

除上述参数外,数据源额外导出:

  • ids— AMI ID 列表,按创建时间排序,方向由sort_ascending决定。源码中该属性为TypeListComputed(源码),元素顺序稳定可靠。

关于 Terraform 状态中的id属性值得说明:数据源 read 完成后会执行d.SetId(strconv.Itoa(create.StringHashcode(fmt.Sprintf("%#v", input))))(源码)。从这段实现看,id是对最终DescribeImagesInput结构体格式化的字符串做 hash 得到的整数。其直接效果是:相同查询条件复用已有状态,条件变化时状态自动刷新——这在数据源场景下是常见的稳定标识做法,ids本身才是用户真正消费的输出。

源码实现:一次 read 的完整调用链

read 入口为 dataSourceAMIIDsRead,整个流程可拆为四步。

1. 组装 DescribeImagesInput

input := ec2.DescribeImagesInput{ IncludeDeprecated: aws.Bool(d.Get("include_deprecated").(bool)), Owners: flex.ExpandStringValueList(d.Get("owners").([]any)), } if v, ok := d.GetOk("executable_users"); ok { input.ExecutableUsers = flex.ExpandStringValueList(v.([]any)) } if v, ok := d.GetOk(names.AttrFilter); ok { input.Filters = newCustomFilterList(v.(*schema.Set)) }

owners无条件放入输入;executable_usersfilter仅在配置了值时才设置到输入中(GetOk语义),避免向 API 传递空参数。

2. 分页拉取全部镜像

查询通过 findImages 执行,该函数封装了分页与错误处理:

pages := ec2.NewDescribeImagesPaginator(conn, input) for pages.HasMorePages() { page, err := pages.NextPage(ctx) if tfawserr.ErrCodeEquals(err, errCodeInvalidAMIIDNotFound) { return nil, &retry.NotFoundError{ LastError: err, } } if err != nil { return nil, err } output = append(output, page.Images...) }

从源码结构看有两个要点:

  • 使用 SDK v2 的DescribeImagesPaginator自动翻页,保证结果集不受单页大小限制;
  • 当 API 返回InvalidAMIID.NotFound错误码时,转换为retry.NotFoundError(错误码常量定义于 errors.go)。对于数据源而言,这意味着若按 ID 条件查询不到任何镜像,Terraform 会得到一个明确的“未找到”错误,而不是静默返回空列表。

3. name_regex 本地过滤

if v, ok := d.GetOk("name_regex"); ok { r := regexache.MustCompile(v.(string)) for _, image := range images { name := aws.ToString(image.Name) // Check for a very rare case where the response would include no // image name. No name means nothing to attempt a match against, // therefore we are skipping such image. if name == "" { continue } if r.MatchString(name) { filteredImages = append(filteredImages, image) } } } else { filteredImages = images[:] }

这印证了文档中“该过滤在本地对 AWS 返回结果执行”的描述:正则只匹配镜像的Name字段(MatchString为部分匹配而非全匹配),且对极少数无名称的镜像直接跳过。正则使用regexache.MustCompile预编译,编译失败会在 plan/validate 阶段被拦截(配合前述StringIsValidRegExp校验)。

4. 按创建时间排序并输出

slices.SortFunc(filteredImages, func(a, b awstypes.Image) int { atime, _ := time.Parse(time.RFC3339, aws.ToString(a.CreationDate)) btime, _ := time.Parse(time.RFC3339, aws.ToString(b.CreationDate)) compare := atime.Compare(btime) if d.Get("sort_ascending").(bool) { return compare } return -compare }) for _, image := range filteredImages { imageIDs = append(imageIDs, aws.ToString(image.ImageId)) }

排序依据是 API 返回的CreationDate字段(RFC3339 格式):sort_ascending = true时正序(旧 → 新),默认false时取-compare反转为倒序(新 → 旧)。因此ids[0]在默认配置下就是创建时间最新的镜像 ID,这是“取属主下最新一批镜像批量部署”类场景的关键保证。

验收测试对行为的实证验证

配套的验收测试位于 ec2_ami_ids_data_source_test.go,覆盖了文档声明的三条核心行为:

  1. 基础查询TestAccEC2AMIIDsDataSource_basic):用owners = ["099720109477"]name过滤ubuntu/images/hvm-instance/ubuntu-*,断言ids.# > 0
  2. 排序方向TestAccEC2AMIIDsDataSource_sorted):构造两个aws_ami数据源取得两张已知镜像,再用aws_ami_idsname过滤同时命中它们,分别以sort_ascending = false/true各跑一步,断言ids.0/ids.1的相对顺序正好相反;
  3. include_deprecatedTestAccEC2AMIIDsDataSource_includeDeprecated):以include_deprecated = true查询 Ubuntu 镜像并断言结果非空。

其中排序测试的配置值得注意:它对第二张镜像额外叠加了creation-date过滤(限定到某个月份),使两张镜像的创建时间明确不同,从而让升/降序断言具有确定性。

Timeouts 与使用建议

该数据源声明了 read 超时,默认为 20 分钟,对应 Terraform 的超时配置项read(默认20m)。源码中通过schema.ResourceTimeout{Read: schema.DefaultTimeout(20 * time.Minute)}实现(源码)。对结果集很大的属主(如amazon),这一宽松默认值给了分页拉取充分时间,但如果配置了过宽的过滤器导致单次查询超过 20 分钟,仍会因超时失败。

基于以上实现细节,实践上建议:

  • 务必提供owners并尽量收窄owners必填本身就是防止全库扫描的设计;查询公开镜像时用属主别名(amazon),查询发行方镜像时用具体账户 ID。
  • 优先用 API 侧filter,其次才是name_regexname_regex在本地对全量返回结果做匹配,文档已明确提示“结果集大时可能有性能影响”,正确做法是先靠owners+filter(如creation-datearchitecturestate = available)把 API 返回集压小,再用正则做精细模式匹配。
  • 利用排序方向取最新镜像:默认降序下ids[0]即最新镜像,可与slice(data.aws_ami_ids.x.ids, 0, 1)等写法配合实现“取最新一个 AMI”的模式;需要稳定旧版本审计时再显式开启sort_ascending
  • 注意 deprecated 语义include_deprecated默认false,若属主已弃用某些镜像而你希望它们仍出现在列表中(例如做清理盘点),需显式置为true

该数据源在 provider 中的注册信息可见 service_package_gen.go(TypeName: "aws_ami_ids"),与同服务包内的 aws_ami 单镜像数据源文档 构成互补:查单张镜像用aws_ami,查一组 ID 用aws_ami_ids

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询