Ansible 弃用机制详解:4 个版本的弃用周期与 Display.deprecated / AnsibleModule.deprecate 实践
2026/9/12 6:26:35 网站建设 项目流程

Ansible 弃用机制详解:4 个版本的弃用周期与 Display.deprecated / AnsibleModule.deprecate 实践

【免费下载链接】ansibleAnsible is a radically simple IT automation platform that makes your applications and systems easier to deploy and maintain. Automate everything from code deployment to network configuration to cloud management, in a language that approaches plain English, using SSH, with no agents to install on remote systems. https://docs.ansible.com.项目地址: https://gitcode.com/GitHub_Trending/ans/ansible

本文围绕 Ansible 仓库中的向后兼容与弃用(Deprecation)政策展开:先讲清楚“弃用 4 个版本后才移除”的版本节奏如何计算,再结合仓库源码剖析Display.deprecatedAnsibleModule.deprecate两个标记 API 的真实签名、消息格式化逻辑以及警告去重与任务级捕获机制。读完之后,你将知道如何在贡献代码时正确标注一个即将被移除的功能,并理解用户侧看到的[DEPRECATION WARNING]消息是怎么一步步生成的。

为什么向后兼容优先

context/deprecation.md 开篇只有一句话,但它是整个政策的总纲:

Backward compatibility is prioritized over most other concerns.(向后兼容性优先于绝大多数其他考量。)

Ansible 是一个面向生产环境的自动化平台,Playbook、Role 和模块往往在团队与组织间长期复用。一旦某个接口说删就删,所有依赖它的用户都会被静默打断。因此仓库采用了一个明确的、可预测的弃用周期:先给用户充足的迁移窗口期,再执行移除。理解这个周期,是正确使用下文两个 API 的前提。

弃用周期:deprecation + 2 个过渡版本 + removal

文档给出的规则是:

  • 弃用周期为4 个版本deprecation + 2 releases + removal(标记弃用 + 2 个中间发布 + 移除)。
  • 移除版本的计算方式:当前版本 + 3。当前版本以 lib/ansible/release.py 中的__version__为准。
  • 文档中的示例:在 2.19 标记弃用,意味着在 2.22 移除。

也就是说,一个功能从“还能正常使用但开始报警告”到“彻底消失”,中间有 3 个完整版本的缓冲期。用一个简表来描述时间线:

版本(以 release.py 当前版本 C 计)状态用户可见行为
C(deprecation 版本)标记弃用运行触发该功能的 Playbook 时打印[DEPRECATION WARNING],功能仍可用
C+1、C+2(过渡版本)过渡期持续打印弃用警告,功能仍可用
C+3(removal 版本)移除触发该功能直接报错,消息变为“was removed”

以当前仓库快照验证这条规则:lib/ansible/release.py 中__version__ = '2.22.0.dev0',即当前开发版本为 2.22,按“+3”规则,现在标记弃用的功能应写移除版本2.25。这也解释了为什么仓库源码中能看到大量version='2.23'version='2.24'之类的弃用调用——它们是前几个版本标记、尚未到达移除点的功能。

标记弃用代码的两个官方入口

文档“Deprecating code”一节的原话是:

UseDisplay.deprecatedorAnsibleModule.deprecatewith the removal version.(使用Display.deprecatedAnsibleModule.deprecate并带上移除版本。)

两个 API 分别对应 Ansible 的两类代码场景,必须“with the removal version”——即version参数填的是移除版本而不是当前版本,这正是上一条“+3”规则落到代码里的写法。

控制器侧:Display.deprecated

Display.deprecated定义在 lib/ansible/utils/display.py,完整签名为:

def deprecated( self, msg: str, version: str | None = None, removed: bool = False, date: str | None = None, collection_name: str | None = None, *, deprecator: _messages.PluginInfo | None = None, help_text: str | None = None, obj: t.Any = None, ) -> None:

关键参数说明(来自源码 docstring 与实现):

  • msg:面向用户的弃用说明,应说明“什么变了、应该改成什么”。
  • version/date:二者只能给其一,不能同时给date若使用必须是YYYY-MM-DD格式(针对以日期为节奏发布的外部集合)。
  • removedTrue表示该功能已到移除点,此时消息前缀从[DEPRECATION WARNING]:变为[DEPRECATED]:,并且不是打警告而是直接抛出AnsibleError——即“警告”升级为硬错误,见 display.py 的实现。
  • help_text:给用户的具体迁移指引(如替代写法、替代参数名)。
  • obj:触发弃用的源码对象,用于在错误上下文中标注来源位置。
  • collection_name/deprecator:大多数调用方无需提供;确需指定时二者只给一个,内部由_deprecator.get_best_deprecator归一化。

仓库中一个真实的调用例子在模板引擎的条件表达式处理里,lib/ansible/_internal/_templating/_engine.py:

