There are a few different ways to invoke one or more roles in a playbook.
- roles
- import_playbook
- import_role
- include_role (this article)
- include_tasks
- import_tasks
AVOID TROUBLE
9 times out of 10, when I would run a playbook that had include_role, the playbook would run just fine with no issues. However, every now and then it would fail with something like this.
TASK [include_role 'foo' main.yml] ************************************
ERROR! Could not find specified file in role: tasks/main.yml
I think this is a defect with the include_role module as mentioned in this GitHub issue -> https://github.com/ansible/ansible/issues/22571. For this reason, I always instead use one of the other modules, usually import_role.
Let's say you have the following structure.
├── /usr/local
│ ├── main.yml
│ ├── roles
│ │ ├── foo
│ │ ├── ├── tasks
│ │ ├── ├── ├── main.yml
│ │ ├── bar
│ │ ├── ├── tasks
│ │ ├── ├── ├── main.yml
And the foo role creates the /tmp/foo.txt file and the bar role creates the /tmp/bar.txt file.
~]$ cat roles/foo/tasks/main.yml
- ansible.builtin.file:
path: /tmp/foo.txt
state: touch
~]$ cat roles/bar/tasks/main.yml
- ansible.builtin.file:
path: /tmp/bar.txt
state: touch
Here is a simple example of how roles "foo" and "bar" could be run using include_role. This assumes that the "foo" and "bar" roles are included in one of your roles search directories.
---
- hosts: localhost
tasks:
- name: include_role 'foo'
ansible.builtin.include_role:
name: foo
- name: include_role 'bar'
ansible.builtin.include_role:
name: bar
...
Let's say you are using when to do something like this.
---
- hosts: all
roles:
- role: foo
when: x is defined
- role: bar
when: y is defined
...
This is not ideal, as each task in the playbook that is not used will be skipped, making for a messy ansible.log that might have a bunch of "skipping" tasks.
TASK [/etc/ansible/roles/foo: foo test]
ok: [server1.example.com] => {
"msg": "Hello World"
}
TASK [/etc/ansible/roles/bar: bar test]
skipping: [server1.example.com]
Sometimes, it's better to use include_role.
---
- hosts: all
tasks:
- name: include_role 'foo' when x is defined
ansible.builtin.include_role:
name: foo
when: x is defined
- name: include_role 'bar' when y is defined
ansible.builtin.nclude_role:
name: bar
when: y is defined
...
Now, the role will be skipped without iterating through each task in the role.
TASK [/etc/ansible/roles/foo: foo test]
ok: [server1.example.com] => {
"msg": "Hello World"
}
tasks_from
By default, the tasks in the main.yml file in the role will be invoked. In this example, the tasks in roles/foo/tasks/main.yml would be run.
- name: include_role 'roles/foo/tasks/main.yml'
ansible.builtin.include_role:
name: foo
If you have other yaml files in the role tasks directory, such as roles/foo/tasks/bar.yml, the tasks_from parameter can be used to invoke the tasks in bar.yml.
- name: include_role 'roles/foo/tasks/bar.yml'
ansible.builtin.include_role:
name: foo
tasks_from: bar
Including variables (vars and vars_from)
By default, if there is a "vars" directory that contains a main.yml file in the same directory as the role, the variables in the vars main.yml file will be available in the tasks main.yml file.
roles/foo/tasks/main.yml
roles/foo/vars/main.yml
If you have other yaml files in the role vars directory, such as roles/foo/vars/bar.yml, the vars_from parameter can be used to include the variable in bar.yml.
---
- hosts: all
tasks:
- name: include the variables in roles/foo/vars/bar.yml
ansible.builtin.include_role:
name: foo
vars_from: bar
...
Or, variables can be define using vars.
---
- hosts: all
tasks:
- ansible.builtin.include_role:
name: foo
vars:
bar: Hello World
...
apply delegate_to
Here is how you can use delegate_to to run all of the tasks in the "foo" role on localhost. It almost always makes sense to also have run_once: true since you probably don't want to run the tasks on localhost more than once.
---
- hosts: all
tasks:
- ansible.builtin.include_role:
name: foo
apply:
delegate_to: localhost
run_once: true
...
Did you find this article helpful?
If so, consider buying me a coffee over at