Назад | Перейти на главную страницу

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

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

Когда мне следует использовать первое, а когда - второе?

В документации по этой теме довольно много:

Основное отличие:

Все 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 для работы с различными рабочими процессами и принятия решений на основе некоторых динамически собираемых фактов:

install_prerequisites:

- include_tasks: prerequisites_{{ ansible_os_family | lower }}.yml

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

Импорт в основном заменяет задачу задачами из файла. Во время выполнения нет задач импорта. Итак, такие атрибуты, как 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 не выполняется, поскольку наследует when из import_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

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'vars имеют приоритет над import_tasks'единицы). Чтобы избежать этого, мы можем переключиться на включение в 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

Решение - переключиться на включение в 2.yml также. Это предотвращает распространение when: https к дочерним задачам.