Recursive variable templating

I have quite a huge inventory (actually, multiple inventory files) and some of the nodes have much more variables than others, default values is used for any missed variable, it works pretty fine if I have only one thread like β€œvariable defined/not defined”, in that case I just can use filter plug-in default.

I.e. I have variable timezone that can be missed, I just can use {{ timezone|default('UTC') }}, and it works perfectly.

But I going to have a more complex scenario where the default value of the variable depends by some other parameter, like:
inventory/hosts:

[servers]
localhost

[servers:vars]
timezone="Europe/Kyiv"
network="Lviv"

inventory/group_vars/all:

defaulttimezone: "{% if network == 'Athlone' %}Europe/Dublin{% else %}UTC{% endif %}"
desiredtimezone: "{{ timezone|default(defaulttimezone) }}"
timezone: "{{ desiredzone }}"

The idea here is that I should have timezone for all of my hosts, and for one region (network) I have one default value and for another - another. All of them can be overridden by timezone in the inventory of a particular host. Group vars have higher priority than inventory, so, here I should have the final variable.

Unfortunately, it doesn’t work in that way, please find below, test playbook (playbooks/playbook.yaml):

---
- hosts: localhost
  gather_facts: no
  tasks:
  - ansible.builtin.debug:
      var: timezone

and finally:

root@947fc5508048:/opt# ansible-playbook -i inventory/hosts playbooks/playbook.yaml 

PLAY [localhost] ********************************************************************************************************************

TASK [ansible.builtin.debug] ********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ desiredtimezone }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: An unhandled exception occurred while templating '{{ timezone|default(defaulttimezone) }}'. Error was a <class 'ansible.errors.AnsibleError'>, original message: recursive loop detected in template string: {{ timezone|default(defaulttimezone) }}. maximum recursion depth exceeded"}

PLAY RECAP **************************************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

root@947fc5508048:/opt# 

It’s due to recursion doesn’t work. What solution can I have besides just using the different variable names in the inventory file? I prefer to keep timezone in inventory as is easy for humans to read, write, and understand.

It’s tested with ansible-core==2.16.9, but seems that 2.16.10 and 2.17.3 and current development version will end up with the same recursion error.

root@947fc5508048:/opt# ansible --version
ansible [core 2.16.9]
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.12/site-packages/ansible
  ansible collection location = /root/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.12.4 (main, Jun 27 2024, 00:07:37) [GCC 12.2.0] (/usr/local/bin/python)
  jinja version = 3.1.4
  libyaml = True
root@947fc5508048:/opt# 

Any suggestion?

You have a typo in your example i think. timezone: "{{ desiredzone }}" should be timezone: "{{ desiredtimezone }}" right?

Maybe obvious, but the recursion is happening because evaluating timezone means evaluation desiredtimezone, which means evaluating timezone…

You could try this:

#inventory/group_vars/all
defaulttimezone: "{% if network == 'Athlone' %}Europe/Dublin{% else %}UTC{% endif %}"

# playbook.yml
---
- hosts: localhost
  tasks:
    - name: Set TImezone
      set_fact:
        timezone: "{{ defaulttimezone }}"
      when: timezone is not defined

Alternatively:

#inventory/group_vars/all
network_to_timezone_map:
  Athlone: Europe/Dublin
  default: UTC

timezone: "{{ network_to_timezone_map[network] | default(network_to_timezone_map['default']) }}"

# playbook.yml
---
- hosts: localhost
  tasks:
    - debug:
        var: timezone

In both cases, timezone can be overridden with a command line var ansible-playbook -e 'timezone=foo', in host_vars, or by settings a group_var besides all

both will work, but it require a changes in playbooks (I have a huge old codebase), and it’s can’t be overridden by inventory file (inventory have lower priority than group vars)

hmmm ok. i do see i missed the stipulations in the original post, sorry about that. I dont think i see a solution without a change to the playook or variable names, hopefully someone else does

So why not move the group vars from the inventory hosts file to… group vars?

inventory/group_vars/all.yml

---
timezone: "{{ 'Europe/Dublin' if network == 'Athlone' else 'UTC' }}"

inventory/group_vars/servers.yml

timezone: 'Europe/Kyiv'

inventory/hosts

[servers]
localhost

#[servers:vars]
#timezone="Europe/Kyiv"
#network="Lviv"

playbook

---
- hosts: localhost
  gather_facts: no
  tasks:
  - ansible.builtin.debug:
      var: timezone

output

ansible-playbook -i ./inventory/hosts ./tmp.yml

PLAY [localhost] *********************************************************************************************************************************************************************************************

TASK [ansible.builtin.debug] *********************************************************************************************************************************************************************************
ok: [localhost] => {
    "timezone": "Europe/Kyiv"
}

PLAY RECAP ***************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Take advantage of variable precedence. If you place something in inventory/host_vars/{{inventory_hostname}}.yml, that will take precedence over the group vars (in case you have exceptions within any particular group).

1 Like

to @mikemorency 's note - shouldn’t this be timezone: "{{ desiredtimezone }}"

You can keep the same variable names (and remove the intermediate var desiredtimezone) by setting your default somewhere with less precedence than where you want to override it. In your example inventory, you are using inventory group vars (#3 Using Variables β€” Ansible Community Documentation), so the only way to set the default timezone with less priority is using role defaults:

.
β”œβ”€β”€ inventory
β”‚   β”œβ”€β”€ hosts
β”‚   β”‚   [all]
β”‚   β”‚   h0
β”‚   β”‚   [servers]
β”‚   β”‚   h1
β”‚   β”‚   [servers:vars]
β”‚   β”‚   timezone="Europe/Kyiv"
β”‚   β”‚   network="Lviv"
β”œβ”€β”€ roles
β”‚   β”œβ”€β”€ default_vars
β”‚   β”‚   β”œβ”€β”€ defaults
β”‚   β”‚   β”‚   β”œβ”€β”€ main.yml
β”‚   β”‚   β”‚   β”‚   defaulttimezone: "{% if network is defined and network == 'Athlone' %}Europe/Dublin{% else %}UTC{% endif %}"
β”‚   β”‚   β”‚   β”‚   timezone: "{{ defaulttimezone }}"
β”œβ”€β”€ playbook.yml
β”‚   ---
β”‚   - hosts: h0,h1
β”‚     gather_facts: no
β”‚     roles:
β”‚       - default_vars
β”‚     tasks:
β”‚     - ansible.builtin.debug:
β”‚         var: timezone

You could also switch to using host vars in your inventory file (#8 in Using Variables β€” Ansible Community Documentation), like this:

.
β”œβ”€β”€ inventory
β”‚   β”œβ”€β”€ group_vars
β”‚   β”‚   β”œβ”€β”€ all
β”‚   β”‚   β”‚   defaulttimezone: "{% if network is defined and network == 'Athlone' %}Europe/Dublin{% else %}UTC{% endif %}"
β”‚   β”‚   β”‚   timezone: "{{ defaulttimezone }}"
β”‚   β”œβ”€β”€ hosts
β”‚   β”‚   [all]
β”‚   β”‚   h0
β”‚   β”‚   [servers]
β”‚   β”‚   h1 timezone="Europe/Kyiv" network="Lviv"
β”œβ”€β”€ playbook.yml
β”‚   ---
β”‚   - hosts: h0,h1
β”‚     gather_facts: no
β”‚     tasks:
β”‚     - ansible.builtin.debug:
β”‚         var: timezone