A host is in several groups. Two of them set max_connections. Ansible
does not warn, does not fail, and does not ask. It picks one, applies
it, and reports a successful run.
This lesson is the rule it uses. Every claim here was executed against
ansible-core 2.21.3 rather than read from documentation, because this
is exactly the kind of semantic that is easy to get plausibly wrong.
The rule
Three clauses, in order of decisiveness.
Host beats group. A variable set on the host wins over any group
the host belongs to.
Child beats parent. A variable set on a child group wins over the
same variable on its parent.
Same-level groups merge alphabetically, so the last group name in
alphabetical order wins — unless ansible_group_priority says
otherwise, in which case the higher priority wins.
Read-only / Safenested groups disagreeing— Real output from ansible-core 2.21.3. The deeper group wins, which is consistent with the general principle that the more specific definition takes precedence.
Read-only / Safetwo unrelated groups, same variable— Real output from ansible-core 2.21.3. `zulu` wins because z sorts after a. Nothing about the two groups makes zulu more authoritative; the alphabet decided.
Rename zulu to backup and the answer becomes 100, with no other
edit. That is the whole problem in one sentence.
ansible_group_priority
The documented override. Set it on a group and that group’s variables
win against same-level siblings regardless of name. Higher wins;
the default is 1.
Read-only / Safethe same inventory, with a priority on alpha— Real output from ansible-core 2.21.3. The only change from the previous example is ansible_group_priority: 10 on alpha, and the answer flips from 400 to 100.
ansible_group_priority works. Use it when you need it. But reaching
for it should feel like a warning rather than a solution, and here is
why.
It encodes the decision in the wrong place. The reason alpha wins
is now a number in a variable block, not a structure a reviewer can see.
Reading the inventory no longer tells you which value a host gets.
It is invisible in a diff that adds a group. Somebody adds a third
group setting the same variable. The priority does not mention it,
because priorities are per-group rather than per-variable, and the new
group joins the alphabetical scramble with whatever number it happens to
have.
Relying on alphabetical merge order is not a design, it is a
coincidence. It works, and it continues working until someone renames
a group, which is an operation nobody expects to change behaviour.
The better move is almost always to make the conflict impossible.
Detecting conflicts before they matter
The resolved output shows the winner, not the argument. --host will
tell you max_connections is 400 and will never tell you that something
else wanted 100.
So detection is a two-step: find hosts in more than one group that could
disagree, then check what each of those groups defines.
Read-only / Safestep 1 - which groups is this host actually in?— Prints the host group memberships. debug runs on the controller, so nothing is connected to. Any host in two role groups or two environment groups is a conflict candidate.
ansible -i inventory/hosts.yml web01.example.com \
-m debug -a 'var=group_names' --connection=local
Read-only / Safestep 2 - who else defines this variable?— Searches the repository for every definition. The resolved inventory cannot tell you this, because by the time it renders the losing value has been discarded.
Read-only / Safestep 3 - catch it in CI, before review— Renders the whole inventory and reports any host in more than one group from the same family. Runs against files only; a suitable check for a pull request pipeline.
ansible-inventory -i inventory --list \
| python3 -c '
import json, sys
inv = json.load(sys.stdin)
envs = ["production", "staging", "development"]
members = {e: set(inv.get(e, {}).get("hosts", [])) for e in envs}
for a in envs:
for b in envs:
if a < b:
both = members[a] & members[b]
if both:
print(f"CONFLICT {a} and {b}: {sorted(both)}")
'
A check like that belongs in the pipeline rather than in a runbook. A
host in two environment groups is a repository-level bug — it is wrong
in the file, before anything runs — and the right time to catch it is
when the file changes.
Knowledge check
Knowledge check · 4 questions
Q1. Groups `alpha` and `zulu` are both direct children of `all`, both contain web01, and both set `max_connections` - alpha to 100, zulu to 400. What does web01 get?
Q2. `ansible_group_priority` cannot make a parent group override its own child.
Q3. Why does this course treat `ansible_group_priority` as a warning sign rather than a solution? Select all that apply.
Q4. A host is in both `patch_now` and `no_patch`. What is the right way to think about this?
Passing score: 75%. Answers are checked in this browser.