ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Terraform AWS Provider 的 List Resource 实现指南:从资源分类到 skaff 脚手架落地

Terraform AWS Provider 的 List Resource 实现指南:从资源分类到 skaff 脚手架落地 Terraform AWS Provider 的 List Resource 实现指南从资源分类到 skaff 脚手架落地【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-awsTerraform 1.14 引入了list块允许用户直接查询远端资源集合而 AWS Provider 对 List Resource 的支持有一套完整的设计规范与落地工具链。本文基于仓库中的设计文档 docs/list-resources.md 展开覆盖 List Resource 的核心概念模型强实体/弱实体/属性实体/等待器实体、AWS API 列表模式、Plugin Framework 与 Plugin SDK 两条实现路径、skaff脚手架的用法与生成物以及验收测试的编写规范读完你不仅能理解每个分类的设计动机还能照着仓库中的真实实现如 Rekognition Collection、EventBridge Rule为自己负责的 AWS 服务补上 List Resource。背景List Resource 解决什么问题在 Terraform 1.14 之前列出当前云上有哪些某类资源需要借助数据源data source或 AWS CLI而数据源返回的是查询快照与 Terraform 状态之间没有身份Identity关联。Terraform 1.14 引入的list块把资源查询变成了一等公民查询结果中的每一项携带资源身份可以直接导入到 Terraform 管理之下。对 Provider 开发者而言这意味着每类远端资源需要一种新的代码单元——List Resource。它本质上是针对某个资源类型resource type实现的列表查询逻辑注册进 Provider 后即可被list块调用。本文剩余部分全部围绕如何正确地把一个 AWS 资源类型实现为 List Resource展开。概念一按与其他资源的关系分类设计文档指出实现 List Resource 前必须先沿三个维度对远端资源类型进行分类与其他资源的关系、AWS API 的工作方式、Terraform 侧的管理考量。第一个维度直接决定 List Resource 的 schema 设计以及资源类型的 Resource Identity 设计。这一节借用数据库实体-关系Entity-Relationship模型的术语但有一个关键区别List Resource 的分类只依据读取远端资源时使用的标识符而不是资源之间在数据库意义上的业务关系。强实体Strong Entity强实体是指仅凭自身身份信息就能被读取或列出的资源类型。即使它必须依附于其他资源只要那个关联资源的标识符不需要参与读取/列表操作它仍然是强实体。文档给出的例子EC2 实例aws_instance只需要InstanceID就能读取因此是强实体——尽管它必须位于某个 VPC Subnet、进而位于某个 VPC 之内。弱实体Weak Entity弱实体是指无法仅凭自身身份读取或列出还必须提供关联资源标识符的资源类型。文档例子ELB Listeneraws_lb_listener只有在列表请求中包含所属 ELB 负载均衡器的 ARN 时才能被返回因此是弱实体。这个分类会直接落到 schema 设计上——见后文实现要求一节弱实体的 List Resource schema 需要定义一个对应父资源标识符的必填属性。属性实体Property Entity属性实体是以 1:1 或 1:[0,1] 关系建模关联资源某个属性的资源类型。其中 1:[0,1] 关系可能不存在的特例称为可选属性实体optional property entity它是弱实体的一个特例。文档特别注明这不是实体-关系模型中的概念。文档例子S3 桶aws_s3_bucket的许多属性被建模为独立资源如桶 ACLaws_s3_bucket_acl与桶策略aws_s3_bucket_policy。桶策略只有在用户显式创建时才存在因此是可选属性实体。等待器资源Waiter Resource等待器资源表面上与属性实体相似同样是与关联资源 1:1 或 1:[0,1] 的关系但它的存在目的不同让 Provider 能够执行多步流程等待或创建依赖直到完成。文档例子ACM 证书aws_acm_certificate可以用 Route 53 的 DNS 记录aws_route53_record完成验证这涉及多步流程在待验证状态创建证书、用证书的验证字段创建 DNS 记录、等待 DNS 解析以完成验证。aws_acm_certificate_validation这个资源类型实现的正是等待这一步使其他资源可以依赖已验证的证书。理解等待器资源的意义在于它的列表行为与普通属性实体不同——它不代表一个独立的远端资源列表实现上需要按其特殊语义处理。概念二AWS API 的列表模式文档归纳了 AWS 列表 API 的三种常见模式这直接影响 List Resource 内部的分页与二次调用逻辑All-Or-One全量或单个同一个 AWS 请求给出标识符时检索单个远端资源不给标识符时检索全部远端资源。All-Or-Some全量或部分同一个 AWS 请求给出一组标识符时检索这一组远端资源不给标识符时检索全部远端资源。Summary List摘要列表列表 API 只返回远端资源信息的子集获取完整资源信息需要后续 API 调用。文档指出一个最常见的情形列表调用不返回资源标签tags必须用单独的 API 调用获取。这一模式在仓库代码中可以直接对应List Resource 通常会拆出两个函数——一个负责分页列出标识符或摘要另一个负责按需拉取完整资源。例如 internal/service/rekognition/collection_list.go 中的listCollectionIDs第 86–103 行只负责通过rekognition.NewListCollectionsPaginator分页产出 ID而完整资源数据则由findCollectionByID在需要时才获取。概念三Terraform 侧的管理考量可管理资源Manageable Resources可管理资源指可以被纳入 Terraform 管理的远端资源。大多数情况下某资源类型的全部远端资源都是可管理的但有些服务定义了用户无法修改的默认实例这些就是不可管理资源既不应可导入也不应可列出。文档例子RDS 及其他 RDS 衍生服务定义了一组默认 Parameter Group数据库配置参数集合。用户可以创建自定义 Parameter Group但对默认值无能为力——默认 parameter group 属于不可管理资源应从列表结果中排除。特殊情况资源类型Special Case Resource Types某些资源类型存在伴生资源类型用于特殊处理尤其是创建时可能还有删除时。文档例子EC2 服务为aws_vpc、aws_security_group、aws_network_acl、aws_route_table、aws_subnet、aws_vpc_dhcp_options定义了默认变体资源。它们都实现 Adopt-on-Create 模式删除为 no-op 或忽略删除失败。从源码结构看这类变体资源通常能在资源数据上找到标志位或其他值来识别例如默认 VPC / 默认安全组List Resource 实现时必须利用该标志把它们排除出结果。实现要求返回内容、Display Name 与过滤规则设计文档对 List Resource 的默认行为给出了明确约定默认只返回身份List Resource 默认只应返回每个远端资源的Resource Identity和Display Name。IncludeResource参数当 list 请求上的参数IncludeResource设为true时才应填充完整的资源数据。Display Name 的选择应尽量能友好且唯一地标识资源。资源类型有Name字段或等价物如 RDS 资源类型的DBIdentifier时这是最佳选择对 EC2、ELB 等将Name标签键作为控制台名称值的服务应使用Name标签的值。排除不可管理资源它们无法被纳入 Terraform 管理必须从结果中剔除。排除特殊情况资源类型由于没有机制覆盖所返回资源的资源类型这类资源应被排除并且应在实践者文档practitioner documentation中说明同时应为特殊情况资源类型本身单独创建一个 List Resource。弱实体的 schema 要求若资源类型是弱实体但不是属性实体List Resource schema 应定义一个对应父资源标识符的必填属性。文档例子aws_s3_object是弱实体需要bucket属性来标识所属 S3 桶。Plugin Framework 路径脚手架由skaff工具在目标服务目录下生成skaff list --framework --name resource-name注册 List Resource 需要注解FrameworkListResource(resource_name)其中resource_name必须与被关联的资源类型名称一致。仓库中的真实示例见 internal/service/rekognition/collection_list.go// Function annotations are used for list resource registration to the Provider. DO NOT EDIT. // FrameworkListResource(aws_rekognition_collection) func newCollectionResourceAsListResource() list.ListResourceWithConfigure { return collectionListResource{} }文档对框架路径的核心重构要求为既有资源类型添加 List Resource 时要把现有资源 Read 操作中把 API 响应展平flatten到资源数据模型的那部分提取为一个新的flatten方法。对很多资源类型这实际上只是调用flex.Flatten(...)展平行为可用flex.WithFieldNamePrefix(...)等 AutoFlex 选项调整。List Resource 与资源类型的 Read 操作都应调用这个flatten函数保证两条路径的数据填充逻辑一致。上文的 Rekognition 示例精确展示了这一约定collection_list.go 的List方法遍历分页迭代器listCollectionIDsGo 1.23 的iter.Seq2序列仅当request.IncludeResource为true时才调用findCollectionByID获取完整资源并用flex.Flatten(ctx, out, data, flex.WithFieldNamePrefix(Collection))展平第 70 行无论是否填充资源数据都先设置身份字段CollectionID、ID并设置result.DisplayName collectionID若retry.NotFound(err)资源在列表与获取之间被删除则continue跳过而不是报错。从源码结构看框架路径的 List 结构体统一内嵌framework.WithList见 internal/framework/with_list.go。它提供SetResult方法负责在填充前后运行结果拦截器AppendResultInterceptor、把零值字段归一化为 nullsetZeroValueAttrFieldsToNull第 101 行起最后通过result.Resource.Set(ctx, data)把模型写入结果——这正是只填身份与填身份资源数据两种模式在框架层的统一收口点。Plugin SDKSDKv2路径脚手架同样由skaff生成skaff list --name resource-name注册注解为SDKListResource(resource_name)resource_name同样必须与被关联资源类型名称一致。仓库中的真实示例见 internal/service/events/rule_list.go// SDKListResource(aws_cloudwatch_event_rule) func newRuleResourceAsListResource() inttypes.ListResourceForSDK { l : listResourceRule{} l.SetResourceSchema(resourceRule()) return l } type listResourceRule struct { framework.ListResourceWithSDKv2Resource }SDK 路径的迭代器循环体必须遵守以下规则必须设置id用rd.SetId(value)为资源数据rd设置id值见 rule_list.go 第 55–56 行rd : l.ResourceData(); rd.SetId(id)。填充身份所需的附加属性用rd.Set(attribute-name, attribute-value)设置 Resource Identity 需要的其他属性。IncludeResource时填充资源数据应通过一个命名为resourceResource NameFlatten的函数完成List Resource 与资源 Read 操作都应使用这个展平函数上例中的resourceRuleFlattenrule_list.go 第 67 行。若该函数尚不存在需重构资源的 Read 操作把设置资源数据值的那段函数体迁移进展平函数。脚手架skaff list命令详解skaff是 Provider 仓库内置的代码生成工具入口 skaff/main.golist子命令的实现在 skaff/cmd/list.go。除文档提到的两个基本用法外从命令定义第 19–26 行可以看到完整参数标志缩写说明--name-n实体名称如DBInstance--snakename-s若 skaff 猜错显式给出 snake_case 名称如db_vpc_instance--clear-comments-c生成源码中不包含指导注释--force-f强制创建覆盖已有文件--framework-p使用 Plugin Framework 脚手架否则为 SDKv2命令执行时由Create(name, snakeName, !clearComments, framework, force)驱动skaff/list/list.go并在生成前做两项校验--name必须以首字母大写给出如DBInstance否则报错提示若显式提供--snakename必须全小写下划线格式。生成逻辑基于一组嵌入式 Go 模板list_common.gtpl、list_framework.gtpl、list_sdkv2.gtpl、listtest.gtpl、testconfig.gtpl、query.gtpl、websitedoc.gtpl见 skaff/list/list.go 第 23–42 行分别对应 List Resource 公共骨架、框架/SDK 两条路径的资源文件、验收测试、测试配置、list查询配置文件与网站文档。也就是说一条命令同时产出实现文件、测试脚手架和文档骨架开发者只需按提示填充分页迭代器与展平逻辑。验收测试规范skaff会为 List Resource 生成验收测试脚手架但文档规定了必须覆盖的测试矩阵必测项basic测试验证可以查询到多个资源includeResource测试验证IncludeResource设为true时资源数据被正确填充。对区域型资源大多数资源类型属于此类还必须增加regionOverride测试验证list块上的region属性可以覆盖 Provider 的默认区域。配置应尽量简单避免可选属性。唯一的例外若资源类型有可选的name属性或namename_prefix组合且name值被用于 Resource Identity则应在配置中显式指定name。若资源类型的某些属性设置可能影响列表行为还应补充针对性测试验证该行为。测试配置约定多实例所有测试都应创建被测资源类型的多个实例把count元参数 设为var.resource_count。配置中其他资源保持单实例除非确需多个例如测试 ELB 负载均衡器时需要多个 EC2 Subnet。属性实体的特殊配置必须创建多个父资源实例且每个属性实体资源关联到一个父资源实例basic测试配置还应包含一个不带属性资源的父资源实例并用querycheck.ExpectNoIdentity断言该父资源的身份不出现在列表结果中。includeResource测试若资源类型支持标签应设置tags属性且标签只打在被测资源上QueryResultChecks应包含querycheck.ExpectResourceKnownValues检查验证资源的每个属性都等于预期值在 list 查询配置文件中把include_resource设为true。regionOverride测试应为配置中所有非全局资源设置region属性在 list 查询配置文件的config块中把region设为var.region。这里的querycheck.ExpectNoIdentity/querycheck.ExpectResourceKnownValues对应仓库内的 internal/acctest/querycheck 包测试脚手架模板skaff/list/testconfig.gtpl、query.gtpl生成的.tf查询配置与.hcl断言配置即引用这些辅助函数。参考实现清单仓库中已有大量 List Resource 实现可供参照两类注解的实例分布如下均为服务目录下的*_list.go文件FrameworkListResource路径internal/service/rekognition/collection_list.go、internal/service/s3files/access_point_list.go、internal/service/ec2/vpc_security_group_ingress_rule_list.go、internal/service/opensearchserverless/vpc_endpoint_list.go、internal/service/accountaccess/entitlement_list.go 等。SDKListResource路径internal/service/events/rule_list.go、internal/service/sfn/state_machine_list.go、internal/service/codebuild/project_list.go、internal/service/ec2/vpc_list.go、internal/service/ec2/eip_list.go 等。对照阅读时的建议顺序先用本文的概念分类确定目标资源属于哪一类实体与 API 模式 → 选一个同类的现有实现例如弱实体参考events/rule_list.go属性实体参考s3files下的策略类 List→ 用skaff list [--framework] --name Name生成脚手架 → 按文档约定补齐展平函数、Display Name 与过滤逻辑 → 按测试矩阵补全basic/includeResource/regionOverride三类测试。小结AWS Provider 的 List Resource 设计可以用三句话概括先分类后实现——用实体关系、API 模式、Terraform 管理约束三个维度决定 schema 与过滤策略默认轻量——默认只返回 Resource Identity 与 Display NameIncludeResource才填充资源数据且不可管理资源与特殊情况资源必须被排除复用 Read 的展平逻辑——无论 Framework 还是 SDK 路径List 与 Read 共用同一份 flatten 函数是数据一致性的关键。脚手架命令skaff list --framework --name resource-name或skaff list --name resource-name、注册注解FrameworkListResource/SDKListResource与三类必测测试basic、includeResource、regionOverride共同构成了从概念到落地、再到质量保障的完整闭环。【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表