What is the difference between ansible_facts['hostname'] and ansible_hostname, and which should you use?
They hold the same fact. ansible_facts[...] is the namespaced form introduced in Ansible 2.5; ansible_* is the older form, where each fact was injected as a separate top-level variable. Use ansible_facts[...], because injected facts have very high precedence and can collide with your own variables.
* Inside ansible_facts a fact can't collide with your variables; injected ansible_* names can. *
ansible_facts.* name |
ansible_* name |
|---|---|
ansible_facts['hostname'] |
ansible_hostname |
ansible_facts['fqdn'] |
ansible_fqdn |
ansible_facts['default_ipv4']['address'] |
ansible_default_ipv4['address'] |
ansible_facts['interfaces'] |
ansible_interfaces |
ansible_facts['devices']['vda']['partitions']['vda1']['size'] |
ansible_devices['vda']['partitions']['vda1']['size'] |
ansible_facts['dns']['nameservers'] |
ansible_dns['nameservers'] |
ansible_facts['kernel'] |
ansible_kernel |
Inside ansible_facts, the ansible_ prefix is dropped from the key; the injected form keeps it.
Why the old form is discouraged: an injected fact has a very high precedence and overrides playbook, inventory host and group variables of the same name. A fact can therefore silently replace a value you set yourself. Inside the ansible_facts dictionary, facts can't collide with anything.
Both forms work today, because the setting inject_facts_as_vars in the [defaults] section of ansible.cfg defaults to true. Set it to false and only ansible_facts[...] works; ansible_hostname then raises an "undefined variable" error. Many older playbooks still use the injected names.
Go deeper:
INJECT_FACTS_AS_VARS (official config reference) — the setting, its default and the prefix rule.