if conditional in (None, ''): # deprecated backward-compatible behavior; None/empty input conditionals are always True if _TemplateConfig.allow_broken_conditionals: _display.deprecated( msg='Empty conditional expression was evaluated as True.', help_text=self._BROKEN_CONDITIONAL_ALLOWED_FRAGMENT, obj=conditional, version='2.23', ) return True raise AnsibleBrokenConditionalError("Empty conditional expressions are not allowed.", obj=conditional)

这段代码完整演示了文档要求的全部要素:msg说明行为、help_text给出替代方案、obj指向触发源、version='2.23'是移除版本(当前 2.22 基础上 +3 以内)。同时可以看到典型的“弃用期 + 移除点”双分支写法:过渡期内打弃用警告并保留旧行为,移除后同一位置抛出正式异常。

模块侧:AnsibleModule.deprecate

当弃用的代码运行在远端(被打包成模块执行的 Python 代码)时,控制器侧的Display不可用,文档因此给出第二个入口AnsibleModule.deprecate,定义在 lib/ansible/module_utils/basic.py:

def deprecate( self, msg: str, version: str | None = None, date: str | None = None, collection_name: str | None = None, *, deprecator: _messages.PluginInfo | None = None, help_text: str | None = None, ) -> None: """ Record a deprecation warning to be returned with the module result. ... Specify `version` or `date`, but not both. If `date` is a string, it must be in the form `YYYY-MM-DD`. """

与控制器侧的差异在于:模块是“执行完把 JSON 结果发回”的模型,没有实时终端可写,所以 docstring 明确说明其语义是“Record a deprecation warning to be returned with the module result”——把警告记录进模块结果,随结果一起传回控制器,最终由回调层展示。参数规则与Display.deprecated一致:versiondate二选一、日期格式YYYY-MM-DDversion填移除版本。

弃用消息的内部处理链

知道两个入口之后,再看这些警告在 Ansible 内部如何被格式化与分发,能解释用户在终端看到的每一段文字。

1. 前缀与措辞的拼装。lib/ansible/_internal/_display_utils.py 的get_deprecation_message_with_plugin_info负责生成最终文案:未移除时前缀为[DEPRECATION WARNING]:,已移除时为[DEPRECATED]:;时间片段按“有date→ in a release after <date>;有version→ version <version>;都没有 → in a future release”的规则生成;如果removed=True,措辞从 “This feature will be removed” 切换为 “This feature was removed”。函数还会根据deprecator信息把消息归属到具体的集合与插件(例如module 'xxx' in collection 'ansible.builtin',builtin 集合统一显示为 “ansible-core”)。

2. 移除点即报错。如前文所述,Display._deprecated_with_plugin_inforemoved=True分支中直接raise AnsibleError(formatted_msg),保证移除版本中旧功能一触即错,而不是继续静默工作。

3. 展示期去重。display.py 中的_deduplicate在“打印时”才对消息做去重:同一警告在一个运行内重复触发时只在终端打印一次,但注释特别说明去重发生在很晚的阶段,“Duplicates included in task results will always be visible to registered variables and callbacks”——注册变量和回调中看到的重复警告不受去重影响,避免丢失警告与具体任务的对应关系。

4. 任务级延迟捕获。lib/ansible/_internal/_display_utils.py 定义了DeferredWarningContext:在该上下文内调用Display.warning()/Display.deprecated()时,警告不会被立即打印,而是被捕获并附加到任务结果上(区分get_warnings()get_deprecation_warnings()两类),由当前激活的显示回调统一呈现给用户。这是“警告必须能被register到的结果看到、也能被任务归属”这一设计目标的具体实现。

给贡献者的落地清单

综合 context/deprecation.md 的政策与上述源码实现,在 Ansible 中标记一个功能弃用时应做到:

  1. 算对移除版本:读 lib/ansible/release.py 的__version__,移除版本 = 当前版本 + 3;写version=参数时填这个值,不要填当前版本。
  2. 选对入口:控制器侧代码(解析、执行器、模板引擎等)用Display.deprecated;模块内代码(会在远端执行的lib/ansible/modules/module_utils)用AnsibleModule.deprecate
  3. 写清 msg 与 help_textmsg说清被弃用的行为,help_text给出替代做法;versiondate只提供一个。
  4. 为移除版本准备分支:参考 _engine.py 的条件表达式处理 的写法,过渡期走弃用警告,移除点抛出正式异常或彻底删除旧行为。
  5. 注意警告的去重与捕获边界:终端打印会去重,但任务结果、注册变量与回调中仍会保留完整警告;不要把“终端只出现一次”当作“只发生了一次”的证据。

这套“4 版本周期 + 两个标记 API + 展示期去重/任务级捕获”的组合,构成了 Ansible 在快速演进的代码库中仍然能给出稳定迁移路径的机制基础。

【免费下载链接】ansibleAnsible is a radically simple IT automation platform that makes your applications and systems easier to deploy and maintain. Automate everything from code deployment to network configuration to cloud management, in a language that approaches plain English, using SSH, with no agents to install on remote systems. https://docs.ansible.com.项目地址: https://gitcode.com/GitHub_Trending/ans/ansible

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

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

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

立即咨询