Answers:
文档中有很多关于此主题的内容:
主要区别在于:
import*在解析剧本时,所有语句都会进行预处理。
所有include*语句都按照在执行Playbook时遇到的方式进行处理。
所以import是静态的,include是动态的。
根据我的经验,import在处理逻辑“单位”时应该使用。例如,将一长串任务分成子任务文件:
main.yml:
- import_tasks: prepare_filesystem.yml
- import_tasks: install_prerequisites.yml
- import_tasks: install_application.yml
但是您将习惯于include处理不同的工作流程并根据一些动态收集的事实做出决策:
install_prerequisites:
- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml
include什么?如果我们使用include将import_tasks是等效的?
include具有static: yes(的行为类似import_tasks)和static: no(如include_tasks)。
static什么?
static是None默认:因为Ansible 2.0,任务包括是动态的,更像真正的任务。这意味着可以循环,跳过它们并使用任何来源的变量。Ansible尝试自动检测到此问题,但是您可以使用static指令(在Ansible 2.1中添加了该指令)绕过自动检测。
导入是静态的,包含是动态的。导入在解析时进行,包括在运行时。
导入基本上将任务替换为文件中的任务。import_task在运行时没有。因此,诸如tags和和when(以及最可能的其他属性)之类的属性被复制到每个导入的任务中。
include确实已执行。tags并且when包含的任务仅适用于任务本身。
如果import任务是未标记的,则将执行导入文件中标记的任务。如果include任务未加标签,则不会从包含的文件中执行任何任务。
如果import标记了任务,则将执行导入文件中的所有任务。如果标记了任务,则仅执行包含文件中的标记任务include。
imports的局限性:
with_*或loop属性一起使用includes的局限性:
--list-tags 不显示包含文件中的标签--list-tasks 不显示包含文件中的任务notify用来触发来自动态包含内部的处理程序名称--start-at-task用来开始执行动态包含中的任务对我来说,基本上可以归结为imports不能与循环属性一起使用的事实。
import肯定会失败,在这样的情况下这样:
# playbook.yml
- import_tasks: set-x.yml
when: x is not defined
# set-x.yml
- set_fact
x: foo
- debug:
var: x
debug不执行,因为它when从import_tasks任务继承。因此,没有导入任务文件会更改import的when属性中使用的变量。
我有一个以imports 开头的策略,但是一旦需要,请include确保该包含的文件或包含的文件未导入任何内容。但这很难维护。目前尚不清楚是否能保护我免受麻烦。含义是,将includes和imports 混合使用,而不推荐使用。
我不能只使用imports,因为我偶尔需要循环include执行任务。我可能只能切换到includes。但是我决定在所有地方都改用导入,除了应该多次执行该任务的情况。我决定亲自体验所有这些棘手的情况。也许我的剧本中没有任何内容。或希望我能找到一种使之起作用的方法。
UPD创建任务文件可以多次导入但执行一次的可能有用的技巧:
- name: ...
...
when: not _file_executed | default(False)
- name: ...
...
when: not _file_executed | default(False)
...
- name: Set _file_executed
set_fact:
_file_executed: True
UPD混合包含和导入的一个并非真正预期的效果是,包含vars覆盖了导入变量:
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:
# here you're bound to use include, some sort of 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 https var
- import_tasks: 4.yml
4.yml:
- debug:
var: https
我们得到true和true,参见前面的情况(include vars优先于import vars)。因此,我们切换到include in 3.yml。但是随后将3.yml跳过第一个包含。由于它是when: https从父任务继承而来的,因此后者应该https从任务的继承vars。解决方案是也切换到包含2.yml。这样可以防止传播when: https到子任务。