include_tasks 和 import_tasks 有什么区别?

Ben*_*n S 99 ansible

在 Ansible 2.4 中,该include模块已弃用。取而代之的是,它附带了两个替换模块,import_tasks以及include_tasks. 但它们有非常相似的描述:

  • include_tasks:包含一个文件,其中包含要在当前剧本中执行的任务列表。
  • import_tasks:导入要添加到当前剧本以供后续执行的任务列表。

什么时候用前者,什么时候用后者?

Kon*_*rov 116

文档中有很多关于这个主题的内容:

主要区别在于:

所有import*语句都在解析 playbook 时进行预处理。
所有include*语句都按照它们在剧本执行期间遇到的方式进行处理。

所以import是静态的,include是动态的。

根据我的经验,您应该import在处理逻辑“单元”时使用。例如,将一长串任务分成子任务文件:

主文件:

- import_tasks: prepare_filesystem.yml
- import_tasks: install_prerequisites.yml
- import_tasks: install_application.yml
Run Code Online (Sandbox Code Playgroud)

但是您会习惯于include处理不同的工作流程并根据一些动态收集的事实做出决定:

安装先决条件:

- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml
Run Code Online (Sandbox Code Playgroud)

  • 我发现这个链接非常有用:http://docs.ansible.com/ansible/latest/playbooks_conditionals.html#applying-when-to-roles-imports-and-includes 它指出了导入和包含行为不同的情况 - 'when' 条件,其中文件中的任务可能会更改用于确定导入的标准。使用 import_tasks,每个任务都会检查条件,因此当条件改变时行为也会改变。使用 include_tasks,任务是否存在取决于在执行 include_tasks 语句时条件是否被评估为真。如果我理解得好... (10认同)

x-y*_*uri 36

导入是静态的,包含是动态的。导入发生在解析时,包括在运行时。

导入基本上用文件中的任务替换任务。运行时没有导入任务。因此,像tags, 和when(很可能是其余的)这样的属性被复制到每个导入的任务中。

包括确实被执行了。tagswhen包含的任务仅适用于任务本身。

如果导入任务未标记,则会执行来自导入文件的标记任务。如果包含任务未标记,则不会从包含文件执行任何任务。

如果导入任务被标记,则导入文件中的所有任务都会被执行。如果包含任务被标记,则只有包含文件中的标记任务才会被执行。

进口限制:

  • 不能与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
Run Code Online (Sandbox Code Playgroud)

debug不执行,因为它继承whenimport_tasks任务。因此,不会更改导入任务when属性中使用的变量的导入任务文件。

我有一个从导入开始的策略,但是一旦我需要一个包含,我就确保包含的文件或其子文件没有导入任何内容。但这很难维持。现在还不清楚它是否会保护我免受麻烦。我的意思是,不建议混合包含和导入。

我不能只使用导入,因为我偶尔需要循环。我可能可以切换到只包含。但我决定在任何地方都切换到导入,除非我需要循环。我决定亲身体验所有那些棘手的边缘情况。也许我的剧本中不会有任何内容。或者希望我能找到一种方法让它发挥作用。

UPD创建一个可以多次导入但只执行一次的任务文件的可能有用的技巧:

- name: ...
  ...
  when: not _file_executed | default(False)

- name: ...
  ...
  when: not _file_executed | default(False)

...

- name: Set _file_executed
  set_fact:
    _file_executed: True
Run Code Online (Sandbox Code Playgroud)

UPD混合包含和导入的真正预期效果是包含任务的变量覆盖导入任务的变量:

playbook.yml

- hosts: all
  tasks:
    - import_tasks: 2.yml
      vars:
        v1: 1
    - include_tasks: 2.yml
      vars:
        v1: 1
Run Code Online (Sandbox Code Playgroud)

2.yml

- import_tasks: 3.yml
  vars:
    v1: 2
Run Code Online (Sandbox Code Playgroud)

3.yml

- debug:
    var: v1    # 2 then 1
Run Code Online (Sandbox Code Playgroud)

可能是因为include_tasks首先导入文件,然后应用其vars指令。

实际上,它也可以像这样重现:

playbook.yml

- hosts: all
  tasks:
    - import_tasks: 2.yml
      vars:
        v1: 1
    - include_tasks: 2.yml
      vars:
        v1: 1
Run Code Online (Sandbox Code Playgroud)

2.yml

- debug:
    var: v1    # 2 then 1
  vars:
    v1: 2
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

2.yml

- import_tasks: 3.yml
  when: https
Run Code Online (Sandbox Code Playgroud)

3.yml

- import_tasks: 4.yml
  vars:
    https: no  # here we're trying to temporarily override the https var
- import_tasks: 4.yml
Run Code Online (Sandbox Code Playgroud)

4.yml

- debug:
    var: https
Run Code Online (Sandbox Code Playgroud)

我们得到trueand true,参见前一种情况(include_tasks'vars 优先于import_tasks''s)。为了避免这种情况,我们可以切换到包含在3.yml. 但是第一个包含在3.yml被跳过。由于它继承when: https自父任务,所以第一个任务基本上是这样写的:

- import_tasks: 4.yml
  vars:
    https: no  # here we're trying to temporarily override the https var
  when: https
Run Code Online (Sandbox Code Playgroud)

解决方案是也切换到包含2.yml。这可以防止传播when: https到子任务。

  • 很好的答案!。我对互联网上的每个人只是重复文档所说的内容感到沮丧。谢谢你。 (12认同)