Ansible 模块架构

如果您正在处理 ansible-core 代码、编写 Ansible 模块或开发操作插件,您可能需要了解 Ansible 的程序流如何执行。如果您只是在剧本中使用 Ansible 模块,则可以跳过此部分。

模块类型

Ansible 在其代码库中支持几种不同类型的模块。其中一些是为了向后兼容性,而另一些是为了提供灵活性。

操作插件

操作插件对于任何编写剧本的人来说看起来都像模块。大多数操作插件的使用文档都存在于同名模块中。一些操作插件完成所有工作,而模块只提供文档。一些操作插件执行模块。The normal 操作插件执行没有特殊操作插件的模块。操作插件始终在控制节点上执行。

一些操作插件在控制节点上完成所有工作。例如,debug 操作插件(它为用户打印文本以供查看)和 assert 操作插件(它测试剧本中的值是否满足特定条件)完全在控制节点上执行。

大多数操作插件在控制节点上设置一些值,然后在托管节点上调用一个实际的模块,该模块对这些值执行某些操作。例如,template 操作插件从用户那里获取值,以使用来自剧本环境的变量在控制节点上的临时位置构造一个文件。然后,它将临时文件传输到远程系统上的临时文件。之后,它调用 copy module,它在远程系统上运行,将文件移动到其最终位置,设置文件权限等。

新式模块

与 Ansible 捆绑在一起的所有模块都属于此类别。虽然您可以用任何语言编写模块,但所有官方模块(与 Ansible 捆绑在一起)都使用 Python 或 PowerShell。

新式模块以某种方式将模块的参数嵌入到模块本身中。旧式模块必须将一个单独的文件复制到托管节点,这效率较低,因为它需要两次跨网络连接,而不是只有一次。

Python

新式 Python 模块使用 Ansiballz 框架 框架来构造模块。这些模块使用来自 ansible.module_utils 的导入来引入模块样板代码,例如参数解析、将返回值格式化为 JSON 以及各种文件操作。

注意

在 Ansible 中,直到版本 2.0.x,官方 Python 模块使用 模块替换器框架 框架。对于模块作者而言,Ansiballz 框架 在很大程度上是 模块替换器框架 功能的超集,因此您通常不需要了解它们之间的区别。

PowerShell

新式 PowerShell 模块使用 模块替换器框架 框架来构造模块。这些模块在发送到托管节点之前,会将一个 PowerShell 代码库嵌入到它们中。

JSONARGS 模块

这些模块是脚本,它们在脚本体中包含字符串 <<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>。此字符串将被替换为 JSON 格式的参数字符串。这些模块通常将变量设置为该值,例如

json_arguments = """<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>"""

它将扩展为

json_arguments = """{"param1": "test's quotes", "param2": "\"To be or not to be\" - Hamlet"}"""

注意

Ansible 输出一个包含裸引号的 JSON 字符串。双引号用于引用字符串值,字符串值内的双引号用反斜杠转义,单引号可以在字符串值内不转义地出现。要使用 JSONARGS,您的脚本语言必须有一种方法来处理这种类型的字符串。该示例使用 Python 的三引号字符串来执行此操作。其他脚本语言可能具有类似的引号字符,这些字符不会与 JSON 中的任何引号混淆,或者它可能允许您定义自己的开始引号和结束引号字符。如果语言没有为您提供任何这些功能,那么您需要编写一个 非原生 JSON 模块旧式模块

这些模块通常使用 JSON 库解析 json_arguments 的内容,然后在整个代码中使用它们作为本地变量。

非原生想要 JSON 模块

如果模块在任何位置都包含字符串 WANT_JSON,Ansible 将其视为一个非原生模块,它接受一个文件名作为其唯一的命令行参数。文件名用于一个包含 JSON 字符串的临时文件,该字符串包含模块的参数。该模块需要打开文件,读取和解析参数,对数据进行操作,并将返回数据作为 JSON 编码的字典打印到标准输出,然后退出。

这些类型的模块是自包含的实体。从 Ansible 2.1 开始,Ansible 只是修改它们以更改 shebang 行(如果存在)。

