[community.docker.docker_node] Setting labels does not run on manager node

I am using ansible community.docker modules to manage a docker swarm cluster. So far the initialization of manager and worker nodes does work great.

Now I try to label nodes in the cluster and use the community.docker.docker_node for that. When I try to label the nodes, I get an error from the node telling me that this module must be run on a manger node.

fatal: [aragorn.m.internal]: FAILED! => {"changed": false, "msg": "Error running docker swarm module: must run on swarm manager node"}

How do I do that? Checked the module syntax and examples but could not get a clue about it.

My code looks like that:

- name: Manage docker swarm cluster
  hosts: swarm
  tasks:

  ...

    - name: Set Labels on swarm nodes
      community.docker.docker_node:
        hostname: "{{ inventory_hostname_short }}"
        labels: "{{ swarm_labels }}"
        labels_state: replace

Whereas swarm is the group of all nodes of the swarm and swarm_labels is a dictionary of labels given as a host variable of the host to set the labels on. Only a few of them are managers.

The module needs to be run on one of the host(s) that’s a manager node.

Something like:

    - name: Set Labels on swarm nodes
      community.docker.docker_node:
        hostname: "{{ inventory_hostname_short }}"
        labels: "{{ swarm_labels }}"
        labels_state: replace
      delegate_to: "{{ swarm_manager_node }}"

where swarm_manager_node is the inventory hostname of a manager node.

1 Like

I tried that already. This will only work if the delegated target is the master node. For all worker nodes this gives an error like:

fatal: [concierge.m.internal -> camina.m.internal]: FAILED! => {"changed": false, "msg": "Failed to update node : 400 Client Error for http+docker://localhost/v1.47/nodes/sxrdnv670whbk2ifo96pw1qrj/update?version=3152: Bad Request (\"invalid JSON: json: cannot unmarshal number into Go struct field NodeSpec.Labels of type string\")"}

Looks like the connection is not made via docker socket but it tries to contact via http.

And the 400er status code means bad request, which means the module does not create a valid request.

Unfortunately the documentation does not give any further hints but only shows the example I used in this post.

That error message sounds like you are trying to set a label to an integer value, and not to a string.

1 Like

Oh, mea culpa. You are totally right. I guess I still have to go a long way with ansible. Giving the label as strings worked perfectly.

Here is a draft from my inventory, in case others come over this post:

swarm:
    children:
        swarm_masters:
            hosts:
                camina.m.internal:
                    swarm_advertise_addr: 192.168.1.4
                    swarm_data_path_addr: 192.168.2.8
                    swarm_labels:
                        capacity: "small"

        swarm_nodes:
            hosts:
                concierge.m.internal:
                    swarm_advertise_addr: 192.168.1.3
                    swarm_data_path_addr: 192.168.2.3
                    swarm_labels:
                        capacity: "large"
                        rack: "1"

        ...

My problem was to assign the rack label as integer and not as string, as you already guessed.

The module should be fixed so that it automatically converts non-strings to strings (or warns/fails for things that cannot be converted correctly, like booleans), but fixing the types on your side is of course the better way :slight_smile: There’s also always the problem with having 1.10 ending up as 1.1 because it’s treated as a floating point number :wink: (Integers are safe though, except if you happen to use hexadecimal or octal encoding, which will be gone by the time when they’re converted back to strings…)

I created Sanitize labels by felixfontein · Pull Request #985 · ansible-collections/community.docker · GitHub which should fix this (also for some more modules).