Table of Contents
Go from Ansible beginner to Ansible pro with this full video course.
You can include playbooks inside other playbooks by using the import_playbook directive. There are a number of reasons you might want to move playbooks into separate files when using Ansible:
- Refactoring - chop up unfeasibly large playbooks to make the whole thing easier to read, or reduce repetition (DRY) by putting common plays into a file that can be imported by multiple playbooks
- Conditionally including playbooks - you may wish to have certain plays run conditionally based on some variable
How to import a playbook
Let’s say that there are some common roles that you would like to include across all your different server types. You could create a common_roles.yml playbook like this:
---
# ./common_roles.yml
- name: install common roles
hosts: "{{ server_type }}"
roles:
- users
- ntp
- python
- git
- aws-cli
And then include it in your other playbooks to reduce repetition and keep your playbooks DRY:
---
# ./web.yml
- import_playbook: common_roles.yml
- name: configure web servers
hosts: web
roles:
- nginx
- my_site
---
# ./database.yml
- import_playbook: common_roles.yml
- name: configure database servers
hosts: database
roles:
- postgres
If you ever need to add another common role, you just need to update a single playbook.
Note that I have set hosts: "{{ server_type }}" in the common_roles.yml playbook to limit the hosts that it runs against. For this to work you will need to set the server_type variable when calling ansible-playbook:
$ ansible-playbook web.yml --extra-vars "server_type=web"
$ ansible-playbook database.yml --extra-vars "server_type=database"
There are other ways to achieve this, but this is the best way I could think of. Another way would be to use the --limit option, but I think this is more fragile and less expressive.
How to import a playbook conditionally
Extending the example from above, let’s say that you have some roles that you would like to include only if the env is staging, such as some tools to help debug your live application. An example playbook might look like this:
---
# ./staging_roles.yml
- name: install roles for staging only
hosts: "{{ env }}_{{ server_type }}"
roles:
- debug-tools
You can then update your other playbooks to conditionally include the staging_roles.yml playbook using the when keyword:
---
# ./web.yml
- import_playbook: common_roles.yml
- import_playbook: staging_roles.yml
when: env == 'staging'
- name: configure web servers
hosts: "{{ env }}_web"
roles:
- nginx
- my_site
---
# ./database.yml
- import_playbook: common_roles.yml
- import_playbook: staging_roles.yml
when: env == 'staging'
- name: configure database servers
hosts: "{{ env }}_database"
roles:
- postgres
Note that I have included an env variable here to further limit the servers the playbooks run against and you would need to add this to your command line call:
$ ansible-playbook web.yml --extra-vars "env=staging server_type=web"
$ ansible-playbook database.yml --extra-vars "env=staging server_type=database"
How to import a playbook with dynamic filename
Further extending the examples from above, you could refactor your playbooks to an extreme level: create a master.yml and include your server-specific playbooks using import_playbook and the server_type variable:
---
# ./master.yml
- import_playbook: common_roles.yml
- import_playbook: staging_roles.yml
when: env == 'staging'
- import_playbook: "{{ server_type }}.yml"
You can modify the server-specific playbooks to contain only a single play each:
---
# ./web.yml
- name: configure web servers
hosts: "{{ env }}_web"
roles:
- nginx
- my_site
---
# ./database.yml
- name: configure database servers
hosts: "{{ env }}_database"
roles:
- postgres
Now you can configure both the web and database servers using the single master.yml playbook, using the env and server_type variables to specify which servers you would like to configure:
$ ansible-playbook master.yml --extra-vars "env=staging server_type=web"
$ ansible-playbook master.yml --extra-vars "env=staging server_type=database"
This is a pretty extreme example, but I think it demonstrates the power of Ansible when it comes to refactoring playbooks with import_playbook.
Do you have any other use cases or examples that I didn’t cover? Hit me up in the comments and let’s discuss! 😃