另请参见

用 ruby 编写的非原生模块示例位于 Ansible for Rubyists 存储库中。

二进制模块

从 Ansible 2.2 开始,模块也可以是小型二进制程序。Ansible 不会执行任何魔法来使这些程序可移植到不同的系统,因此它们可能特定于编译它们的系统,或者需要其他二进制运行时依赖项。尽管有这些缺点,但您可能必须针对特定的二进制库编译自定义模块,因为这是访问某些资源的唯一方法。

二进制模块接收参数并以与想要 JSON 模块相同的方式向 Ansible 返回数据。

另请参见

一个用 go 编写的二进制模块示例。

旧式模块

旧式模块类似于想要 JSON 模块,除了它们接收的文件包含用于参数的key=value对,而不是JSON。当模块没有显示它属于其他类型的任何标记时,Ansible 会将其视为旧式模块。

模块如何执行

当用户使用 ansibleansible-playbook 时,他们会指定要执行的任务。任务通常是模块的名称以及传递给模块的多个参数。Ansible 会接收这些值并在最终在远程机器上执行之前以各种方式处理它们。

执行器/任务执行器

TaskExecutor 接收从剧本(或在 /usr/bin/ansible 的情况下从命令行)解析的模块名称和参数。它使用该名称来确定它正在查看模块还是操作插件。如果是模块,它会加载正常操作插件,并将名称、变量以及有关任务和剧本的其他信息传递给该操作插件以进行进一步处理。

The normal 操作插件

The normal 操作插件在远程主机上执行模块。它是实际在管理机器上执行模块的大部分工作的核心协调器。

  • 它会加载适用于该任务的连接插件,然后根据需要进行传输或执行以建立与该主机的连接。

  • 它会将任何内部 Ansible 属性添加到模块的参数中(例如,将no_log传递给模块的参数)。

  • 它与其他插件(连接、shell、become、其他操作插件)一起在远程机器上创建任何临时文件,并在之后清理。

  • 它会将模块和模块参数推送到远程主机,尽管下一节中描述的module_common代码会决定这些参数将采用哪种格式。

  • 它会处理与模块相关的任何特殊情况(例如,异步执行,或 Windows 模块必须与 Python 模块具有相同名称,以便从其他操作插件中进行内部调用)。

这些功能中的大部分来自BaseAction类,它位于plugins/action/__init__.py中。它使用ConnectionShell对象来执行其工作。

注意

任务使用async:参数运行时,Ansible 使用async操作插件而不是normal操作插件来调用它。该程序流程目前没有记录。请阅读源代码以了解其工作原理。

执行器/module_common.py

executor/module_common.py中的代码会组装要发送到管理节点的模块。首先读取模块,然后检查其类型。

在组装步骤之后,会对所有具有 shebang 行的模块进行最后一次修改。Ansible 检查 shebang 行中的解释器是否在ansible_$X_interpreter清单变量中配置了特定路径。如果有,Ansible 会用该路径替换模块中给出的解释器路径。之后,Ansible 会将完整的模块数据和模块类型返回给正常操作,以便继续执行模块。

组装框架

Ansible 支持两种组装框架:Ansiballz 和更早的模块替换器。

模块替换器框架

