3

In Ansible I'm trying to generate a variable from a task on one host and then use the variable to do something to another host. Specifically, I'm trying to create a Kubernetes cluster - On the control plane node I can save the join command into a variable, but this appears to be scoped to the source host only - I can't work out how to access that variable from another host.

- name: read join command from the controlPlane
  shell: kubeadm token create --print-join-command
  when: inventory_hostname in groups['controlPlane']
  register: joinCmd

- name: join worker nodes to cluster
  command: "{{ joinCmd.stdout }}"
  when: inventory_hostname in groups['workerNodes']

The above fails on the second task (The task includes an option with an undefined variable. the error was: 'dict object' has no attribute 'stdout'). The standard approach seems to be save the line to a file locally, copy the file to the worker nodes and execute it locally which seems cumbersome (and leaves the join token lying around).

How can I achieve this with variables only?

1
  • i may be mistaken, but you may need a separate play. I seem to remember that host vars are re-evaluated when a new play is started Commented May 25, 2021 at 5:29

2 Answers 2

2

I found a solution - the trick here is delegate_to and delegate_facts:

- hosts: all
  remote_user: ansible
  become: false

  tasks:
  - name: read join line from controlPlane
    shell: kubeadm token create --print-join-command
    when: inventory_hostname in groups['workerNodes']
    register: joinCmd
    delegate_to: "{{ item }}"
    delegate_facts: true
    with_items: "{{ groups['controlPlane'] }}"

  - name: join all worker nodes to cluster
    command: "{{ joinCmd.results[0].stdout }}"
    become: yes
    when: inventory_hostname in groups['workerNodes']

The first task kind of reads backwards to my mind - when says 'run this task on all the workerNode hosts...' but delegate_to says '..but actually run it on a different host'. It works for me though (I've only got 1 host in controlPlane group, not sure of outcome with more hosts).

1

Another option here would be to run tasks on the master node(s) to create the join command and just run the role for nodes joining based on the same conditions:

- hosts: cluster_masters,cluster_workers
  pre_tasks:
    - name: Create the token to join
      ansible.builtin.shell: |
        kubeadm token create --print-join-command
      register: join_command
      when: inventory_hostname in groups.cluster_masters
    - name: Set token as fact
      ansible.builtin.set_fact:
        join_command: "{{ join_command.stdout }}"
      run_once: true
      when: inventory_hostname in groups.cluster_masters
  roles:
    - role: applications/kubernetes/node
      when: inventory_hostname in groups.cluster_workers and join_command is defined

The join_command is now availabe in the role

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.