Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker_swarm module - join_token parameter for ansible not working

This is my ansible playbook, the tasks are copied from docker_swarm module documentation so it should work:

  - name: Init a new swarm with default parameters
    docker_swarm:
      state: present
      advertise_addr: "{{ manager_ip }}:2377"
    register: rezult
    when: "ansible_default_ipv4.address == '{{ manager_ip }}'"


  - name: Add nodes
    docker_swarm:
      state: join
      advertise_addr: "{{ manager_ip }}"
      join_token: rezult.swarm_facts.JoinTokens.Worker
      remote_addrs: "{{ manager_ip }}:2377"
    when: "ansible_default_ipv4.address != '{{ manager_ip }}'"

It inits a swarm manager with the "manager_ip" --extra-var but it fails in the "add nodes task" with this error:

fatal: [vm2]: FAILED! => {"changed": false, "msg": "Can not join the Swarm Cluster: 500 Server Error: Internal Server Error (\"invalid join token\")"}

if I put "'{{ }}'" around "rezult.swarm_facts.JoinTokens.Worker" after join_token I get this:

fatal: [vm2]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'swarm_facts'\n\nThe error appears to be in '/home/ansible/docker-ansible/docker.yml': line 47, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n  - name: Add nodes\n    ^ here\n"}

If I put the debug msg for rezult.swarm_facts.JoinTokens.Worker I get the correct token:

ok: [opensuse1] => {
    "msg": "SWMTKN-1-5p7brhxxz4gzu716t78tt5woj7h6aflq0kdwvzwlbbe7ct0ba7-e59bg0t79q67ogd61ydwxc5yq"
}

and If I use that token manually with the docker swarm join command on the server I wish to merge with manager it works. So the variable has the correct value and the connection between nodes work. But I just can't get join_token to work. I am running ansible 2.8.5 with python 2.7.5.

I know I can use the shell module but I do not want to do that.

like image 294
CzipO2 Avatar asked Oct 04 '19 08:10

CzipO2


3 Answers

Something like this works for me:

---
- name: Init swarm on the first node
  community.general.docker_swarm:
    state: present
    advertise_addr: "{{ ansible_host }}"
  register: result
  when: inventory_hostname == groups['swarm_managers'][0]

- name: Get join-token for manager nodes
  set_fact:
    join_token_manager: "{{ hostvars[groups['swarm_managers'][0]].result.swarm_facts.JoinTokens.Manager }}"

- name: Get join-token for worker nodes
  set_fact:
    join_token_worker: "{{ hostvars[groups['swarm_managers'][0]].result.swarm_facts.JoinTokens.Worker }}"

- name: Join other managers
  community.general.docker_swarm:
    state: join
    join_token: "{{ join_token_manager }}"
    advertise_addr: "{{ ansible_host }}"
    remote_addrs: "{{ hostvars[groups['swarm_managers'][0]].ansible_host }}"
  when:
    - inventory_hostname in groups['swarm_managers']
    - inventory_hostname != groups['swarm_managers'][0]

- name: Join workers
  community.general.docker_swarm:
    state: join
    join_token: "{{ join_token_worker }}"
    advertise_addr: "{{ ansible_host }}"
    remote_addrs: "{{ hostvars[groups['swarm_managers'][0]].ansible_host }}"
  when:
    - inventory_hostname not in groups['swarm_managers']

In swarm_managers group there are managers and all other hosts from this inventory are workers.

like image 173
SantaXL Avatar answered Oct 22 '22 05:10

SantaXL


I think achempion was correct, the issue was that OPs variable rezult.swarm_facts.JoinTokens.Worker was not being evaluated, but rather provided as an object of sorts.

Replace rezult.swarm_facts.JoinTokens.Worker with "{{ rezult.swarm_facts.JoinTokens.Worker }}" and it should work.

I realise OP has probably already moved on but I have spent ages trying to figure out a very similar problem and this appeared to resolve it for me.

like image 34
SiKotic Avatar answered Oct 22 '22 06:10

SiKotic


As I have not enough reputation to comment - here is an other mistake in your playbooks task. You use:

  - name: Add nodes
    docker_swarm:
      state: join
      advertise_addr: "{{ manager_ip }}"
      join_token: rezult.swarm_facts.JoinTokens.Worker
      remote_addrs: "{{ manager_ip }}:2377"
    when: "ansible_default_ipv4.address != '{{ manager_ip }}'"

...which assigns the advertise_addr to the wrong ip address. This will still allow your nodes to join, but mess up their overlay network configuration (no node can ping each other, resulting in constant network failures). I would suggest to use the ssh connection ip instead:

  - name: Add nodes
    docker_swarm:
      state: join
      advertise_addr: "{{ ansible_ssh_host }}"
      join_token: rezult.swarm_facts.JoinTokens.Worker
      remote_addrs: "{{ manager_ip }}:2377"
    when: "ansible_default_ipv4.address != '{{ manager_ip }}'"

Also just take a look into the documentation examples:

- name: Add nodes
  community.docker.docker_swarm:
    state: join
    advertise_addr: 192.168.1.2
    join_token: SWMTKN-1--xxxxx
    remote_addrs: [ '192.168.1.1:2377' ]

...which also uses different ip addresses.

I have to admit: I also fall for it and it took several hours to solve. I hope someone else sees this answer before making the same mistake by just copying your snippet.

like image 27
simonmicro Avatar answered Oct 22 '22 07:10

simonmicro