模块替换器框架是实现新式模块的原始框架,它仍然用于 PowerShell 模块。它本质上是一个预处理器(类似于那些熟悉 C 语言的人所熟悉的 C 预处理器)。它对模块文件中的特定子字符串模式进行直接替换。有两种类型的替换。

  • 仅在模块文件中进行的替换。这些是模块可以利用的公共替换字符串,以获取有用的样板或访问参数。

    • from ansible.module_utils.MOD_LIB_NAME import *ansible/module_utils/MOD_LIB_NAME.py的内容替换。这些只应该与新式 Python 模块一起使用。

    • #<<INCLUDE_ANSIBLE_MODULE_COMMON>> 等同于from ansible.module_utils.basic import *,也应该只应用于新式 Python 模块。

    • # POWERSHELL_COMMON 会替换ansible/module_utils/powershell.ps1的内容。它应该只与新式 Powershell 模块一起使用。

  • ansible.module_utils代码使用的替换。这些是内部替换模式。它们可以在内部使用,也可以在上述公共替换中使用,但不应该直接由模块使用。

    • "<<ANSIBLE_VERSION>>" 被 Ansible 版本替换。在新式 Python 模块下,在Ansiballz 框架框架中,正确的方法是实例化一个AnsibleModule,然后从 :attr:AnsibleModule.ansible_version访问版本。

    • "<<INCLUDE_ANSIBLE_MODULE_COMPLEX_ARGS>>" 被一个字符串替换,该字符串是JSON编码的模块参数的 Pythonrepr。对 JSON 字符串使用repr 使其能够安全地嵌入 Python 文件中。在新式 Python 模块下,在 Ansiballz 框架中,最好通过实例化一个AnsibleModule并使用AnsibleModule.params来访问它。

    • <<SELINUX_SPECIAL_FILESYSTEMS>> 会替换一个字符串,该字符串是一个用逗号分隔的文件系统列表,这些文件系统在 SELinux 中具有依赖于文件系统的安全上下文。在新式 Python 模块中,如果你真的需要它,你应该实例化一个AnsibleModule,然后使用AnsibleModule._selinux_special_fs来访问它。该变量也从逗号分隔的文件系统名称字符串更改为实际的 Python 文件系统名称列表。

    • <<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>> 会替换模块参数,使其成为一个 JSON 字符串。必须注意正确地引用该字符串,因为 JSON 数据可能包含引号。在新式 Python 模块中,不会替换该模式,因为它们可以通过其他方式获取模块参数。

    • 字符串syslog.LOG_USER 在任何地方出现时都会被syslog_facility替换,该syslog_facilityansible.cfg或任何适用于此主机的ansible_syslog_facility清单变量中命名。在新式 Python 模块中,这发生了细微的变化。如果你真的需要访问它,你应该实例化一个AnsibleModule,然后使用AnsibleModule._syslog_facility来访问它。它不再是实际的 syslog 设施,现在是 syslog 设施的名称。有关详细信息,请参阅关于内部参数的文档

Ansiballz 框架

Ansiballz 框架在 Ansible 2.1 中被采用,用于所有新式 Python 模块。与模块替换器不同,Ansiballz 使用 ansible/module_utils 中的真实 Python 导入,而不是仅仅预处理模块。它通过构建一个压缩文件来实现这一点 - 其中包括模块文件、模块导入的 ansible/module_utils 中的文件以及一些用于传入模块参数的样板代码。然后,压缩文件被 Base64 编码,并被包装在一个小型 Python 脚本中,该脚本对 Base64 编码进行解码,并将压缩文件放置到托管节点上的一个临时目录中。然后,它仅从压缩文件中提取 Ansible 模块脚本,并将该脚本也放置到临时目录中。然后,它设置 PYTHONPATH 以查找压缩文件中的 Python 模块,并将 Ansible 模块导入为特殊名称 __main__。将其导入为 __main__ 会使 Python 认为它正在执行脚本,而不是简单地导入模块。这使 Ansible 能够在远程机器上的单个 Python 实例中运行包装器脚本和模块代码。

注意

  • Ansible 将压缩文件包装在 Python 脚本中有两个原因:

    • 为了与 Python 2.6 兼容,该版本具有功能较弱的 Python -m 命令行开关版本。

    • 为了使管道功能正常工作。管道需要将 Python 模块管道到远程节点上的 Python 解释器。Python 了解 stdin 上的脚本,但不了解压缩文件。

  • 在 Ansible 2.7 之前,模块由第二个 Python 解释器执行,而不是在同一个进程中执行。在删除 Python-2.4 支持之后,进行了此更改以加快模块执行速度。

在 Ansiballz 中,从 ansible.module_utils 包中导入的任何 Python 模块都会触发将该 Python 文件包含到压缩文件中。模块中的 #<<INCLUDE_ANSIBLE_MODULE_COMMON>> 实例将转换为 from ansible.module_utils.basic import *,然后 ansible/module-utils/basic.py 将包含在压缩文件中。从 module_utils 中包含的文件本身也会被扫描,以查找从 module_utils 中导入的其他 Python 模块,以便也包含在压缩文件中。

