Table of Contents
Go from Ansible beginner to Ansible pro with this full video course.
I’m aware of two ways to include variables from another file in Ansible:
- The
include_vars
module (works in any list of tasks, such as a playbook or role) - The
vars_files
keyword (works on plays only)
There are a number of reasons you might want to move variables into separate files when using Ansible:
- Refactoring - group long lists of variables together into smaller files
- Conditionally include variables - you may wish to load different variables based on host-specific properties or in response to tasks
I have included the most common use cases I can think of for include_vars
and vars_files
in the sections below.
How to use include_vars
The include_vars
module can be used in a playbook or role to load variables from a file. Simply set the value of include_vars
to a local file to load the variables it contains:
---
# ./hello_world.yml
- name: print greeting
hosts: "*"
tasks:
- include_vars: name_vars.yml
- debug: msg="Hello, {{ name }}!"
name_vars.yml
can be located in the same directory as hello_world.yml
, or inside ./vars/
(I prefer to put variable files into ./vars/
). The ./vars/name_vars.yml
file looks like this:
---
# ./vars/name_vars.yml
name: World
The playbook above will produce the following output:
ok: [123.123.123.123] => {
"msg": "Hello, World!"
}
Be careful: any variables you set with set_fact
will not be overwritten with include_vars
due to the variable precedence of different sources in Ansible.
For example, if you change the tasks file from above to be like this:
---
# ./hello_world.yml
- name: print greeting
hosts: "*"
tasks:
- set_fact: name=Percy
- include_vars: name_vars.yml
- debug: msg="Hello, {{ name }}!"
Despite having include_vars
after set_fact
, the output will look like this:
ok: [123.123.123.123] => {
"msg": "Hello, Percy!"
}
How to include variables conditionally
You can conditionally include variables by using the when
keyword.
Similar to the example above, you can include variable files based on the OS family of the remote host:
---
# ./redis.yml
- name: print redis package
hosts: "*"
tasks:
- include_vars: vars-Debian.yml
when: ansible_os_family == 'Debian'
- include_vars: vars-RedHat.yml
when: ansible_os_family == 'RedHat'
- debug: var=redis_package
Where the variable files look like this:
---
# ./vars/vars-Debian.yml
redis_package: redis-server
---
# ./vars/vars-RedHat.yml
redis_package: redis
The debug task from above will print the following:
ok: [centos_7] => {
"redis_package": "redis"
}
ok: [ubuntu_bionic_1804] => {
"redis_package": "redis-server"
}
How to include variables with a dynamic file name
You can make the previous example more terse by calling include_vars
with a dynamic filename based on the ansible_os_family
variable:
- include_vars: "vars-{{ ansible_os_family }}.yml"
- debug: var=redis_package
These tasks will behave in the same way as the previous example:
ok: [centos_7] => {
"redis_package": "redis"
}
ok: [ubuntu_bionic_1804] => {
"redis_package": "redis-server"
}
How to include variables from an Ansible vault file
Including variables from an Ansible Vault file works the same way as including a regular plaintext vars file. A common pattern I use in my playbooks is something like this:
---
# ./configure_app_servers.yml
- name: configure app servers
hosts: app_servers
pre_tasks:
- name: include env vars
include_vars: "{{ env }}.yml"
tags: ["always"]
- name: include vault for env
include_vars: "{{ env }}.vault.yml"
tags: ["always"]
roles:
...
As you can see in the example above, the regular vars file and the vault file are included in the same way with include_vars
. Ansible will automatically detect whether or not the file is an Ansible Vault file and decrypt it accordingly. This same functionality can also be achieved using vars_files
on the play, please see the following sections to see how this is done.
You can set env
by passing the --extra-vars
option to ansible-playbook
:
$ ansible-playbook configure_app_servers.yml --extra-vars "env=prod"
You can set env
to one of dev
, staging
, prod
etc. For the prod
env, you could have variable like this:
---
# ./vars/prod.yml
domain: example.com
rails_env: production
https: true
The prod.vault.yml
would look like this in plain text:
$ANSIBLE_VAULT;1.1;AES256
3462353065386462383165626...
...
But would print this when viewed with ansible-vault view ./vars/prod.vault.yml
:
---
# ./vars/prod.vault.yml
database_password: "94BqEabtebgzbQItkqPEVMyqjKbp57Gc"
api_key: "xVQKRARKgcwDktPCJjYRFiqmHGsvNFd9"
How to include variables for each item in a loop
The example from the previous section could be more terse if you used a loop with include_vars
rather than a two separate tasks:
---
# ./configure_app_servers.yml
- name: configure app servers
hosts: app_servers
pre_tasks:
- name: include vars and vault for env
include_vars: "{{ item }}.yml"
tags: ["always"]
loop:
- "{{ env }}"
- "{{ env }}.vault"
roles:
...
For env: prod
, the loop above would include variables from prod.yml
as well as prod.vault.yml
just like in the previous section.
How to include variables using vars_files
on a play
You could further improve the example above by using the vars_files
keyword on the play. Note that you need to prepend ./vars/
to the file path when using the vars_file
keyword:
---
# ./configure_app_servers.yml
- name: configure app servers
hosts: app_servers
vars_files:
- "./vars/{{ env }}.yml"
- "./vars/{{ env }}.vault.yml"
roles:
...
This is an efficient and readable way to include variables in a play.
Do you have any other use cases or examples that I didn’t cover? Hit me up in the comments and let’s discuss! 😃