В Ansible 2.4 include
модуль устарел. Вместо этого он поставляется с двумя заменяемыми модулями, import_tasks
и include_tasks
. Но у них очень похожие описания:
include_tasks
: Включает файл со списком задач, которые должны быть выполнены в текущей книге воспроизведения.import_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
к дочерним задачам.