传递参数

这两个框架以不同的方式传递参数

  • 模块替换器框架 中,模块参数被转换为 JSON 化字符串,并被替换到组合的模块文件中。

  • Ansiballz 框架 中,JSON 化字符串是包装压缩文件的脚本的一部分。在包装器脚本将 Ansible 模块导入为 __main__ 之前,它使用变量值对 basic.py 中的私有 _ANSIBLE_ARGS 变量进行猴子补丁。当 ansible.module_utils.basic.AnsibleModule 被实例化时,它会解析此字符串并将参数放置到 AnsibleModule.params 中,模块的其他代码可以从这里访问这些参数。

警告

如果您正在编写模块,请记住,我们传递参数的方式是内部实现细节:它在过去已经发生过变化,并且只要对通用模块_utils 代码的更改允许 Ansible 模块放弃使用 ansible.module_utils.basic.AnsibleModule,它就会再次发生变化。不要依赖于内部全局 _ANSIBLE_ARGS 变量。

需要在实例化 AnsibleModule 之前解析参数的非常动态的自定义模块可以使用 _load_params 来检索这些参数。尽管如果需要支持代码更改,_load_params 可能以破坏性的方式发生变化,但它可能比我们传递参数的方式或内部全局变量更稳定。

注意

在 Ansible 2.7 之前,Ansible 模块在第二个 Python 解释器中被调用,然后参数通过脚本的 stdin 传递到脚本。

内部参数

模块替换器框架Ansiballz 框架 都向 Ansible 模块发送了除了用户在剧本中指定的参数以外的其他参数。这些附加参数是帮助实现全局 Ansible 功能的内部参数。模块通常不需要明确了解这些参数,因为这些功能是在 ansible.module_utils.basic 中实现的。但是,某些功能需要来自模块的支持,并且了解一些内部参数是有用的。

本节中的内部参数是全局的。如果您需要向自定义模块添加本地内部参数,请为该特定模块创建操作插件。请查看 复制操作插件 中的 _original_basename 示例。

_ansible_no_log

类型:bool

当任务或剧本中的参数指定 no_log 时,将其设置为 True。任何调用 AnsibleModule.log() 函数的模块都会自动处理此操作。如果您有一个实现自身日志记录的模块,那么您需要检查 _ansible_no_log 的值。要访问模块中的 _ansible_no_log,请实例化 AnsibleModule 工具,然后检查 AnsibleModule.no_log 的值。

注意

在模块的 argument_spec 中指定的 no_log 由不同的机制处理。

_ansible_debug

类型:bool

操作详细日志记录和模块执行的外部命令的日志记录。如果模块使用 AnsibleModule.debug() 函数而不是 AnsibleModule.log() 函数,则仅当您将 _ansible_debug 参数设置为 True 时才会记录消息。要访问模块中的 _ansible_debug,请实例化 AnsibleModule 工具,并访问 AnsibleModule._debug。有关更多详细信息,请参见 DEFAULT_DEBUG

_ansible_diff

类型:bool

使用此参数,您可以配置模块以显示将应用于模板文件的更改的统一差异。要访问模块中的 _ansible_diff,请实例化 AnsibleModule 工具并访问 AnsibleModule._diff。您还可以使用剧本中的 diff 关键字或相关环境变量访问此参数。有关更多详细信息,请参见 剧本关键字DIFF_ALWAYS 配置选项。

_ansible_verbosity

类型:int

您可以使用此参数来控制日志记录的详细程度(0 表示无)。

_ansible_selinux_special_fs

类型:list 元素:strings

此参数为模块提供应具有特殊 SELinux 上下文的 文件系统的名称。它们由在文件中操作(更改属性、移动和复制)的 AnsibleModule 方法使用。

大多数模块可以使用内置的 AnsibleModule 方法来操作文件。要访问需要了解这些特殊上下文文件系统的模块,请实例化 AnsibleModule 并检查 AnsibleModule._selinux_special_fs 中的列表。

