I'm working on a set of Ansible plays in which there is a common or base play, a master play (items relevant only to the master server) and a node play (items relevant to all the node servers). This is pretty standard stuff, apt update and upgrade, install dependencies, do some shenanigans.

Then I needed to pass a variable from the master play/host to the node play/host. In Ansible you use the magic variable called hostvars for this.

So in the master play I registered the output I needed and then set a fact for it:

- name: get join command
  shell: kubeadm token create --print-join-command
  register: join_command_raw

- name: set join command
  set_fact:
    join_command: "{{ join_command_raw.stdout_lines[0] }}"

Then, I went to the node play and tried writing something based on the hostvars variable. The problem is that this variable is made to be attached to a host. And this is a set of dynamic plays in which I am using the excellent dynamic inventory ec2.py. This means that I don't know what the IP or even the name of my master is, so I can't reference it using hostvars['master']['myvariable'].

So I did what any self-respecting professional would do and scoured google and stack overflow looking for an answer. It took a while, and it was not exactly an answer, but I finally made it. I am using tags to identify my masters, so I found that I can still use hostvars for a group and use the dynamic inventory tagging for that. Here is a bit of the inventory in question:

./ec2.py --list
(...)
"tag_k8stype_master": [
    "34.254.186.212"
  ],
"tag_k8stype_node": [
    "52.16.45.100"
  ],
(...)

And this is how I got access to the variable in the node play:

- name: join cluster
  shell: "{{ hostvars[groups['tag_k8stype_master'][0]]['join_command'] }} >> /home/ubuntu/node_joined.txt"
  args:
    creates: /home/ubuntu/node_joined.txt

I hope this helps someone else!