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 编码的字典打印到标准输出。
这些类型的模块是自包含的实体。从 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 会获取这些值并以各种方式处理它们,然后最终在远程机器上执行它们。
执行器/task_executor
TaskExecutor 接收从 剧本(或在 /usr/bin/ansible 的情况下从命令行)解析的模块名称和参数。它使用名称来确定它正在查看模块还是 动作插件。如果是模块,它会加载 普通动作插件 并将名称、变量以及有关任务和剧本的其他信息传递给该动作插件以进行进一步处理。
normal
动作插件
normal
动作插件在远程主机上执行模块。它是实际在受管机器上执行模块的大部分工作的协调者。
它加载任务的相应连接插件,然后根据需要传输或执行以创建到该主机的连接。
它将任何内部 Ansible 属性添加到模块的参数中(例如,将
no_log
传递给模块的属性)。它与其他插件(连接、shell、become、其他动作插件)协同工作,在远程机器上创建任何临时文件并在之后清理。
它将模块和模块参数推送到远程主机,尽管下一节中描述的 module_common 代码决定了这些参数将采用哪种格式。
它处理与模块相关的任何特殊情况(例如,异步执行,或围绕必须与 Python 模块具有相同名称的 Windows 模块的复杂情况,以便从其他动作插件内部调用模块)。
许多此功能来自 BaseAction 类,该类位于 plugins/action/__init__.py
中。它使用 Connection
和 Shell
对象来完成其工作。
注意
当使用 async:
参数运行 任务 时,Ansible 使用 async
动作插件而不是 normal
动作插件来调用它。该程序流程目前没有记录。阅读源代码以了解其工作原理。
执行器/module_common.py
executor/module_common.py
中的代码组装要发送到受管节点的模块。模块首先被读取,然后检查以确定其类型
PowerShell 和 JSON 参数模块 通过 模块替换器 传递。
新式 Python 模块 由 Ansiballz 框架 组装。
非原生-want-JSON、二进制模块 和 旧式模块 不会被这两个框架中的任何一个触及,并且会原样传递。
在组装步骤之后,对所有具有 shebang 行的模块进行最终修改。Ansible 检查 shebang 行中的解释器是否具有使用 ansible_$X_interpreter
清单变量配置的特定路径。如果存在,Ansible 会将该路径替换为模块中给出的解释器路径。之后,Ansible 将完整的模块数据和模块类型返回到 普通动作,后者继续执行模块。
组装框架
Ansible 支持两种组装框架:Ansiballz 和较旧的模块替换器。
模块替换器框架
模块替换器框架是实现新式模块的原始框架,并且仍然用于 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 编码后,再使用 Python 的repr
函数进行转换的结果。使用repr
函数可以安全地将 JSON 字符串嵌入到 Python 文件中。在 Ansiballz 框架下的新式 Python 模块中,可以通过实例化一个 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
,该值在ansible.cfg
或任何适用于此主机的ansible_syslog_facility
库存变量中命名。在新式 Python 模块中,这一点略有变化。如果您确实需要访问它,则应实例化一个 AnsibleModule 对象,然后使用AnsibleModule._syslog_facility
来访问它。它不再是实际的 syslog 设施,而是 syslog 设施的名称。有关详细信息,请参阅 内部参数文档。
Ansiballz 框架
Ansiballz 框架在 Ansible 2.1 中被采用,并用于所有新式 Python 模块。与模块替换器不同,Ansiballz 使用 ansible/module_utils
中的真实 Python 导入,而不是仅仅预处理模块。它通过构建一个 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 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__
之前,它会使用变量值修补basic.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
中实现的。但是,某些功能需要模块的支持,并且了解一些内部参数是有用的。
本节中的内部参数是全局的。如果您需要向自定义模块添加本地内部参数,请为此特定模块创建操作插件。有关示例,请参阅 复制操作插件 中的 _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_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 通过 stdin 执行。
为什么通过 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
的默认值为str
。可能的值包括:str
list
dict
bool
int
float
path
raw
jsonarg
json
bytes
bits
raw
类型不执行任何类型验证或类型转换,并保持传递值的类型。- 元素:
当
type='list'
时,elements
与type
结合使用。然后可以将elements
定义为elements='int'
或任何其他类型,表示指定列表的每个元素都应为该类型。- 默认值:
default
选项允许为参数设置默认值,用于未向模块提供参数的情况。如果未指定,则默认值为None
。- 回退:
fallback
接受一个tuple
,其中第一个参数是可调用对象(函数),将根据第二个参数用于执行查找。第二个参数是要由可调用对象接受的值列表。最常用的可调用对象是
env_fallback
,它允许参数在未提供参数时可选地使用环境变量。示例
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME']))
- 选项:
choices
接受一个参数将接受的选择列表。choices
的类型应与type
匹配。- 必需:
required
接受布尔值,True
或False
,表示参数是否必需。如果未指定,则required
默认值为False
。不应与default
结合使用。- 不记录:
no_log
接受布尔值,True
或False
,显式指示是否应在日志和输出中屏蔽参数值。注意
在没有
no_log
的情况下,如果参数名称似乎表明参数值是密码或口令(例如“admin_password”),则会显示警告,并且该值将在日志中被屏蔽,但**不会**在输出中被屏蔽。要禁用对不包含敏感信息的参数的警告和屏蔽,请将no_log
设置为False
。- 别名:
aliases
接受参数的替代参数名称列表,例如参数为name
但模块接受aliases=['pkg']
以允许pkg
与name
交换使用。使用别名可能会使模块接口变得混乱,因此我们建议仅在必要时添加它们。如果您正在更新参数名称以修复错别字或改进接口,请考虑将旧名称移动到deprecated_aliases
而不是无限期地保留它们。- 选项:
options
实现创建子参数规范的功能,其中顶级参数的子选项也使用本节中讨论的属性进行验证。本节顶部的示例演示了options
的用法。在这种情况下,type
或elements
应为dict
。- 应用默认值:
apply_defaults
与options
一起工作,并允许即使在未提供顶级参数时也应用子选项的default
。在本节顶部
argument_spec
的示例中,它将允许定义module.params['top_level']['second_level']
,即使用户在调用模块时未提供top_level
。- 已移除的版本:
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
指示在该日期之后的 ansible-core 次要版本或集合主要版本将不再包含弃用的参数。与removed_in_version
互斥,并且必须与removed_from_collection
一起使用。示例
option = { 'type': 'str', 'removed_at_date': '2020-12-31', 'removed_from_collection': 'testns.testcol', },
- 已移除的集合:
指定哪个集合(或 ansible-core)弃用了此弃用的参数。对于 ansible-core,指定
ansible.builtin
,或集合的名称(格式foo.bar
)。必须与removed_in_version
或removed_at_date
一起使用。- 弃用的别名:
弃用此参数的别名。必须包含一个字典列表或元组,其中包含以下一些键:
- 名称:
要弃用的别名名称。(必需。)
- 版本:
ansible-core 或集合的哪个版本将删除此别名。必须指定
version
或date
之一。- 日期:
ansible-core 的次要版本或集合的主要版本将不再包含此别名的日期。必须指定
version
或date
之一。- 集合名称:
指定哪个集合(或 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', }, ], },
- 互斥:
如果指定了
options
,则mutually_exclusive
指的是options
中描述的子选项,其行为与 模块选项之间的依赖关系 中相同。- 一起需要:
如果指定了
options
,则required_together
指的是options
中描述的子选项,其行为与 模块选项之间的依赖关系 中相同。- 其中之一需要:
如果指定了
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'),
],
)
- 互斥:
必须是字符串序列(列表或元组)的序列。每个字符串序列都是选项名称的列表,它们是互斥的。如果同时指定了一个列表中的多个选项,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=[ ('file_path', 'file_hash'), ],
在这个例子中,如果指定了选项
file_path
或file_hash
中的一个,如果另一个选项未指定,Ansible 将会以错误的形式结束模块。- 其中之一需要:
必须是字符串序列(列表或元组)的序列。每个字符串序列都是选项名称的列表,其中必须指定至少一个。如果没有指定这些选项中的任何一个,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)