此参数替换 ansible.module_utils.basic.SELINUX_SPECIAL_FS (来自 模块替换器框架)。在模块替换器框架中,参数被格式化为逗号分隔的文件系统名称字符串。在 Ansiballz 框架下,它是一个列表。您可以使用相应的环境变量访问 _ansible_selinux_special_fs。有关更多详细信息,请参见 DEFAULT_SELINUX_SPECIAL_FS 配置选项。

在版本 2.1 中新添加。

_ansible_syslog_facility

此参数控制模块记录到哪个 syslog 设施。大多数模块应该只使用 AnsibleModule.log() 函数,该函数将使用此参数。如果模块必须自己使用此参数,它应该实例化 AnsibleModule 方法,然后从 AnsibleModule._syslog_facility 中检索 syslog 设施的名称。Ansiballz 代码不如 Module Replacer 框架 代码优雅

# Old module_replacer way
import syslog
syslog.openlog(NAME, 0, syslog.LOG_USER)

# New Ansiballz way
import syslog
facility_name = module._syslog_facility
facility = getattr(syslog, facility_name, syslog.LOG_USER)
syslog.openlog(NAME, 0, facility)

有关更多详细信息,请参阅 DEFAULT_SYSLOG_FACILITY 配置选项。

在版本 2.1 中新添加。

_ansible_version

此参数将 Ansible 的版本传递给模块。要访问它,模块应该实例化 AnsibleModule 方法,然后从 AnsibleModule.ansible_version 中检索版本。这替换了 ansible.module_utils.basic.ANSIBLE_VERSION 来自 Module Replacer 框架

在版本 2.1 中新添加。

_ansible_module_name

类型: str

此参数将有关其名称的信息传递给模块。有关更多详细信息,请参阅配置选项 DEFAULT_MODULE_NAME

_ansible_string_conversion_action

此参数提供有关模块在将用户指定模块参数的值转换为字符串后应执行的操作的说明。有关更多详细信息,请参阅 STRING_CONVERSION_ACTION 配置选项。

_ansible_keep_remote_files

类型:bool

此参数提供模块在需要保留远程文件时必须准备好的说明。有关更多详细信息,请参阅 DEFAULT_KEEP_REMOTE_FILES 配置选项。

_ansible_socket

此参数为模块提供用于持久连接的套接字。该参数使用 PERSISTENT_CONTROL_PATH_DIR 配置选项创建。

_ansible_shell_executable

类型:bool

此参数确保模块使用指定的 shell 可执行文件。有关更多详细信息,请参阅 ansible_shell_executable 远程主机环境参数。

_ansible_tmpdir

类型: str

此参数提供模块的说明,即所有命令都必须使用指定的临时目录(如果创建)。操作插件设计此临时目录。

模块可以使用公共 tmpdir 属性访问此参数。如果操作插件未设置参数,则 tmpdir 属性将创建一个临时目录。

目录名称是随机生成的,目录的根目录由以下之一确定

因此,使用 ansible.cfg 配置文件激活或自定义此设置不能保证您控制完整的值。

_ansible_remote_tmp

如果操作插件未设置 _ansible_tmpdir,则模块的 tmpdir 属性将在此目录中创建一个随机目录名称。有关更多详细信息,请参阅 shell 插件的 remote_tmp 参数。

模块返回值 & 不安全字符串

在模块执行结束时,它会将要返回的数据格式化为 JSON 字符串,并将该字符串打印到其标准输出。正常操作插件接收 JSON 字符串,将其解析为 Python 字典,并将其返回给执行器。

如果 Ansible 对每个字符串返回值进行模板化,它将容易受到具有受管节点访问权限的用户攻击。如果一个不诚实的用户将恶意代码伪装成 Ansible 返回值字符串,并且如果这些字符串随后在控制节点上进行模板化,Ansible 可能会执行任意代码。为了防止这种情况,Ansible 将返回数据中的所有字符串标记为 Unsafe,发出字符串中的任何 Jinja2 模板,而不是由 Jinja2 展开。

