Ansible has 2 methods that allows you to scale your playbooks by moving tasks to other files. Those methods are import and include. On the surface, the use of these is very similar if your playbook and tasks are simple. In-fact here is an example of using import and include interchangeably.
import_a_task.yaml
---
- name: import a task
hosts: localhost
gather_facts: false
tasks:
- name: import a task
import_tasks: subtask.yaml
include_a_task.yaml
---
- name: include a task
hosts: localhost
gather_facts: false
tasks:
- name: include a task
include_tasks: subtask.yaml
subtask.yaml
---
- name: Debug some stuff
debug:
msg: "This is a subtask"
The output of the two even looks very similar.
ansible-playbook import_a_task.yaml
PLAY [import a task] ***************************************************************************************************************************************************************************************************
TASK [debug] ***********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "This is a subtask"
}
PLAY RECAP *************************************************************************************************************************************************************************************************************localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You’ll notice the output is similar but the include task contains a few extra lines that show which task was included and ran.
ansible-playbook include_a_task.yaml
PLAY [include a task] **************************************************************************************************************************************************************************************************
TASK [include a task] **************************************************************************************************************************************************************************************************included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost
TASK [debug] ***********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "This is a subtask"
}
PLAY RECAP *************************************************************************************************************************************************************************************************************localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The difference between import and include become apparent when we look at using loops, tags, and conditionals. Let’s first look at how each behaves when we use loops. If we change our playbooks to the following we can see the behavior of each when there is a loop applied to the outermost task.
import_a_task.yaml
---
- name: import a task
hosts: localhost
gather_facts: false
tasks:
- name: import a task
import_tasks: subtask.yaml
loop:
- 123
- 456
- 789
include_a_task.yaml
---
- name: include a task
hosts: localhost
gather_facts: false
tasks:
- name: include a task
include_tasks: subtask.yaml
loop:
- 123
- 456
- 789
subtask.yaml
---
- name: Debug some stuff
debug:
msg: "{{ item }}"
Upon running the import_a_task.yaml and include_a_task.yaml we can see that the import_a_task.yaml fails to execute all together but the include_a_task.yaml includes and executes the subtask one time for each of the items in the list. The import_a_task even tells us that we cannot use loops on ‘import_tasks’ statements and that we should instead use ‘include_tasks’.
ansible-playbook import_a_task.yaml
ERROR! You cannot use loops on 'import_tasks' statements. You should use 'include_tasks' instead.
The error appears to be in '/mnt/c/Users/justin/lab-ansible/import_a_task.yaml': line 6, column 7, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: import a task
^ here
ansible-playbook include_a_task.yaml
PLAY [include a task] **************************************************************************************************************************************************************************************************
TASK [include a task] **************************************************************************************************************************************************************************************************included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=123)
included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=456)
included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=789)
TASK [debug] ***********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": 123
}
TASK [debug] ***********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": 456
}
TASK [debug] ***********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": 789
}
PLAY RECAP *************************************************************************************************************************************************************************************************************localhost : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
We can, use loops in the subtasks when using the import_tasks. This, however, can get cluncky if there are a large number of subtasks you wish to loop over the same list. Using the import_tasks function your playbooks would look something like this:
import_a_task.yaml
---
- name: import a task
hosts: localhost
gather_facts: false
tasks:
- name: import a task
import_tasks: subtask.yaml
subtask.yaml
---
- name: debug 1
debug:
msg: "Loop 1: {{ item }}"
loop:
- 123
- 456
- 789
- name: debug 2
debug:
msg: "Loop 2: {{ item }}"
loop:
- 123
- 456
- 789
When using include_tasks functionality you only have to define the loop one time in the outermost task.
include_a_task.yaml
---
- name: include a task
hosts: localhost
gather_facts: false
tasks:
- name: include a task
include_tasks: subtask.yaml
loop:
- 123
- 456
- 789
subtask.yaml
---
- name: debug 1
debug:
msg: "Loop 1: {{ item }}"
- name: debug 2
debug:
msg: "Loop 2: {{ item }}"
Another item worth noting is that when using the import_tasks – each subtask executes its entire loop before going to the next subtask. However, when using include_tasks – each item in the loop is run against all subtasks one-by-one before moving onto the next item in the loop. The difference can be seen in the output.
ansible-playbook import_a_task.yaml
ansible-playbook import_a_task.yaml
PLAY [import a task] ***************************************************************************************************************************************************************************************************
TASK [debug 1] *********************************************************************************************************************************************************************************************************ok: [localhost] => (item=123) => {
"msg": "Loop 1: 123"
}
ok: [localhost] => (item=456) => {
"msg": "Loop 1: 456"
}
ok: [localhost] => (item=789) => {
"msg": "Loop 1: 789"
}
TASK [debug 2] *********************************************************************************************************************************************************************************************************ok: [localhost] => (item=123) => {
"msg": "Loop 2: 123"
}
ok: [localhost] => (item=456) => {
"msg": "Loop 2: 456"
}
ok: [localhost] => (item=789) => {
"msg": "Loop 2: 789"
}
PLAY RECAP *************************************************************************************************************************************************************************************************************localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 \
ansible-playbook include_a_task.yaml
ansible-playbook include_a_task.yaml
PLAY [include a task] **************************************************************************************************************************************************************************************************
TASK [include a task] **************************************************************************************************************************************************************************************************included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=123)
included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=456)
included: /mnt/c/Users/justin/lab-ansible/subtask.yaml for localhost => (item=789)
TASK [debug 1] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 1: 123"
}
TASK [debug 2] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 2: 123"
}
TASK [debug 1] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 1: 456"
}
TASK [debug 2] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 2: 456"
}
TASK [debug 1] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 1: 789"
}
TASK [debug 2] *********************************************************************************************************************************************************************************************************ok: [localhost] => {
"msg": "Loop 2: 789"
}
PLAY RECAP *************************************************************************************************************************************************************************************************************localhost : ok=9 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
That covers the basics of loops and when and how they can be used in each circumstance. Next we can look at tags.
Worth mentioning as well is that tags function works different,
LikeLike