When working with Ansible inventories where a single host belongs to multiple groups with conflicting group variables, you might encounter unexpected behavior in variable precedence. The specific case involves:
[group1]
host1.mydomain
[maingroup:children]
group1
[group2]
host1.mydomain
Ansible loads group variables in a specific order, and subsequent runs may cache these values, leading to inconsistent behavior:
- First run: Correctly loads
/service1/path
for maingroup - Second run: Correctly loads
/service2/path
for group2 - Subsequent runs: May incorrectly persist the group2 value
Instead of relying solely on group_vars, explicitly load variables in your playbook:
- name: Load service-specific variables
include_vars: "{{ 'group_vars/' + group_names | first }}.yml"
when: group_names | length == 1
Consider using host variables for service-specific configurations:
host_vars/host1.mydomain.yml:
---
services:
group1:
path: /service1/path
group2:
path: /service2/path
Then reference them in tasks:
- name: Use correct service path
debug:
msg: "Using path {{ services[group_names | first].path }}"
To prevent variable caching issues:
ansible.cfg:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 0
- Avoid duplicate host declarations when possible
- Use distinct variable names for different services
- Consider service-specific inventory files
- Implement clear naming conventions (service1_path, service2_path)
In complex Ansible environments, we often need to declare the same host in multiple inventory groups to manage different services. Consider this inventory structure:
[group1]
host1.mydomain
[maingroup:children]
group1
[group2]
host1.mydomain
With corresponding group variables:
# group_vars/maingroup
---
servicepath: /service1/path
# group_vars/group2
---
servicepath: /service2/path
When running playbooks sequentially:
- First execution with
hosts: maingroup
correctly uses/service1/path
- Second execution with
hosts: group2
correctly uses/service2/path
- Subsequent runs with
maingroup
incorrectly inherit/service2/path
This behavior stems from Ansible's variable caching mechanism. When host1.mydomain first appears in group2, Ansible caches its variables and subsequent inventory parsing doesn't properly reset them for maingroup context.
Solution 1: Use distinct variable names
# group_vars/maingroup
---
service1_path: /service1/path
# group_vars/group2
---
service2_path: /service2/path
Solution 2: Leverage group priorities
# inventory file
[group1]
host1.mydomain
[maingroup:children]
group1
[group2]
host1.mydomain ansible_group_priority=10
Solution 3: Use include_vars dynamically
- name: Load correct variables
include_vars:
file: "group_vars/{{ ansible_play_hosts_all[0] }}.yml"
when: ansible_play_hosts_all[0] in group_names
For complex multi-group scenarios, consider:
- Using host_vars for host-specific overrides
- Implementing custom facts via
set_fact
- Creating wrapper roles with explicit variable definitions
Always debug variable precedence with:
- debug:
msg: "{{ hostvars[inventory_hostname].servicepath }}"