源码解读tf-summarize 如何精准识别 add/update/delete/recreate 等 6 类变更【免费下载链接】tf-summarizeA command-line utility to print the summary of the terraform plan项目地址: https://gitcode.com/gh_mirrors/tf/tf-summarizetf-summarize 是一款用于打印 terraform plan 摘要的命令行工具它能自动把纷繁复杂的计划文件整理成 add、update、delete、recreate、moved、import 六类变更清单。本篇源码解读将带你逐层拆解它的实现原理看懂 Go 源码中判定每一类变更的核心逻辑从此阅读 terraform plan 一目了然。一、tf-summarize 是什么为什么需要它Terraform 执行terraform plan之后输出动辄几十上百行人工逐行比对很容易漏掉关键变更。tf-summarize 的价值在于把 plan 结果自动归类为 6 类变更让你一眼看清「哪些资源要新增、哪些要删除、哪些要重建」特别适合在 CI/CD 流水线或 PR 评论里展示计划摘要。它的工作方式非常简单既可以接收terraform plan -outtfplan生成的二进制文件也可以接收terraform show -json tfplan导出的 JSON 文件两条路径最终都会汇总成同一份标准化的资源变更清单。二、整体架构一条数据流看懂 tf-summarize 工作流程从入口 main.go 看工具的核心流程是一条清晰的流水线读取输入 → 选择解析器 → 解析为 Plan → 过滤无变更 → 按 6 类分组 → 选择输出格式关键代码如下main.gonewParser, err : parser.CreateParser(input, newReader.Name()) terraformState, err : newParser.Parse() terraformstate.FilterNoOpResources(terraformState) newWriter : writer.CreateWriter(*tree, *separateTree, *drawable, *md, *json, *html, *jsonSum, terraformState)reader层负责从文件或标准输入读取数据parser层负责把原始数据解析成结构化的 Planterraformstate层是分类核心产出 6 类变更映射表writer层按 table、tree、json、html 等格式渲染输出。三、解析层二进制 plan 与 JSON 的双通道入口在 parser/parser.go 中CreateParser根据文件名后缀判断走哪条通道if fileName ! reader.StdinFileName !strings.HasSuffix(fileName, .json) { return NewBinaryParser(fileName), nil } return NewJSONParser(data), nilJSON 通道直接把 JSON 字节反序列化为tfjson.Plan结构体二进制通道内部调用terraform show -json命令parser/binary-parser.go把二进制 plan 先转换为 JSON 再解析还支持通过TF_BINARY环境变量切换到 terragrunt。两条通道最终都落在同一个tfjson.Plan结构上后续所有分类逻辑因此无需关心数据来源。四、核心揭秘6 类变更如何被精准识别真正的分类逻辑集中在 terraformstate/terraform_state.go 的GetAllResourceChanges函数中它同时调用 6 个过滤函数再按资源地址排序后放入映射表return map[string]ResourceChanges{ import: importedResources, add: addedResources, delete: deletedResources, update: updatedResources, recreate: recreatedResources, moved: movedResources, }4.1 add/update/delete单动作判定Terraform JSON 格式中每个变更都有一个Actions数组。当数组只有一个元素时就对应最基础的三类变更terraformstate/terraform_state.gofunc filterResources(resources ResourceChanges, action tfjson.Action) ResourceChanges { for _, r : range resources { if len(r.Change.Actions) 1 r.Change.Actions[0] action { acc append(acc, r) } } }Actions [create]→add新增绿色 Actions [delete]→delete删除红色 -Actions [update]→update更新黄色 ~这里有个精妙之处严格限定len 1。因为重建类变更的 Actions 数组有 2 个元素如果不加长度判断重建资源也会被误算进 delete 或 create 里。4.2 recreate双动作是重建的铁证重建recreate意味着资源先销毁再创建或先创建再销毁因此 Actions 数组必然包含 2 个动作terraformstate/terraform_state.gofunc recreatedResources(resources ResourceChanges) ResourceChanges { for _, r : range resources { if len(r.Change.Actions) 2 { // if Change is two, it will be create, delete acc append(acc, r) } } }这正是Actions数组长度的精妙之处len 1是普通变更len 2就是重建。在输出时会进一步区分为(-/)先销毁后创建或(/-)先创建后销毁见 terraformstate/terraform_state.go 中的GetColorPrefixAndSuffixText。4.3 movedPreviousAddress 记录移动轨迹资源移动moved是 Terraform 1.x 的新特性用于moved块声明地址变更。tf-summarize 通过比较PreviousAddress与Address判断terraformstate/terraform_state.goif r.PreviousAddress ! r.PreviousAddress ! r.Address { acc append(acc, r) }只有设置了旧地址且与现地址不同才判定为 moved输出时用青色(→)标记并显示「旧地址 to 新地址」。4.4 importImporting 字段的存在即证明导入import变更在Change.Importing中携带导入信息。分类逻辑同时兼容 ID 导入和 Terraform 1.12 引入的 identity 导入terraformstate/terraform_state.goif id ! || identity ! nil { acc append(acc, r) }输出时用青色(i)标记一目了然。五、细节设计NoOp 过滤与分类顺序5.1 NoOp 资源被悄悄剔除计划中常存在大量 no-op 变更没有实际动作它们会污染摘要。FilterNoOpResources会把纯 no-op 变更过滤掉但保留三类特殊情况terraformstate/terraform_state.go带 ID 的导入Importing.ID ! 带 identity 的导入Terraform 1.12发生移动的资源PreviousAddress与Address不同这是最容易踩坑的细节如果一刀切过滤所有 NoOp会把 moved 和 import 这两种「无实际变更但有信息量」的资源误删。5.2 分类顺序决定输出观感在 writer/table.go 中表格输出的分类顺序是固定的var tableOrder []string{import, add, update, recreate, delete, moved}这个顺序经过精心设计先展示导入和新增最后展示删除和移动符合阅读者「先看增、后看删」的心理预期。每类变更还会统计数量例如add (3)方便快速评估影响范围。六、从分类到展示tree 与 separate-tree 的层级之美分类完成后writer层负责把清单渲染成多种格式。其中树形视图由 tree/tree.go 的CreateTree构建它按资源地址如module.github[demo].github_branch.development中的.和[...]切分层级把扁平列表还原成层级树。配合-separate-tree参数还能按 add/delete/update/recreate 分组分别绘制每一组以#####分隔符隔开见 writer/separate_tree.go。七、总结这套分类逻辑值得借鉴的设计回顾整个源码tf-summarize 精准识别 6 类变更的秘诀可以概括为三点统一的数据结构二进制和 JSON 两种输入都归一化为tfjson.Plan分类逻辑只依赖标准字段巧妙的判定规则len(Actions) 1区分普通变更、len(Actions) 2识别重建、PreviousAddress识别移动、Importing识别导入——规则简单却覆盖全部场景合理的过滤与排序NoOp 过滤保留 moved/import 特例输出顺序贴合阅读习惯。如果你想亲自运行体验只需terraform plan -outtfplan生成计划文件然后执行tf-summarize tfplan即可看到分类摘要也可以配合-tree、-json、-html切换输出格式。若想深入调试源码克隆仓库后执行make build即可编译出二进制。理解了这 6 类变更的判定逻辑你就能完全掌控 tf-summarize 的行为甚至为它扩展自定义的变更类型。【免费下载链接】tf-summarizeA command-line utility to print the summary of the terraform plan项目地址: https://gitcode.com/gh_mirrors/tf/tf-summarize创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考