This is one of the most frequest questions being asked in my workshop is that differences between using import or include in Ansible. For example import_role or include_role, what should be behaviour and what to expect?
We know that include could be applied to tasks, plays and handlers. The bare include task (which was used for both Task files and Playbook-level includes) is still available, however it is now considered deprecated and introduced with include_tasks, include_role and include_role.
With filename variable substitution, the code could become much more clean.
include: “{{ codename }}.yml”
We also know that include using(include and import) could be dynamic or static.
Differences Between Static and Dynamic
Ansible has two modes of operation for reusable content with Including and Importing and Roles: dynamic and static.
The main difference is:
All import* statements are pre-processed at the time playbooks are parsed.
All include* statements are processed as they encountered during the execution of the playbook.
So import is static, include is dynamic.
Background
In Ansible 2.0, the concept of dynamic includes was introduced. Due to some limitations with making all includes dynamic in this way, the ability to force includes to be static was introduced in Ansible 2.1.
Static import
If you use any import* Task (import_playbook, import_tasks, etc.), it will be static.
Dynamic Include
If you use any include* Task (include_tasks, include_role, etc.), it will be dynamic.
The two modes of operation are pretty simple:
- Ansible pre-processes all static imports during Playbook parsing time.
- Dynamic includes are processed during runtime at the point in which that task is encountered.
When it comes to Ansible task options like tags and conditional statements (when:):
- For static imports, the parent task options will be copied to all child tasks contained within the import.
- For dynamic includes, the task options will only apply to the dynamic task as it is evaluated, and will not be copied to child tasks.
The primary advantage of using include* statements is looping. When a loop is used with an include, the included tasks or role will be executed once for each item in the loop.
- import_tasks: x.yml
with_items: [1,2,3]
This willi import x.yml one time and every imported task will now run
and loop over 1,2,3
- include_tasks: x.yml
with_items: [1,2,3]
This will include x.yml 3 times and set the 'item' variable to 1, 2
and 3 respectively
In order to conclude this, Basically import tasks will be parsed at the beginning when you run the playbook, but include tasks will only be parsed at the moment Ansible hits them.
Means, with include Running the Playbook which has list of tasks will execute until the error tasks are found, which is in included file.
On other end, Wait, with import, it will flag a error to begin with only. The reason is because the import_role task is pre-processed at the time playbooks are parsed. So it found the syntax error much earlier and so it never was able to even run our first task with the debug module.
This is an example that really emphasizes the fact that import is parsed quite early. This is what is referred to as static.
Ansible include and import has following module which must be explored
import
import_playbook
import_role
import_tasks
include
include_vars
include_playbook
include_role
include_tasks
Reference
- import_playbook – Import a playbook
- import_role – Import a role into a play
- import_tasks – Import a task list
- Including and Importing
- import_playbook with play-level condition
- How to Import Playbooks in Ansible + Examples
- Ansible 101 – Include vs Import
- Best AI tools for Software Engineers - November 4, 2024
- Installing Jupyter: Get up and running on your computer - November 2, 2024
- An Introduction of SymOps by SymOps.com - October 30, 2024
The primary advantage of using include* statements is looping. When a loop is used with an include, the included tasks or role will be executed once for each item in the loop.
Can you provide an example playbook here?