That's the part:
vars_files:
- vars/vars.default.yml
- vars/vars.yml
If a file vars/vars.yml
does not exist - here is an error.
ERROR: file could not read: /.../vars/vars.yml
How can I load additional variables from this file only if it exists? (with no errors)
It's quite simple really. You can squash your different vars_files items into a single tuple and Ansible will automatically go through each one until it finds a file that exists and load it. E.x.:
According to Ansible developers, the proper way to solve this is to use something like:
Furthermore, they say:
Note: The path tests (is file, is exists,...) work only with absolute paths or paths relative to the current working directory when running ansible-playbook command. This is the reason we used the lookup. the lookup accepts paths relative to the playbook directory and returns the absolute path when the file exists.
I encountered this problem in a setup where I needed to create multiple deployment environments (live, demo, sandbox) to the same physical server (not allowed virtual machines here), and then a script to deploy arbitrary svn repos
This required a directory tree of (optional) variable.yml files, that would merge ontop of each other and not throw an exception if any where missing
Start by enabling variable merging in ansible - note that this does shallow hash merging (1 level deep) and not fully recursive deep merge
ansible.cfg
Ansible directory layout
roles/deploy/tasks/includes.yml
This is the main logic for a directory tree of optional variable files.
group_vars/all.yml
Configure default variables for the project and various users and environments
roles/deploy/vars/main.yml
project defaults
roles/deploy/vars/project_1.yml
defaults for project_1
roles/deploy/vars/live/main.yml
defaults for live environment, overrides project defaults
roles/deploy/vars/live/project_1.yml
final overrides for project_1 in the live environment
playbooks/demo.yml
Configure separate playbooks for each environment
WARNING: Because all environments live on a single host, all playbooks must be run individually, otherwise Ansible will brokenly attempt to run all scripts as the first ssh login user and only use the variables for the first user. If you need to run all scripts sequentially, then use xargs to run them each as separate commands.
New answer based on the latest Ansible versions—basically, you should use
with_first_found
, along withskip: true
to skip the task if no file is found.This makes it so you don't have to have a fallback vars file in that list.
See related: https://stackoverflow.com/a/39544405/100134
Or in a more yaml way:
That is, instead of writing an array on one line with square brackets, like:
Use the yaml way of writing array values on multiple lines, like:
As mentioned this looks for a vars file named
{{ ansible_hostname }}.yml
, and if it doesn't exist usesdefault.yml
Piecing various pieces together... include_vars with a when clause that is true when the file exists. i.e.