Reputation: 385
I'm trying to pass a fact from host1 to host2, but when ansible reaches hosts2 it returns "undefined variable":
- name: some playbook
gather_facts: false
hosts: host1
tasks:
- set_fact:
fact1: "foo"
- hosts: host2
gather_facts: false
tasks:
- debug:
msg: "{{ fact1 }}"
Upvotes: 6
Views: 4672
Reputation: 31
TL;DR
Amazing answer by Gary Lopez.
Supplying a bit more information to whoever finds this useful:
Please note that in order to reference other hosts' variables, they need to be defined first.
This is so ansible can access the cache and actually access those variables, because they were collected (e.g. Gathering Facts task was run on hosts).
This information is displayed in the Ansible documentation here : https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_vars_facts.html#information-about-ansible-magic-variables
With hostvars, you can access variables defined for any host in the play, at any point in a playbook. You can access Ansible facts using the hostvars variable too, but only after you have gathered (or cached) facts
So, make sure to plan your playbooks with variable caching in mind, to allow them to be referenced later on, just like Gary Lopez wrote :
- name: First Playbook
gather_facts: no
hosts: host1
tasks:
- set_fact:
fact1: "foo"
- name: Second Playbook
hosts: host2
gather_facts: no
tasks:
- debug:
msg: "{{ hostvars['host1']['fact1'] }}"
It took me time to find and understand this information, probably due to language gap :)
Upvotes: 0
Reputation: 68254
In general, this use case might be solved in three steps. Create, share, and use the variables. For example, given the inventory
shell> cat hosts
host1
host2
the playbook works as expected
- name: Run single host and create facts
hosts: host1
tasks:
- set_fact:
fact1: foo
- name: Share facts among all hosts
hosts: all
tasks:
- set_fact:
fact1: "{{ hostvars.host1.fact1 }}"
run_once: true
- name: Use shared facts
hosts: host2
tasks:
- debug:
var: fact1
If you extend the use case to "passing facts from a group of hosts to another group of hosts" the problem is how to efficiently share the variables? Create a playbook dynamically. For example, given the inventory
shell> cat hosts
host1
host2
host3
host4
let host1 and host4 create the variables and host2 and host3 use them. Create the template
shell> cat share-vars.yml.j2
- name: Share facts among all hosts
hosts: all
tasks:
- set_fact:
{% for i in share_vars %}
{{ i.var }}: "{{ lbr }} hostvars.{{ i.host }}.{{ i.var }} {{ rbr }}"
{% endfor %}
run_once: true
and the playbook
shell> cat create-share-vars.yml
- name: Create playbook share-vars.yml
hosts: localhost
vars:
share_vars:
- {host: host1, var: fact1}
- {host: host4, var: fact4}
lbr: "{{ '{{' }}"
rbr: "{{ '}}' }}"
tasks:
- template:
src: share-vars.yml.j2
dest: share-vars.yml
gives
shell> cat share-vars.yml
- name: Share facts among all hosts
hosts: all
tasks:
- set_fact:
fact1: "{{ hostvars.host1.fact1 }}"
fact4: "{{ hostvars.host4.fact4 }}"
run_once: true
Import this playbook, for example
shell> cat playbook.yml
- hosts: host1
tasks:
- set_fact:
fact1: foo
- hosts: host4
tasks:
- set_fact:
fact4: bar
- import_playbook: share-vars.yml
- hosts: host2,host3
tasks:
- debug:
var: fact1
- debug:
var: fact4
gives (abridged)
PLAY [host2,host3] *********************************************************
TASK [debug] ***************************************************************
ok: [host2] =>
fact1: foo
ok: [host3] =>
fact1: foo
TASK [debug] ***************************************************************
ok: [host2] =>
fact4: bar
ok: [host3] =>
fact4: bar
Notes
Upvotes: 1
Reputation: 1954
set_fact
module sets host variables, You could access to those variable with hostvars
.
- name: some playbook
gather_facts: no
hosts: host1
tasks:
- set_fact:
fact1: "foo"
- hosts: host2
gather_facts: no
tasks:
- debug:
msg: "{{ hostvars['host1']['fact1'] }}"
Upvotes: 7