通过 ActionPlugin._execute_module() 调用模块返回的字符串会自动被正常操作插件标记为 Unsafe。如果另一个操作插件通过其他方式从模块检索信息,它必须自行将返回值数据标记为 Unsafe

如果编码不佳的操作插件未能将其结果标记为“Unsafe”,Ansible 会在将结果返回给执行器时再次审核这些结果,将所有字符串标记为 Unsafe。正常操作插件使用结果数据作为参数来保护自身以及它调用的任何其他代码。执行器内的检查保护所有其他操作插件的输出,确保 Ansible 运行的后续任务也不会对这些结果进行模板化。

特殊注意事项

管道

Ansible 可以通过以下两种方式之一将模块传输到远程机器

  • 它可以将模块写入远程主机上的临时文件,然后使用第二个连接到远程主机来使用模块所需的解释器执行它

  • 或者它可以使用称为管道的机制来执行模块,方法是将其管道传输到远程解释器的标准输入。

管道目前仅适用于用 Python 编写的模块,因为 Ansible 只知道 Python 支持这种操作模式。支持管道意味着,在通过网络发送之前,模块有效负载采用任何格式都必须能够通过标准输入由 Python 执行。

为什么通过标准输入传递参数?

通过标准输入传递参数的原因如下

  • ANSIBLE_PIPELINING 相结合,这可以防止模块的参数暂时保存在远程机器上的磁盘上。这使得远程机器上的恶意用户更难(但并非不可能)窃取参数中可能存在的任何敏感信息。

  • 命令行参数不安全,因为大多数系统允许非特权用户读取进程的完整命令行。

  • 环境变量通常比命令行更安全,但某些系统限制环境的总大小。如果我们达到此限制,这会导致参数被截断。

AnsibleModule

参数规范

提供给 AnsibleModuleargument_spec 定义了模块支持的参数,以及它们的类型、默认值等等。

示例 argument_spec

module = AnsibleModule(argument_spec=dict(
    top_level=dict(
        type='dict',
        options=dict(
            second_level=dict(
                default=True,
                type='bool',
            )
        )
    )
))

本节将讨论参数的行为属性

type:

type 允许您定义参数接受的值的类型。 type 的默认值为 str。可能的值有

  • str

  • list

  • dict

  • bool

  • int

  • float

  • path

  • raw

  • jsonarg

  • json

  • bytes

  • bits

raw 类型不会执行类型验证或类型转换,并保留传递值的类型。

elements:

type='list' 时, elementstype 结合使用。然后可以将 elements 定义为 elements='int' 或任何其他类型,表示指定列表的每个元素都应该具有该类型。

default:

default 选项允许为参数设置默认值,用于参数未提供给模块的场景。如果未指定,默认值为 None

fallback:

fallback 接受一个 tuple,其中第一个参数是一个可调用函数(函数),它将用于根据第二个参数执行查找。第二个参数是一个可调用函数要接受的值列表。

最常用的可调用函数是 env_fallback,它允许参数在未提供参数的情况下可选地使用环境变量。

示例

username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']))
choices:

choices 接受参数要接受的选择列表。 choices 的类型应该与 type 匹配。

required:

required 接受布尔值,可以是 TrueFalse,表示该参数是否必填。如果没有指定,required 默认值为 False。不要与 default 结合使用。

no_log:

no_log 接受布尔值,可以是 TrueFalse,明确表示该参数值是否应该在日志和输出中被屏蔽。

注意

如果没有指定 no_log,如果参数名称看起来像是表示该参数值是一个密码或口令(例如“admin_password”),则会显示警告,并且该值将在日志中被屏蔽,但 **不会** 被输出。要为不包含敏感信息的参数禁用警告和屏蔽,请将 no_log 设置为 False

aliases:

aliases 接受参数的备用名称列表,例如参数名称为 name,但模块接受 aliases=['pkg'] 以允许 pkgname 交换使用。使用别名可能会使模块接口变得混乱,因此我们建议仅在必要时添加它们。如果您要更新参数名称以修复错别字或改进接口,请考虑将旧名称移至 deprecated_aliases,而不是无限期地保留它们。

options:

