5

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.

CzipO2
  • 403
  • 1
  • 6
  • 15
  • Also, I get the same second error when using the shell module. I think ansible just forgets what is in "rezult" when running on a server that it "!= '{{ manager_ip }}'". This is frustrating. – CzipO2 Oct 04 '19 at 08:29

4 Answers4

4

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.

SantaXL
  • 618
  • 8
  • 19
  • Love this, but are you not missing `when: inventory_hostname == groups['swarm_managers'][0]` from the "Get join-token" tasks? – Mr. Developerdude Sep 21 '21 at 04:52
  • 2
    @LennartRolland After the init task, the only host that knows the join tokens is `groups['swarm_managers'][0]`. And we want to make these tokens available for all hosts in inventory. So, in the next 2 tasks, each host is setting `join_token_xxx` fact by getting these variables from `groups['swarm_managers'][0]` - the `hostvars[groups['swarm_managers'][0]]` part. The only `when` that can be added here, that I can think of, is `when: inventory_hostname in groups['swarm_managers']` for `Get join-token for manager nodes` task and vice versa for `Get join-token for worker nodes` task – SantaXL Sep 21 '21 at 12:57
2

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.

SiKotic
  • 21
  • 2
2

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.

simonmicro
  • 53
  • 8
0

I think the issue here is from rezult.swarm_facts.JoinTokens.Worker. In debug info it appears as "msg": "SWMTKN-1-5p7..." but join_token: option from Ansible configuration expects it to be just plain token without additional wrappers as "msg": and so on.

achempion
  • 794
  • 6
  • 17
  • I don't think it's "msg" that's the problem here, that's there in any debug message. Did you manage to figure this out? I have the same problem. – Jimbo Apr 24 '20 at 16:51