In Ansible, variable precedence follows a strict hierarchy where some sources override others. When dealing with connection parameters like ansible_connection
, it's crucial to understand how playbook variables interact with host-specific definitions.
In your scenario, we have two competing definitions:
# Playbook definition
vars:
ansible_connection: aws_ssm
# Host_vars/server1.yml
ansible_connection: local
According to Ansible's variable precedence rules, host_vars (at precedence level 13) actually override playbook variables defined in the vars
section (level 8). This means your host_vars definition should naturally take precedence.
To confirm which value is being used, you can add this debug task to your playbook:
- hosts: it_servers
vars:
ansible_connection: aws_ssm
tasks:
- name: Display actual connection method
debug:
var: ansible_connection
roles:
- nginx
- mysql
If the output shows local
for server1, then the host_vars are working as expected. If not, there might be other factors at play.
Several scenarios could prevent host_vars from overriding playbook vars:
- The host_vars file is in the wrong location (should be in
host_vars/server1.yml
relative to your playbook or inventory) - The filename doesn't match the hostname exactly
- There's another variable source with higher precedence (like
--extra-vars
in your command)
If you need more control, consider these patterns:
1. Using Inventory Variables
[it_servers]
server1 ansible_connection=local
server2
server3
2. Group Variables with Overrides
# group_vars/it_servers.yml
ansible_connection: aws_ssm
# host_vars/server1.yml
ansible_connection: local
3. Conditional Logic in Playbook
- hosts: it_servers
vars:
ansible_connection: "{{ 'local' if inventory_hostname == 'server1' else 'aws_ssm' }}"
roles:
- nginx
- mysql
When managing connection methods:
- Document overrides clearly in your project README
- Use consistent naming patterns for special-case hosts
- Consider creating a separate inventory file for local development hosts
- Test connection methods with
ansible -m ping
before running full playbooks
When working with Ansible, you might encounter situations where a variable is defined in multiple places, and you need to understand which definition takes precedence. In this case, we're dealing with a playbook that defines ansible_connection: aws_ssm
for the it_servers
group, but we want server1
to use ansible_connection: local
through host_vars.
Ansible's variable precedence follows this order (higher overrides lower):
1. Extra vars (-e in CLI)
2. Task vars (only for the task)
3. Block vars (only for tasks in block)
4. Role and include vars
5. Play vars
6. Play vars_prompt
7. Play vars_files
8. Host facts
9. Host vars from inventory file
10. Host vars from host_vars/
11. Group vars from inventory file
12. Group vars from group_vars/
13. Playbook group_vars/
14. Playbook host_vars/
15. Inventory variables
16. Facts discovered about a host system
17. Role "default" vars
In our scenario, host_vars (priority 10) actually have higher precedence than play vars (priority 5), so your host_vars/server1.yml
should naturally override the playbook definition. However, if this isn't happening, there might be other factors at play.
To debug, run this command to see the actual value being used:
ansible server1 -m debug -a "var=ansible_connection"
If host_vars isn't working as expected, consider these alternatives:
1. Using --extra-vars
Override at runtime with highest precedence:
ansible-playbook playbook.yml --extra-vars "ansible_connection=local" --limit server1
2. Using Inventory Variables
Add the connection parameter directly in your inventory:
[it_servers]
server1 ansible_connection=local
server2 ansible_host=192.168.1.2
3. Using Group Variables with Exceptions
Create a special group for servers needing local connection:
# inventory.yml
all:
children:
it_servers:
hosts:
server1:
ansible_connection: local
server2:
local_servers:
hosts:
server1:
To understand why your host_vars aren't working:
# Check effective variables
ansible-inventory --list -i inventory.yml
# Verify host_vars are being loaded
ansible-config dump | grep DEFAULT_HOST_VARS_PATH
For connection parameters specifically:
- Consider using inventory variables rather than playbook vars
- Document connection methods clearly in your inventory
- For complex setups, create separate groups for different connection types
Here's how we might structure this in a production environment:
# inventory.yml
all:
children:
aws_ssm_servers:
vars:
ansible_connection: aws_ssm
hosts:
server2:
server3:
local_servers:
vars:
ansible_connection: local
hosts:
server1:
# playbook.yml
- hosts: aws_ssm_servers:local_servers
tasks:
- name: Show connection method
debug:
msg: "Using {{ ansible_connection }} connection"