options 实现创建子参数规范的能力,其中顶层参数的子选项也使用本节中讨论的属性进行验证。本节顶部的示例演示了 options 的使用。在这种情况下,typeelements 应该是 dict

apply_defaults:

apply_defaultsoptions 配合使用,允许即使在未提供顶层参数的情况下也应用子选项的 default

在本节开头的 argument_spec 示例中,它将允许定义 module.params['top_level']['second_level'],即使用户在调用模块时没有提供 top_level

removed_in_version:

removed_in_version 指示哪个版本的 ansible-core 或集合将删除弃用的参数。与 removed_at_date 相互排斥,并且必须与 removed_from_collection 一起使用。

示例

option = {
  'type': 'str',
  'removed_in_version': '2.0.0',
  'removed_from_collection': 'testns.testcol',
},
removed_at_date:

removed_at_date 指示在该日期之后,ansible-core 的次要版本或集合的主要版本将不再包含弃用的参数。与 removed_in_version 相互排斥,并且必须与 removed_from_collection 一起使用。

示例

option = {
  'type': 'str',
  'removed_at_date': '2020-12-31',
  'removed_from_collection': 'testns.testcol',
},
removed_from_collection:

指定哪个集合(或 ansible-core)弃用了此弃用的参数。对于 ansible-core,指定 ansible.builtin,或指定集合的名称(格式 foo.bar)。必须与 removed_in_versionremoved_at_date 一起使用。

deprecated_aliases:

弃用此参数的别名。必须包含一个列表或元组,其中包含一些以下键的字典

name:

要弃用的别名的名称。(必填。)

version:

ansible-core 或集合的版本,该版本将删除此别名。必须指定 versiondate

date:

此别名不再包含在 ansible-core 的次要版本或集合的主要版本的日期。必须指定 versiondate

collection_name:

指定哪个集合(或 ansible-core)弃用了此弃用的别名。对于 ansible-core,指定 ansible.builtin,或指定集合的名称(格式 foo.bar)。必须与 versiondate 一起使用。

示例

option = {
  'type': 'str',
  'aliases': ['foo', 'bar'],
  'deprecated_aliases': [
    {
      'name': 'foo',
      'version': '2.0.0',
      'collection_name': 'testns.testcol',
    },
    {
      'name': 'foo',
      'date': '2020-12-31',
      'collection_name': 'testns.testcol',
    },
  ],
},
mutually_exclusive:

如果指定了 options,则 mutually_exclusive 指的是 options 中描述的子选项,并且行为与 模块选项之间的依赖关系 中相同。

required_together:

如果指定了 options,则 required_together 指的是 options 中描述的子选项,并且行为与 模块选项之间的依赖关系 中相同。

required_one_of:

如果指定了 options,则 required_one_of 指的是 options 中描述的子选项,并且行为与 模块选项之间的依赖关系 中相同。

required_if:

如果指定了 options,则 required_if 指的是 options 中描述的子选项,并且行为与 模块选项之间的依赖关系 中相同。

required_by:

如果指定了 options,则 required_by 指的是 options 中描述的子选项,并且行为与 模块选项之间的依赖关系 中相同。

context:

版本 2.17 中新增。

您可以将 context 键的值设置为自定义内容的字典。这允许您在参数规范中提供额外的上下文。提供的内容不会被核心引擎验证或利用。

示例

option = {
    'type': 'str',
    'context': {
        'disposition': '/properties/apiType',
    },
    'choices': ['http', 'soap'],
}

模块选项之间的依赖关系

以下是 AnsibleModule() 的可选参数

module = AnsibleModule(
  argument_spec,
  mutually_exclusive=[
    ('path', 'content'),
  ],
  required_one_of=[
    ('path', 'content'),
  ],
)
mutually_exclusive:

必须是字符串序列(列表或元组)的序列。每个字符串序列都是互斥的选项名称列表。如果同时指定了列表中的多个选项,Ansible 将使用错误使模块失败。

示例

mutually_exclusive=[
  ('path', 'content'),
  ('repository_url', 'repository_filename'),
],

在本例中,选项 pathcontent 不能同时指定。此外,选项 repository_urlrepository_filename 不能同时指定。但是,指定 pathrepository_url 是被接受的。

要确保只指定两个(或更多)选项中的一个,请将 mutually_exclusiverequired_one_of 结合使用。

required_together:

必须是字符串序列(列表或元组)的序列。每个字符串序列都是必须一起指定的选项名称列表。如果指定了这些选项中的至少一个,则必须存在同一序列中的其他所有选项。

示例

required_together=[
  ('file_path', 'file_hash'),
],

在本例中,如果指定了选项 file_pathfile_hash 中的一个,如果另一个选项未指定,Ansible 将使用错误使模块失败。

required_one_of:

必须是字符串序列(列表或元组)的序列。每个字符串序列都是选项名称列表,其中必须至少指定一个。如果没有指定这些选项中的任何一个,Ansible 将使模块执行失败。

示例

required_one_of=[
  ('path', 'content'),
],

在本例中,必须至少指定 pathcontent 中的一个。如果都没有指定,执行将失败。显式允许同时指定两者;要防止这种情况,请将 required_one_ofmutually_exclusive 结合使用。

required_if:

必须是序列的序列。每个内部序列描述一个条件依赖关系。每个序列必须包含三个或四个值。前两个值是选项的名称和选项的值,它描述了条件。序列的后续元素仅在该名称的选项具有此确切值时才需要。

如果您希望在满足条件时指定列表中所有选项名称,请使用以下格式之一

('option_name', option_value, ('option_a', 'option_b', ...)),
('option_name', option_value, ('option_a', 'option_b', ...), False),

如果您希望在满足条件时指定列表中至少一个选项名称,请使用以下格式

('option_name', option_value, ('option_a', 'option_b', ...), True),

示例

required_if=[
  ('state', 'present', ('path', 'content'), True),
  ('force', True, ('force_reason', 'force_code')),
],

在本例中,如果用户指定了 state=present,则必须提供选项 pathcontent 中的至少一个(或两个)。要确保只能指定一个,请将 required_ifmutually_exclusive 结合使用。

另一方面,如果 force(一个布尔参数)设置为 true,则必须指定 force_reasonforce_code

required_by:

必须是将选项名称映射到选项名称序列的字典。如果字典键中指定了选项名称,则它映射到的选项名称也必须全部指定。请注意,除了选项名称的序列之外,您还可以指定单个选项名称。

示例

required_by={
  'force': 'force_reason',
  'path': ('mode', 'owner', 'group'),
},

在示例中,如果指定了force,则还必须指定force_reason。同样,如果指定了path,则还必须指定三个选项modeownergroup

声明检查模式支持

要声明模块支持检查模式,请在AnsibleModule()调用中提供supports_check_mode=True

module = AnsibleModule(argument_spec, supports_check_mode=True)

模块可以通过检查布尔值module.check_mode来确定它是在检查模式下被调用的。如果它评估为True,则模块必须注意不要进行任何修改。

如果指定了supports_check_mode=False(这是默认值),则模块将在检查模式下退出,并使用skipped=True和消息remote module (<insert module name here>) does not support check mode

添加文件选项

要声明模块应该添加对所有常见文件选项的支持,请在AnsibleModule()调用中提供add_file_common_args=True

module = AnsibleModule(argument_spec, add_file_common_args=True)

您可以在此处找到所有文件选项的列表。建议您将您的DOCUMENTATION扩展到文档片段ansible.builtin.files(参见文档片段),在这种情况下,以确保所有这些字段都被正确记录。

辅助函数module.load_file_common_arguments()module.set_fs_attributes_if_different()可以用来为您处理这些参数。

argument_spec = {
  'path': {
    'type': 'str',
    'required': True,
  },
}

module = AnsibleModule(argument_spec, add_file_common_args=True)
changed = False

# TODO do something with module.params['path'], like update its contents

# Ensure that module.params['path'] satisfies the file options supplied by the user
file_args = module.load_file_common_arguments(module.params)
changed = module.set_fs_attributes_if_different(file_args, changed)

module.exit_json(changed=changed)