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! 😃