Ansible 模块架构
如果您正在处理 ansible-core
代码、编写 Ansible 模块或开发动作插件,您可能需要了解 Ansible 的程序流程如何执行。如果您只是在 playbook 中使用 Ansible 模块,则可以跳过此部分。
模块类型
Ansible 在其代码库中支持几种不同类型的模块。其中一些是为了向后兼容性,另一些是为了实现灵活性。
动作插件
对于编写 playbook 的任何人来说,动作插件看起来都像模块。大多数动作插件的使用文档都位于同名模块中。一些动作插件完成所有工作,而模块仅提供文档。一些动作插件执行模块。normal
动作插件执行没有特殊动作插件的模块。动作插件始终在控制节点上执行。
一些动作插件在控制节点上完成所有工作。例如,debug 动作插件(打印文本供用户查看)和 assert 动作插件(测试 playbook 中的值是否满足某些条件)完全在控制节点上执行。
大多数动作插件在控制节点上设置一些值,然后在受管节点上调用实际的模块,该模块使用这些值执行某些操作。例如,template 动作插件从用户那里获取值,以使用 playbook 环境中的变量在控制节点上的临时位置构造文件。然后,它将临时文件传输到远程系统上的临时文件。之后,它调用在远程系统上操作的 copy 模块,以将文件移动到其最终位置、设置文件权限等等。
新式模块
所有与 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 编码的字典形式打印到 stdout。
这些类型的模块是自包含的实体。从 Ansible 2.1 开始,Ansible 只会修改它们的 shebang 行(如果存在)。
另请参阅
用 Ruby 编写的非原生模块的示例可以在 Ansible for Rubyists 仓库中找到。
二进制模块
从 Ansible 2.2 开始,模块也可以是小型二进制程序。Ansible 不会对这些程序进行任何特殊处理,使其可移植到不同的系统,因此它们可能特定于编译它们的系统,或者需要其他二进制运行时依赖项。尽管存在这些缺点,但如果这是访问某些资源的唯一方法,您可能需要针对特定的二进制库编译自定义模块。
二进制模块以与 want JSON 模块 相同的方式接收参数并将数据返回给 Ansible。
另请参阅
一个用 Go 编写的 二进制模块的示例。
旧式模块
旧式模块类似于 want JSON 模块,不同之处在于它们接收的文件包含 key=value
格式的参数对,而不是 JSON。当模块不包含任何其他类型模块的标记时,Ansible 会将其判断为旧式模块。
模块的执行方式
当用户使用 ansible 或 ansible-playbook 时,他们会指定要执行的任务。任务通常是模块的名称,以及要传递给模块的多个参数。Ansible 会获取这些值并以各种方式处理它们,然后才最终在远程机器上执行。
Executor/task_executor
TaskExecutor 接收从 playbook(或在 /usr/bin/ansible 的情况下从命令行)解析的模块名称和参数。它使用名称来决定它是在查看模块还是 Action Plugin。如果是模块,它会加载 Normal Action Plugin,并将名称、变量以及有关任务和 playbook 的其他信息传递给该 Action Plugin 以进行进一步处理。
normal
action 插件
normal
action 插件在远程主机上执行模块。它是将模块实际在受管机器上执行的大部分工作的主要协调者。
它为任务加载适当的连接插件,然后根据需要传输或执行以创建到该主机的连接。
它将任何内部 Ansible 属性添加到模块的参数中(例如,将
no_log
传递给模块的属性)。它与其他插件(连接、shell、become、其他 action 插件)一起工作,以在远程机器上创建任何临时文件并在之后清理。
它将模块和模块参数推送到远程主机,尽管下一节中描述的 module_common 代码决定了它们将采用哪种格式。
它处理有关模块的任何特殊情况(例如,异步执行,或者必须与 Python 模块同名的 Windows 模块的相关复杂性,以便从其他 Action Plugin 内部调用模块)。
此功能的大部分来自 BaseAction 类,它位于 plugins/action/__init__.py
中。它使用 Connection
和 Shell
对象来完成其工作。
注意
当 任务 使用 async:
参数运行时,Ansible 使用 async
Action Plugin 而不是 normal
Action Plugin 来调用它。该程序流程目前没有文档记录。请阅读源代码以获取有关其工作原理的信息。
Executor/module_common.py
executor/module_common.py
中的代码组装要发送到受管节点的模块。首先读取模块,然后检查以确定其类型。
PowerShell 和 JSON-args 模块 通过 Module Replacer 传递。
新式 Python 模块 由 Ansiballz 框架 组装。
非原生 want-JSON、二进制模块 和 旧式模块 不受上述任何一种影响,并保持不变。
在组装步骤之后,会对所有具有 shebang 行的模块进行最后一次修改。Ansible 检查 shebang 行中的解释器是否具有使用 ansible_$X_interpreter
清单变量配置的特定路径。如果有,Ansible 会将该路径替换为模块中给定的解释器路径。之后,Ansible 将完整的模块数据和模块类型返回给 Normal Action,它会继续执行模块。
汇编器框架
Ansible 支持两个汇编器框架:Ansiballz 和较旧的 Module Replacer。
Module Replacer 框架
Module Replacer 框架是实现新式模块的原始框架,并且仍然用于 PowerShell 模块。它本质上是一个预处理器(类似于熟悉该编程语言的 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
将被替换为在ansible.cfg
或适用于此主机的任何ansible_syslog_facility
清单变量中命名的syslog_facility
。在新式 Python 模块中,此功能略有变化。如果确实需要访问它,则应实例化一个 AnsibleModule,然后使用AnsibleModule._syslog_facility
来访问它。它不再是实际的 syslog facility,现在是 syslog facility 的名称。有关详细信息,请参阅有关内部参数的文档。
Ansiballz 框架
Ansible 2.1 采用了 Ansiballz 框架,并将其用于所有新式 Python 模块。与模块替换器不同,Ansiballz 使用 ansible/module_utils
中内容的实际 Python 导入,而不仅仅是预处理模块。它通过构造一个 zip 文件来实现此目的,该 zip 文件包括模块文件、ansible/module_utils
中由模块导入的文件以及一些样板代码以传递模块的参数。然后,将 zip 文件进行 Base64 编码,并将其包装在小型 Python 脚本中,该脚本对 Base64 编码进行解码,并将 zip 文件放置在受管节点上的临时目录中。然后,它仅从 zip 文件中提取 Ansible 模块脚本,并将其也放置在临时目录中。然后,它设置 PYTHONPATH 以查找 zip 文件内的 Python 模块,并将 Ansible 模块导入为特殊名称 __main__
。将其作为 __main__
导入会导致 Python 认为它正在执行脚本,而不仅仅是导入模块。这使 Ansible 可以在远程计算机上的单个 Python 副本中运行包装脚本和模块代码。
注意
Ansible 将 zip 文件包装在 Python 脚本中出于两个原因
为了与 Python 2.6 兼容,该版本具有功能较弱的 Python
-m
命令行开关。以便管道能够正常运行。管道需要将 Python 模块通过管道传输到远程节点上的 Python 解释器。Python 可以理解 stdin 上的脚本,但不能理解 zip 文件。
在 Ansible 2.7 之前,该模块由第二个 Python 解释器执行,而不是在同一进程中执行。此更改是在放弃 Python-2.4 支持后进行的,以加快模块执行速度。
在 Ansiballz 中,从 ansible.module_utils
包导入 Python 模块会触发将该 Python 文件包含到 zip 文件中。模块中的 #<<INCLUDE_ANSIBLE_MODULE_COMMON>>
实例将转换为 from ansible.module_utils.basic import *
,然后将 ansible/module-utils/basic.py
包含在 zip 文件中。从 module_utils
中包含的文件本身也会扫描来自 module_utils
的其他 Python 模块的导入,以将其包含在 zip 文件中。
传递参数
两个框架传递参数的方式不同
在模块替换器框架中,模块参数将转换为 JSON 化字符串并替换到组合的模块文件中。
在 Ansiballz 框架中,JSON 化字符串是包装 zip 文件的脚本的一部分。在包装脚本将 Ansible 模块作为
__main__
导入之前,它会使用变量值来 monkey-patchbasic.py
中的私有_ANSIBLE_ARGS
变量。实例化ansible.module_utils.basic.AnsibleModule
时,它会解析此字符串,并将参数放置在AnsibleModule.params
中,模块的其他代码可以在其中访问这些参数。
警告
如果您正在编写模块,请记住,我们传递参数的方式是内部实现细节:它在过去已发生更改,并且只要对公共 module_utils 代码的更改允许 Ansible 模块放弃使用 ansible.module_utils.basic.AnsibleModule
,它将再次发生更改。不要依赖内部全局 _ANSIBLE_ARGS
变量。
需要在实例化 AnsibleModule
之前解析参数的非常动态的自定义模块可以使用 _load_params
来检索这些参数。虽然 _load_params
如果需要支持代码更改,可能会以破坏性的方式更改,但它可能比我们传递参数的方式或内部全局变量更稳定。
注意
在 Ansible 2.7 之前,Ansible 模块在第二个 Python 解释器中调用,然后通过脚本的 stdin 将参数传递给该脚本。
内部参数
模块替换器框架和 Ansiballz 框架 都会向 Ansible 模块发送超出用户在 playbook 中指定的那些参数的其他参数。这些额外的参数是内部参数,有助于实现全局 Ansible 功能。模块通常不需要显式了解这些参数,因为这些功能是在 ansible.module_utils.basic
中实现的。但是,某些功能需要模块的支持,并且了解一些内部参数很有用。
本节中的内部参数是全局的。如果您需要向自定义模块添加本地内部参数,请为该特定模块创建一个操作插件。有关示例,请参阅 copy 操作插件中的 _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
。您还可以使用 playbook 中的 diff
关键字或相关的环境变量来访问此参数。有关更多详细信息,请参阅 Playbook 关键字 和 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 代码不如 模块替换器框架 代码优雅。
# 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
。
2.1 版本新增。
_ansible_module_name
类型:str
此参数将有关其名称的信息传递给模块。有关更多详细信息,请参阅配置选项 DEFAULT_MODULE_NAME。
_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 字符串,并将该字符串打印到其 stdout。正常的操作插件接收 JSON 字符串,将其解析为 Python 字典,并将其返回给执行器。
如果 Ansible 模板化了每个字符串返回值,它将容易受到可以访问受管节点的用户攻击。如果一个不择手段的用户将恶意代码伪装成 Ansible 返回值字符串,并且如果这些字符串随后在控制节点上被模板化,则 Ansible 可能会执行任意代码。为了防止这种情况发生,Ansible 将返回数据中的所有字符串标记为 Unsafe
,逐字发出字符串中的任何 Jinja2 模板,而不是由 Jinja2 扩展。
通过 ActionPlugin._execute_module()
调用模块返回的字符串会被正常的操作插件自动标记为 Unsafe
。如果另一个操作插件通过其他方式从模块检索信息,它必须自行将其返回数据标记为 Unsafe
。
如果编写不当的操作插件未能将其结果标记为“Unsafe”,则 Ansible 在将结果返回给执行器时会再次审核结果,将所有字符串标记为 Unsafe
。正常的操作插件会保护自身及其调用的任何其他代码,并将结果数据作为参数传递。执行器内部的检查会保护所有其他操作插件的输出,确保 Ansible 执行的后续任务也不会从这些结果中模板化任何内容。
特殊注意事项
管道
Ansible 可以通过以下两种方式之一将模块传输到远程机器
它可以将模块写入远程主机上的临时文件,然后使用与远程主机的第二个连接,使用模块需要的解释器执行它
或者,它可以使用所谓的管道将模块通过管道传输到远程解释器的 stdin 来执行模块。
管道目前仅适用于用 Python 编写的模块,因为 Ansible 只知道 Python 支持这种操作模式。支持管道意味着在通过网络发送之前模块有效负载所采用的任何格式都必须可以通过 stdin 由 Python 执行。
为什么通过 stdin 传递参数?
之所以选择通过 stdin 传递参数,原因如下
当与 ANSIBLE_PIPELINING 结合使用时,这可以防止模块的参数暂时保存在远程计算机上的磁盘上。这使得远程计算机上的恶意用户更难(但并非不可能)窃取参数中可能存在的任何敏感信息。
命令行参数是不安全的,因为大多数系统允许非特权用户读取进程的完整命令行。
环境变量通常比命令行更安全,但某些系统限制了环境的总大小。如果我们达到该限制,这可能会导致参数被截断。
AnsibleModule
参数规范
提供给 AnsibleModule
的 argument_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'
时,elements
与type
结合使用。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
接受一个布尔值,True
或False
,指示该参数是否为必需参数。 如果未指定,则required
默认为False
。 这不应与default
结合使用。- no_log:
no_log
接受一个布尔值,True
或False
,明确指示是否应在日志和输出中屏蔽参数值。注意
在没有
no_log
的情况下,如果参数名称似乎指示该参数值是密码或密码短语(例如“admin_password”),则会显示警告,并且该值将在日志中被屏蔽,但不会输出。要禁用不包含敏感信息的参数的警告和屏蔽,请将no_log
设置为False
。- aliases:
aliases
接受该参数的替代参数名称列表,例如,当参数为name
但模块接受aliases=['pkg']
以允许pkg
与name
可互换使用的情况。 使用别名可能会使模块接口混乱,因此我们建议仅在必要时添加它们。 如果您正在更新参数名称以修复拼写错误或改进接口,请考虑将旧名称移动到deprecated_aliases
,而不是无限期地保留它们。- options:
options
实现了创建子参数规范的能力,其中顶级参数的子选项也使用本节中讨论的属性进行验证。 本节顶部的示例演示了options
的用法。 在这种情况下,type
或elements
应为dict
。- apply_defaults:
apply_defaults
与options
一起使用,并允许即使在未提供顶级参数时也应用子选项的default
。在本节顶部的
argument_spec
示例中,即使用户在调用模块时未提供top_level
,它也允许定义module.params['top_level']['second_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_version
或removed_at_date
一起使用。- deprecated_aliases:
弃用此参数的别名。 必须包含一个字典列表或元组,其中包含以下一些键:
- name:
要弃用的别名的名称。(必需。)
- version:
此别名将被删除的 ansible-core 或集合的版本。 必须指定
version
或date
中的一个。- date:
一个日期,在此日期之后,次要版本的 ansible-core 或主要集合版本将不再包含此别名。 必须指定
version
或date
中的一个。- collection_name:
指定哪个集合(或 ansible-core)弃用了此弃用的别名。 对于 ansible-core,请指定
ansible.builtin
,或集合的名称(格式为foo.bar
)。 必须与version
或date
一起使用。
示例
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'), ],
在此示例中,选项
path
和content
不能同时指定。 此外,选项repository_url
和repository_filename
不能同时指定。 但是,指定path
和repository_url
是可以接受的。要确保精确指定两个(或多个)选项中的一个,请将
mutually_exclusive
与required_one_of
结合使用。- required_together:
必须是字符串序列的序列(列表或元组)。每个字符串序列都是一个选项名称列表,这些选项必须一起指定。如果指定了这些选项中的至少一个,则必须同时存在同一序列中的其他选项。
示例
required_together=[ ('file_path', 'file_hash'), ],
在此示例中,如果指定了
file_path
或file_hash
选项之一,如果未指定另一个选项,Ansible 将使模块失败并显示错误。- required_one_of:
必须是字符串序列的序列(列表或元组)。每个字符串序列都是一个选项名称列表,必须从中指定至少一个选项。如果未指定这些选项中的任何一个,Ansible 将导致模块执行失败。
示例
required_one_of=[ ('path', 'content'), ],
在此示例中,必须指定
path
和content
中的至少一个。如果未指定任何一个,则执行将失败。明确允许指定两者;要阻止这种情况,请将required_one_of
与mutually_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
,则必须提供path
和content
选项中的至少一个(或两者)。为了确保只能指定一个,请将required_if
与mutually_exclusive
结合使用。另一方面,如果将
force
(一个布尔参数)设置为true
,yes
等,则必须同时指定force_reason
和force_code
。- required_by:
必须是将选项名称映射到选项名称序列的字典。如果在字典键中指定了选项名称,则它映射到的选项名称也必须全部指定。请注意,除了选项名称序列之外,您还可以指定一个单独的选项名称。
示例
required_by={ 'force': 'force_reason', 'path': ('mode', 'owner', 'group'), },
在示例中,如果指定了
force
,则还必须指定force_reason
。此外,如果指定了path
,则还必须指定mode
、owner
和group
这三个选项。
声明检查模式支持
要声明模块支持检查模式,请向 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)