We are in the process of upgrading from Ansible 2.18 to 2.20 and are aware that there were some significant changes to templating in 2.19.
What would be the best practice for handling “undefined” variables in templates in Ansible 2.19+? For example, we have a bunch of global variables defined in our group_vars/all.yml, one of them is:
backup dictionaries are defined in each of the inventories’ group_vars/all.yml and restic_repository was being lazily evaluated when needed in Ansible 2.18.
However, we have a play that references another global variable earlier in the run, so I guess the whole global group_vars/all.yml is loaded and evaluated in 2.19, and we get an error in that play:
FAILED! => {"changed": false, "msg": "Task failed: 'backup' is undefined"}
What would be considered best practice here? use default() in the template? Define a dummy backup dictionary in the global group_var/all.yml?
Variable templating is lazier in 2.19 than 2.18, and a task that uses one variable in group_vars/all.yml does not result in templating unrelated variables in group_vars/all.yml. Can you provide more context, like the full error (which shows the origin of the undefined variable) and failing task + surrounding context that previously succeeded in 2.18?
elastic_prefix and elastic_host_certificates_path are local variables, but elastic_host_certificates_path references a global variable set in global_vars/all.yml.
The full error text is:
[ERROR]: Task failed: 'backup' is undefined
Task failed.
Origin: <path>/roles/elasticsearch/tasks/elastic_instance.yml:50:7
48 path: "{{ elastic_host_certificates_path }}/{{ elastic_ca_cert_filename }}"
49 register: elastic_ca_cert_stat
50 - name: "[{{ elastic_prefix }}] Stat node cert files"
^ column 7
<<< caused by >>>
'backup' is undefined
Origin: <path>/group_vars/all.yml:128:31
126 --prune
127 # Restic backup bucket name is set in cluster's all.yml file.
128 restic_repository: "s3:s3.amazonaws.com/{{ backup.aws_bucket_name }}"
^ column 31
elastic_instance.yml is included (include_tasks) from role’s main.yml.
restic_repository variable is referenced in a later play and different role, it’s never used in the elasticsearch role.
This was run on Debian 13.3 WSL on Windows 10, in a Python 3.13.5 venv with the following pip packages installed:
Could you share more of group_vars/all.yml prior to the definition of restic_repository? It’s acting like that variable definition is being sucked up into something that comes before that.
If the backup definition from relevant group_vars wasn’t being pulled in (because of inventory differences?), then we still wouldn’t expect the error to be thrown in the elastic_instance.yml task file since it’s not used until later.
loop: "{{ groups['docker-swarm'] | map('extract', hostvars) | list }}"
I was able to reproduce, but need to do some more research. In earlier versions of ansible-core, undefined variables in hostvars were just the template string, which was a bug.