В чем разница между include_tasks и import_tasks?

63

В Ansible 2.4 includeмодуль устарел. На его месте он поставляется с двумя сменными модулями import_tasksи include_tasks. Но у них очень похожие описания:

  • include_tasks: Включает файл со списком задач, которые должны быть выполнены в текущей пьесе.
  • import_tasks: Импортирует список задач, которые будут добавлены в текущую книгу воспроизведения для последующего выполнения.

Когда я должен использовать первое, и когда я должен использовать второе?

Бен С
источник
(Также: предупреждение об устаревании относится к «динамическим» и «статическим» задачам. Я прочитал документы, но не понял их.)
Бен С.

Ответы:

70

Немного об этой теме в документации:

Основным отличием является:

Все import*операторы предварительно обрабатываются во время анализа playbooks.
Все 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
Константин Суворов
источник
8
Я нашел эту ссылку очень полезной: docs.ansible.com/ansible/latest/… Вызывает случай, когда импорт и включение ведут себя по-разному - условие «когда», когда задачи в файле могут изменить критерии, используемые для определения импорта , С помощью import_tasks каждая задача проверяет критерии, поэтому поведение меняется при изменении критериев. С помощью include_tasks задачи либо присутствуют, либо не зависят от того, было ли условие оценено как истинное, когда выполнялся оператор include_tasks. Если я хорошо понимаю ...
Этель Эванс
Каково было поведение include? Если бы мы использовали, includeбыл import_tasksбы эквивалент?
Энди Шинн
includeимел static: yes(вел себя как import_tasks) и static: no(как include_tasks).
Константин Суворов
Для чего по умолчанию static?
Энди Шинн
staticэто Noneпо умолчанию: Так как анзибль 2.0, задача включает в себя динамические и вести себя как реальные задачи. Это означает, что они могут быть зациклены, пропущены и использовать переменные из любого источника. Ansible пытается автоматически обнаружить это, но вы можете использовать статическую директиву (которая была добавлена ​​в Ansible 2.1), чтобы обойти автоопределение.
Константин Суворов
17

Импорт статический, в том числе динамический. Импорт происходит во время синтаксического анализа, включает во время выполнения.

Импорт в основном заменяет задачу задачами из файла. Там нет 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«s whenатрибута.

У меня была политика для начала с imports, но как только мне нужно includeубедиться, что ничего не импортируется этим включенным файлом или файлами, которые он включает. Но это чертовски сложно поддерживать. И до сих пор не ясно, защитит ли это меня от неприятностей. То есть смешивать includeс и importс, которые они не рекомендуют.

Я не могу использовать только imports, так как мне иногда нужно циклически includeвыполнять задачи. Я мог бы, вероятно, переключиться только на includeс. Но я решил переключиться на импорт везде, кроме случаев, когда задача должна выполняться несколько раз. Я решил испытать все эти сложные случаи из первых рук. Может быть, не будет в моих пьесах. Или, надеюсь, я найду способ заставить это работать.

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 Один не совсем ожидаемый эффект от смешивания включает и импортирует то, что включает в себя переопределенные переменные импорта:

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, видим предыдущий случай (включающие переменные имеют приоритет над импортируемыми переменными). Таким образом, мы переключаемся на включает в 3.yml. Но затем первое включение в 3.ymlпропускается. Поскольку он наследуется when: httpsот родительской задачи, а последняя предположительно берет httpsот задачи vars. Решение состоит в том, чтобы переключиться на включения в 2.yml. Это предотвращает распространение when: httpsна дочерние задачи.

х-юри
источник
4
Отличный ответ! Я был разочарован тем, что все в интернете просто повторяют то, что написано в документации. Спасибо.
Серхио Акоста