2026/8/21 17:52:53

源码解读:tf-summarize 的资源树构建与 JSON Diff 计算,Terraform plan 一目了然

源码解读:tf-summarize 的资源树构建与 JSON Diff 计算,Terraform plan 一目了然 源码解读tf-summarize 的资源树构建与 JSON Diff 计算Terraform plan 一目了然【免费下载链接】tf-summarizeA command-line utility to print the summary of the terraform plan项目地址: https://gitcode.com/gh_mirrors/tf/tf-summarizetf-summarize是一个开源的 Terraform plan 摘要命令行工具它的核心价值在于把冗长的terraform plan输出压缩成一张表、一棵树或一份带颜色的 JSON。这篇源码解读将带你深入其内部重点剖析两个最精妙的部分资源树构建把扁平的资源地址变成层级结构与JSON Diff 计算只输出真正发生变化的字段。读完你不仅能看懂源码还能学到 Go 语言里处理嵌套数据结构的实用技巧。源码架构总览一条数据从 plan 到摘要的流水线在动手看代码之前先建立整体认知。tf-summarize 的代码组织非常清晰main.go是入口数据依次流经四个包reader/从文件或 STDIN 读取原始字节parser/把 JSON 或二进制 tfplan 解析为结构体terraformstate/按动作类型增删改、重建、迁移、导入给资源分类writer/把分类结果渲染成表格、树、JSON、HTML 等格式main.go里通过flag解析-tree、-json、-html等参数再调用writer.CreateWriter选择对应的输出器。整条链路只有几十行代码非常适合作为 Go 命令行工具的学习范本。资源树构建原理如何把扁平地址变成层级结构这是 tf-summarize 最核心的算法之一位于tree/tree.go。Terraform 的资源地址是这样的字符串module.github[demo].github_branch.development。它天然带有层级信息但要变成真正的树需要两步。第一步splitResources 按地址切分层级splitResources函数逐字符扫描地址遇到.就切分一段遇到[则把[...]整体当作一个节点。这样module.github[demo].github_branch.development会被切分成module、github[demo]、github_branch、development四段。注意对索引[...]的特殊处理这是很多人容易写错的细节github[demo]必须作为一个整体否则树就散架了。第二步createTreeMultiLevel 自顶向下插入节点拿到层级列表后createTreeMultiLevel从根节点开始逐层查找getTree在兄弟节点中按名字匹配。如果找到同名节点就复用并下钻找不到就新建节点挂上去。只有最后一个层级叶子才持有真正的tfjson.ResourceChange数据中间节点只保留名字。这保证了同一资源地址下多次出现的子资源可以正确合并。关键代码在tree/tree.go的CreateTree与createTreeMultiLevel。构建完成后writer/tree.go的printTree用递归加上|---前缀输出 ASCII 树叶子节点会通过terraformstate.GetColorPrefixAndSuffixText追加()、(-)、(~)等动作后缀和 ANSI 颜色一眼就能看出哪些资源被新增、删除或修改。JSON Diff 计算原理如何只输出变化字段如果你用-json参数输出会从整棵资源树变成每棵树的差异化 JSON。这个逻辑在writer/json.go的treeValue函数里它按动作类型走三条分支新增 / 导入直接输出Change.After变更后的完整值删除直接输出Change.Before变更前的完整值更新 / 重建调用第三方库jsondiff.Compare对Before和After做差异对比其中最值得学习的是更新分支的配置opts : jsondiff.DefaultJSONOptions() opts.SkipMatches true _, str : jsondiff.Compare(before, after, opts)SkipMatches true是关键开关它让 diff 结果只包含发生变化的键未变化的字段全部跳过。这正是摘要二字的精髓——几百行的 JSON 只输出几行真正变动的内容并且结果被组织成以()、(-)、(~)为键的映射为下一步美化做准备。带颜色的 JSON 美化输出json-prettyprint 的实现diff 计算出的原始 JSON 会交给writer/json-prettyprint.go中的Formatter处理。它没有用现成的json.MarshalIndent而是手写了一套递归格式化器pretty函数按类型分发字符串、数字、布尔、map、数组分别处理processMap会对 key 排序保证输出稳定并通过缩进深度控制层级最巧妙的是一组颜色映射当 key 是()时用绿色加粗、(-)用红色、(~)用黄色、(/-)用品红与树形输出的动作标记风格完全统一这样生成的 JSON 不但结构清晰而且颜色本身就是变更语义的编码扫一眼就能定位高风险操作。资源分类六种动作是如何判定的整个摘要的地基在terraformstate/terraform_state.go。GetAllResourceChanges把plan.ResourceChanges按动作分拣成六类add、delete、update、recreate、import、moved并分别按地址排序。判定规则很严谨recreatedResources通过len(Actions) 2识别先销毁再重建movedResources通过PreviousAddress ! PreviousAddress ! Address识别资源迁移importedResources兼容了 Terraform 1.12 引入的 identity 导入方式FilterNoOpResources会剔除 no-op 变更但保留导入和迁移的资源避免误伤main.go在解析 plan 后立即调用FilterNoOpResources做前置过滤这样后续所有 writer 都不必再关心无效数据。实战三种输出格式如何选择掌握了实现原理日常使用就更有底气了。以 README 中给出的流程为例terraform plan -outtfplan terraform show -json tfplan output.json tf-summarize output.json # 表格适合快速总览变更数量 tf-summarize -tree output.json # 树适合观察资源层级关系 tf-summarize -json output.json # 差异化 JSON适合脚本解析和 CI 集成想自己跑一遍源码克隆仓库后用go build -o tf-summarize .即可编译example/目录下提供了现成的terraform.tfstate和tfplan.json测试数据。总结通读源码你会发现tf-summarize 的设计哲学是每个包只做一件事reader只管读、parser只管解析、terraformstate只管分类、tree只管建树、writer只管渲染。资源树构建与 JSON Diff 计算作为两大核心一个解决结构可视化一个解决内容差异化配合 ANSI 颜色编码把 Terraform plan 从几千行压缩到几十行让每一次基础设施变更都清晰可控。如果你正在写类似的 CI/CD 辅助工具这份源码是极佳的参考。【免费下载链接】tf-summarizeA command-line utility to print the summary of the terraform plan项目地址: https://gitcode.com/gh_mirrors/tf/tf-summarize创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考