尧图精选

OpenTofu 模块变量与输出弃用机制(Deprecation)RFC 深度解读与实现指南

🕒 发布时间:2026/9/19 22:08:55 📁 来源:尧图网络
OpenTofu 模块变量与输出弃用机制DeprecationRFC 深度解读与实现指南【免费下载链接】opentofuOpenTofu lets you declaratively manage your cloud infrastructure.项目地址: https://gitcode.com/gh_mirrors/op/opentofu本篇技术指南围绕 OpenTofu 官方 RFC《Deprecation of module variables and outputs》展开深入讲解模块作者如何通过deprecated字段标记输入变量input variables与输出outputs的弃用状态、模块调用方如何在tofu validate、tofu plan、tofu apply、tofu test等命令中收到对应警告以及如何通过-deprecation命令行标志module:all/module:local/module:none控制警告范围。文章还结合当前仓库源码揭示弃用标记在 go-cty value marks 层面的底层实现帮助你既能在模块开发中正确使用该机制也能理解其设计边界与未来演进方向。背景与动机为什么模块作者需要“声明式弃用”OpenTofu 配置可以拆分为多个模块每个模块代表配置的一部分并拥有自己的输入变量与输出用于提供额外定制与集成能力。在实际项目中调用模块的用户往往不是模块的实现者因此模块作者需要谨慎考虑模块如何演进尤其是如何引入和传达破坏性变更——包括输入变量和输出的弃用。当前阶段模块作者通常只有两种选择长期保持向后兼容这会让模块持续背负过时接口阻碍演进仅在发布说明release notes中写弃用通告这依赖调用方主动阅读信息传递效率低用户容易遗漏。这两种方式对终端用户都不理想。因此 OpenTofu 需要提供一种机制由模块作者在配置中声明弃用OpenTofu 在用户实际使用被弃用的变量或输出时自动发出警告。[!NOTE] 模块整体层面的弃用是类似的问题但该场景在 OpenTofu Registry 层面解决不属于本 RFC 讨论范围。提案方案概览核心方案非常简洁允许模块作者在variable块与output块中增加名为deprecated的字段字段值为必填字符串用于承载警告消息当模块调用方的配置中实际使用了被弃用的输入变量或输出时OpenTofu 产生由模块作者指定的警告消息tofu validate、tofu plan、tofu apply与tofu test的结果中均应包含弃用警告。用户侧语法在 variable 与 output 块中使用 deprecated模块作者只需在两个块中分别添加deprecated参数即可RFC 给出的完整示例variable this_is_my_variable { type string description This is a variable for the old way of configuring things. deprecated This variable will be removed on 2024-12-31. Use another_variable instead. } output this_is_my_output { value some_resource.some_name.some_field description This is an output for the old way of using things. deprecated This output will be removed on 2024-12-31. Use another_output instead. }该语法在当前仓库中已落地。在 internal/configs/named_values.go 中Variable结构与Output结构均新增了Deprecated string字段解析逻辑通过gohcl.DecodeExpression读取deprecated属性。值得注意的是解析时还包含一条校验规则如果deprecated值经 TrimSpace 后为空字符串会报错Invalid deprecated value错误详情要求“deprecated参数不能为空且应提供如何迁移离开该弃用变量/输出的说明”从源码层面印证了 RFC 中“必填字符串”的设计if !valDiags.HasErrors() strings.TrimSpace(v.Deprecated) { diags append(diags, hcl.Diagnostic{ Severity: hcl.DiagError, Summary: Invalid deprecated value, Detail: The deprecated argument must not be empty, and should provide instructions on how to migrate away from usage of this deprecated variable., ... }) }官方文档变量弃用、输出弃用也给出了对应示例例如variable examle { type string deprecated examle variable must no longer be used due to a typo, use example instead }被弃用模块变量的警告输出当模块调用方为某个被弃用的变量指定非 null 值时OpenTofu 会产生模块作者指定的弃用警告。RFC 中的示例输出│ Warning: The variable this_is_my_variable is marked as deprecated by module author. │ │ on mod/main.tf line 9, in module call mod: │ 9: this_is_my_variable something │ │ This variable will be removed on 2024-12-31. Use another_variable instead.从源码实现看该警告由 internal/tofu/eval_variable.go 中的evalVariableDeprecation函数产生当config.Deprecated 时直接跳过当变量被标记为弃用但未使用、或未给定值时同样跳过对应日志variable %q is marked as deprecated but is not used/no value given一旦检测到实际使用即生成Variable %q is marked as deprecated with the following message:格式的警告诊断并附带marks.DeprecationCauseVariable(addr, config.Deprecated)作为额外信息便于下游合并与定位。[!NOTE] 关于 null 值如果模块用户为被弃用变量显式传入nullOpenTofu不会产生警告。因为 OpenTofu 将显式 null 值视同于完全省略该变量这是 OpenTofu 语言中一种惯用idiomatic做法而非理想状态。可参考类型与 null 值的文档。被弃用模块输出的警告输出当模块调用方的配置中引用了被弃用的模块输出时OpenTofu 同样产生警告。RFC 中的示例输出│ Warning: Value derived from a deprecated source │ │ on main.tf line 9, in resource some_resource some_name: │ 9: some_field module.mod.this_is_my_output │ │ This value is derived from module.mod.this_is_my_output, which is │ deprecated with the following message: │ │ This output will be removed on 2024-12-31. Use another_output instead.需要强调的是输出值可能在多个不同的图节点graph nodes执行期间被使用无法像输入变量那样在单一校验点统一处理因此输出弃用必须采用“值携带标记”的方案详见下文技术实现。为依赖模块静默弃用警告在依赖第三方非本配置作者控制模块的场景下允许用户按需忽略这些模块产生的弃用警告是有意义的。RFC 将包含弃用变量/输出模块调用的模块分为两类本地模块local modules从本地文件系统获取的模块非本地模块non-local modules从远程系统获取的模块。这种划分基于“用户能控制哪些模块配置”的判断例如位于本地模块即使是非根模块中的弃用调用配置作者理论上可以修复因此不应被静默忽略。静默机制支持两种粒度全局忽略所有非本地模块的警告或按单个模块忽略。该设置不应放在模块调用块module call block内部——因为同一模块可能被多处调用每处调用应能独立决定产生或静默警告。RFC 最终建议通过命令行标志控制名为deprecation可选值如下取值含义module:all默认显示来自本地与远程模块调用的全部弃用警告module:local仅显示来自本地模块内部模块调用的弃用警告module:none静默所有关于弃用输出/变量的警告未来可以扩展出其他命名空间选项例如none用于整体禁用弃用警告或backend:等其它命名空间。技术实现输入变量与输出的不同路径RFC 明确指出输入变量与输出的技术方案必须不同输入变量沿用现有的变量校验思路变量在使用时被校验校验点集中可在求值时直接生成警告模块输出值可能在多个图节点执行期间被消费无法集中校验因此需要借助go-cty 的 value marks值标记机制让“弃用标记”随值一起在图中流动。当前 OpenTofu 已使用 value marks 跟踪敏感值sensitive以及 console-only 的type函数产生的特定输出。仓库 internal/lang/marks/marks.go 中定义了以下布尔型标记常量const Sensitive valueMark(Sensitive) const Ephemeral valueMark(Ephemeral) const TypeType valueMark(TypeType)RFC 提醒在正式实现弃用标记前必须仔细审查所有操作 marks 的位置因为部分实现如genconfig.GenerateResourceContents会把任何 mark 都当作敏感值处理而另一些实现如funcs.SensitiveFunc会在执行中抹除任何非敏感 mark。这一审查步骤是引入包括弃用标记在内的新标记的前提。弃用标记Deprecation marks的设计敏感Sensitive与类型Type标记是布尔型标志用内部 go 类型marks.valueMark表示弃用标记则必须携带更多数据——至少包括“该值由哪些地址组合而来”的地址列表。因此 RFC 提出引入新类型例如marks.Deprecation它是一个包含源地址列表的结构体。由于 go-cty 将 marks 处理为集合即只使用键的 map无法使用内置的“标记存在性检查”必须自定义检查逻辑。在 internal/lang/marks/marks.go 中该设计已落地为type deprecationMark struct { Cause DeprecationCause } type DeprecationCause struct { module string subject string message string }并提供了三类构造工厂函数DeprecationCauseResource(res addrs.AbsResourceInstance, path cty.Path, message string)标记资源实例及其属性路径DeprecationCauseOutput(out addrs.AbsOutputValue, message string)标记模块输出DeprecationCauseVariable(vaddr addrs.AbsInputVariableInstance, message string)标记输入变量。标记的注入与提取通过以下核心函数完成Deprecated(v cty.Value, cause DeprecationCause) cty.Value为值打上弃用标记若同一 causemodule subject 相同已标记过则幂等跳过DeprecatedOutput(v cty.Value, addr addrs.AbsOutputValue, msg string) cty.Value从模块输出地址构造 cause 并打标记若地址属于根模块则直接返回原值对根模块输出打标记无意义测试框架作用于模块时会命中该分支HasDeprecated(v cty.Value) bool遍历值的所有 marks判断是否包含deprecationMark类型ExtractDeprecationDiagnosticsWithBody/ExtractDeprecatedDiagnosticsWithExpr基于值内的弃用标记借助hcl.Body/hcl.Expression构造指向具体属性或表达式的警告诊断并在返回前通过WrangleMarksDeep丢弃这些弃用标记“提取即清除”避免标记泄漏到后续执行RemoveDeepDeprecated(val cty.Value) cty.Value深度移除值内所有弃用标记。诊断消息的默认模板为This value is derived from subject, which is deprecated with the following message: message其诊断摘要统一为Value derived from a deprecated source与 RFC 中的示例输出完全一致。诊断通过tfdiags.Override包裹deprecatedDiagnosticExtra其中ExtraInfoKey()返回subject message用于按弃用地址合并consolidate重复诊断——官方文档outputs.mdx也提到默认情况下被弃用的模块输出会按输出地址合并若同一被弃用变量被多处使用警告会合并展示如需逐条查看可配合相应开关。求值节点与检查位置RFC 提出的落地路径为扩展模块输出节点在用户指定弃用消息时给值打上弃用标记随后在tofu.EvalContext用于求值表达式与块的位置即EvalContext.EvaluateBlock与EvalContext.EvaluateExpr检查该标记。检查时必须考虑deprecation标志即 CLI 的module:all/module:local/module:none的取值若值是在自身标记弃用的模块内部被使用则不应触发警告避免模块作者自己使用自己的弃用接口时收到警告。该方案的另一收益是可复用性未来若需要从其它来源不限于模块输出标记更多值为弃用可直接复用这套求值检查实现。命令行控制-deprecation 标志RFC 提出的deprecationCLI 标志已在仓库中落地为-deprecation参数。其解析逻辑位于 internal/command/arguments/deprecation_level.go定义了三级枚举const ( // 显示所有模块的弃用警告不做任何过滤 DeprecationWarningLevelAll DeprecationWarningLevel iota // 仅显示来自相对路径引用模块本地模块的弃用警告 DeprecationWarningLevelLocal // 禁用全部弃用警告 DeprecationWarningLevelNone )ParseDeprecatedWarningLevel将字符串映射为枚举all含空字符串→ Alllocal→ Localnone→ None遇到未知值时不报错而是记录 WARN 日志并回退到 All 级别——因为弃用警告对系统运行不构成关键影响容错优先。命令行注册位于 internal/command/arguments/view.goSpecify what type of warnings are shown. Accepted values for m: all, local, none. Default: all. When all is selected, OpenTofu will show the deprecation warnings for all modules. When local is selected, the warns will be shown only for the modules that are imported with a relative path. When none is selected, all the deprecation warnings will be dropped.该参数被标记为全局参数SetGlobal(true)可同时传入多个值但要求统一使用module:前缀若出现其它前缀如backend:arg会返回错误Expected -deprecation prefix module:而module:之外的命名空间参数则被保留为未解析参数为未来扩展预留空间。对应的解析测试位于 internal/command/arguments/view_test.go覆盖了-deprecationmodule:all、-deprecationmodule:local、-deprecationmodule:none以及混合命名空间的场景。典型用法示例# 默认行为显示所有模块的弃用警告 tofu plan # 仅显示本地模块相对路径引用产生的弃用警告 tofu plan -deprecationmodule:local # 完全静默所有弃用警告 tofu plan -deprecationmodule:none“本地模块”的定义RFC 中“本地模块”指从本地文件系统获取的模块。在 deprecation_level.go 的注释中进一步明确为以相对路径relative path引用的模块。这一点在判断哪些警告可被静默时至关重要——配置作者对本地相对路径引用的模块拥有直接控制权因而默认不应静默其警告。替代方案对比为什么最终选择 deprecated 字段RFC 详细列出了当时考虑过的其它备选方案主要从 UX 角度并说明了各自的取舍这对于理解最终设计非常关键。HCL 注释标记# deprecated: This variable will be removed on 2024-12-31. Use another_variable instead. variable this_is_my_variable { type string description This is a variable for the old way of configuring things. }当前 OpenTofu 不把注释视为有特殊含义的内容引入该能力等于为整个语言新增一套跨模块使用的功能体系需要单独的 RFC 来定义其演进方式。此外hclsyntax解析器的内部实现也限制了注释成为合法配置组成部分。独立的 deprecation 块variable this_is_my_variable { type string description This is a variable for the old way of configuring things. } deprecation this_is_my_variable { type variable message This variable will be removed on 2024-12-31. Use another_variable instead. }该方案过于冗长且与 OpenTofu 语言设计风格不一致。不过其优点是可将弃用声明放进单独的.tofu文件从而与其它工具保持兼容。自定义变量校验custom variable validationvariable this_is_my_variable { type string description This is a variable for the old way of configuring things. validation { condition var.this_is_my_variable ! null warning_message This variable will be removed on 2024-12-31. Use another_variable instead. } }该方案可用于在潜在不当行为发生时给出通用警告可复用于变量弃用场景但无法覆盖输出的弃用输出没有类似的校验机制因此不完整。扩展变量 description已被 TSC 否决variable this_is_my_variable { type string description This is a variable for the old way of configuring things. deprecated{ This variable will be removed on 2024-12-31. Use another_variable instead. } }在 description 字符串中内嵌特殊标记语法可读性与可解析性都较差已被 TSC技术指导委员会否决。开放问题与未来考量开放问题RFC 写作时无未决问题None。未来考量为 OpenTofu 语言实现通用的弃用机制本身较困难但本方案从 UX 角度看具备足够的通用性未来可扩展至其它用途保持 OpenTofu 用户一致的体验。弃用标记机制允许复用求值检查部分的实现在未来处理更多deprecation标志。与上游兼容性RFC 写作时 Terraform 尚未发布模块变量与输出的弃用机制因此 OpenTofu 将该功能标记为实验性experimental以便未来按需调整 UX同时保持与上游项目的兼容性。在使用该功能时请注意这一实验性定位。从 RFC 到实现关键源码索引如果你希望深入阅读该机制的实现细节以下是仓库中的关键入口关注点文件deprecated字段的配置解析与空值校验internal/configs/named_values.go弃用标记类型、注入与诊断提取internal/lang/marks/marks.go弃用变量求值警告生成internal/tofu/eval_variable.go-deprecation级别枚举与解析internal/command/arguments/deprecation_level.go-deprecation命令行参数注册internal/command/arguments/view.go命令行参数解析测试internal/command/arguments/view_test.go变量弃用官方文档website/docs/language/values/variables.mdx输出弃用官方文档website/docs/language/values/outputs.mdx总结模块变量与输出的弃用机制是 OpenTofu 在模块生态治理上的一项务实设计它以极小的语法成本variable/output块中各加一个deprecated字符串参数将“何时弃用、如何迁移”的声明权交还给模块作者同时借助 go-cty value marks 机制让弃用状态随值在求值图中传播从而在validate、plan、apply、test全流程中对实际使用者给出精准警告。配合-deprecationmodule:all|local|none三级控制用户既能看到全部警告也可以针对无法掌控的远程依赖模块选择性静默。虽然该功能目前处于实验性阶段但其清晰的 UX 设计与可复用的标记实现为 OpenTofu 未来扩展更通用的弃用机制奠定了坚实基础。【免费下载链接】opentofuOpenTofu lets you declaratively manage your cloud infrastructure.项目地址: https://gitcode.com/gh_mirrors/op/opentofu创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →