include模块已被弃用。取而代之的是两个替代模块:import_tasks和include_tasks。但它们的描述非常相似:
include_tasks:在当前playbook中包含一个任务列表文件以供执行。import_tasks:导入一个任务列表以添加到当前playbook中以供后续执行。
include模块已被弃用。取而代之的是两个替代模块:import_tasks和include_tasks。但它们的描述非常相似:
include_tasks:在当前playbook中包含一个任务列表文件以供执行。import_tasks:导入一个任务列表以添加到当前playbook中以供后续执行。文档中对这个主题有很多内容:
主要的区别是:
所有的
import*语句在解析playbook时进行预处理。
所有的include*语句在playbook执行过程中被逐个处理。
因此,import 是静态的,include 是动态的。
根据我的经验,在处理逻辑“单元”时,应该使用 import。例如,将长列表的任务拆分为子任务文件:
main.yml:
- import_tasks: prepare_filesystem.yml
- import_tasks: install_prerequisites.yml
- import_tasks: install_application.yml
但是你可以使用include来处理不同的工作流程,并根据一些动态收集到的事实做出决策:
安装先决条件:
- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml
include的行为是什么?如果我们使用include,import_tasks是否相当于它? - Andy Shinninclude有static: yes(像import_tasks一样)和static: no(像include_tasks一样)的行为。 - Konstantin Suvorovstatic 的默认值是什么? - Andy Shinnstatic 默认情况下是 None:自 Ansible 2.0 起,任务的包含是动态的,并且表现得更像真正的任务。这意味着它们可以被循环执行、跳过,并且可以使用来自任何来源的变量。Ansible 尝试自动检测这一点,但你可以使用静态指令(在 Ansible 2.1 中添加)来绕过自动检测。 - Konstantin Suvorovimport_tasks呢? - Felipe Alvarezimport_tasks,效果很好。 - Ben S导入是静态的,包含是动态的。导入发生在解析时,包含发生在运行时。
导入基本上用文件中的任务替换任务。运行时没有导入任务。因此,像tags和when(以及很可能其他属性)会被复制到每个导入的任务中。
包含确实会被执行。包含的任务的tags和when只适用于任务本身。
如果导入任务未标记,则导入文件中的带标记的任务将被执行。如果包含任务未标记,则不会执行包含文件中的任何任务。
如果导入任务被标记,则将执行导入文件中的所有任务。如果包含任务被标记,则只会执行包含文件中的带标记的任务。
导入的限制:
with_*或loop属性一起使用包含的限制:
--list-tags不显示来自包含文件的标签--list-tasks不显示来自包含文件的任务notify来触发来自动态包含文件的处理程序名称--start-at-task在动态包含文件中开始执行任务对我来说,这基本上归结为导入不能与loop属性一起使用。
导入在像这样的情况下肯定会失败:
# playbook.yml
- import_tasks: set-x.yml
when: x is not defined
# set-x.yml
- set_fact
x: foo
- debug:
var: x
debug不会被执行,因为它从import_tasks任务继承了when。所以,在导入任务文件中改变用于导入任务的when属性的变量时,不要导入任务文件。
我曾经有一个规则是从导入开始,但是一旦我需要一个包含(include),我确保被包含文件或其子文件中没有导入任何东西。但是这非常难以维护。而且目前还不清楚这是否会保护我免受麻烦。我的意思是,混合使用包含和导入是不推荐的。
我不能仅使用导入,因为偶尔我需要循环。我可能可以完全转换为仅使用包含。但是我决定在除了需要循环的情况下,到处都使用导入。我决定首先亲自体验所有那些棘手的边界情况。也许在我的剧本中不会有任何问题。或者希望我能找到一种让它工作的方法。
更新:一个可能有用的技巧是创建一个可以被多次导入但只执行一次的任务文件:
- name: ...
...
when: not _file_executed | default(False)
- name: ...
...
when: not _file_executed | default(False)
...
- name: Set _file_executed
set_fact:
_file_executed: True
UPD 混合使用 include 和 import 的一个意外效果是,include 任务的变量会覆盖导入任务的变量。
playbook.yml:
- hosts: all
tasks:
- import_tasks: 2.yml
vars:
v1: 1
- include_tasks: 2.yml
vars:
v1: 1
2.yml:
- import_tasks: 3.yml
vars:
v1: 2
3.yml:
- debug:
var: v1 # 2 then 1
еҸҜиғҪжҳҜеӣ дёә`include_tasks`йҰ–е…ҲеҜје…Ҙж–Үд»¶пјҢз„¶еҗҺеҶҚеә”з”Ёе…¶`vars`жҢҮд»ӨгҖӮ
е®һйҷ…дёҠпјҢд№ҹеҸҜд»Ҙиҝҷж ·еӨҚзҺ°пјҡ
playbook.yml:
- hosts: all
tasks:
- import_tasks: 2.yml
vars:
v1: 1
- include_tasks: 2.yml
vars:
v1: 1
2.yml:
- debug:
var: v1 # 2 then 1
vars:
v1: 2
UPD包含和导入混合的又一个案例。
playbook.yml:
- hosts: all
tasks:
# say, you're bound to use include here (because you need a loop)
- include_tasks: 2.yml
vars:
https: yes
2.yml:
- import_tasks: 3.yml
when: https
3.yml:
- import_tasks: 4.yml
vars:
https: no # here we're trying to temporarily override the https var
- import_tasks: 4.yml
4.yml:
- debug:
var: https
我们得到了true和true,参见前面的案例(include_tasks的变量优先于import_tasks的变量)。为了避免这种情况,我们可以在3.yml中切换到includes。但是然后3.yml中的第一个include被跳过了。由于它从父任务继承了when: https,所以第一个任务基本上是这样的:
- import_tasks: 4.yml
vars:
https: no # here we're trying to temporarily override the https var
when: https
解决方案是在2.yml中也切换到includes。这样可以防止when: https传播到子任务中。
include的文件或反之亦然被视为混用。只要你不这样做,就应该是安全的。 - x-yuri