---
- block:
  - name: Make sure we're not already using Docker swarm
    docker_swarm:
      state: absent
      force: true

  - name: Try to get docker_node_info when docker is not running in swarm mode
    docker_node_info:
    ignore_errors: yes
    register: output

  - name: assert failure when called when swarm is not in use or not run on manager node
    assert:
      that:
         - 'output is failed'
         - 'output.msg == "Error running docker swarm module: must run on swarm manager node"'

  - name: Create a Swarm cluster
    docker_swarm:
      state: present
      advertise_addr: "{{ansible_default_ipv4.address | default('127.0.0.1')}}"
    register: output

  - name: assert changed when create a new swarm cluster
    assert:
      that:
         - 'output is changed'
         - 'output.actions[0] | regex_search("New Swarm cluster created: ")'
         - 'output.swarm_facts.JoinTokens.Manager'
         - 'output.swarm_facts.JoinTokens.Worker'

  - name: Try to get docker_node_info when docker is running in swarm mode and as manager
    docker_node_info:
    register: output

  - name: assert reading docker swarm node facts
    assert:
      that:
         - 'output.nodes | length > 0'
         - 'output.nodes[0].ID is string'

  - name: Register node ID
    set_fact:
      nodeid: "{{ output.nodes[0].ID }}"

####################################################################
## Set node as swarm manager #######################################
####################################################################

  - name: Try to set node as manager (check)
    docker_node:
      hostname: "{{ nodeid }}"
      role: manager
    check_mode: yes
    register: set_as_manager_1

  - name: Try to set node as manager
    docker_node:
      hostname: "{{ nodeid }}"
      role: manager
    register: set_as_manager_2

  - name: Try to set node as manager (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      role: manager
    register: set_as_manager_3

  - name: Try to set node as manager (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      role: manager
    check_mode: yes
    register: set_as_manager_4

  - name: assert that node role does has not changed
    assert:
      that:
         - 'set_as_manager_1 is not changed'
         - 'set_as_manager_2 is not changed'
         - 'set_as_manager_3 is not changed'
         - 'set_as_manager_4 is not changed'
         - 'set_as_manager_1.node.Spec.Role == "manager"'
         - 'set_as_manager_2.node.Spec.Role == "manager"'
         - 'set_as_manager_3.node.Spec.Role == "manager"'
         - 'set_as_manager_4.node.Spec.Role == "manager"'

####################################################################
## Set node as swarm worker ########################################
####################################################################

  - name: Try to set node as worker (check)
    docker_node:
      hostname: "{{ nodeid }}"
      role: worker
    check_mode: yes
    register: set_as_worker_1

  - name: Try to set node as worker
    docker_node:
      hostname: "{{ nodeid }}"
      role: worker
    ignore_errors: yes
    register: set_as_worker_2

  - name: assert that node cannot change role to worker
    assert:
      that:
         - 'set_as_worker_1 is changed'
         - 'set_as_worker_2 is failed'
         - 'set_as_worker_2.msg | regex_search("attempting to demote the last manager of the swarm")'

####################################################################
## Set node as pasued ##############################################
####################################################################

  - name: Try to set node availability as paused  (check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: pause
    check_mode: yes
    register: set_as_paused_1

  - name: Try to set node availability as paused
    docker_node:
      hostname: "{{ nodeid }}"
      availability: pause
    register: set_as_paused_2

  - name: Try to set node availability as paused (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: pause
    register: set_as_paused_3

  - name: Try to set node availability as paused (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: pause
    check_mode: yes
    register: set_as_paused_4

  - name: assert node changed availability to paused
    assert:
      that:
         - 'set_as_paused_1 is changed'
         - 'set_as_paused_2 is changed'
         - 'set_as_paused_3 is not changed'
         - 'set_as_paused_4 is not changed'
         - 'set_as_paused_2.node.Spec.Availability == "pause"'

####################################################################
## Set node as drained #############################################
####################################################################

  - name: Try to set node availability as drained (check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: drain
    check_mode: yes
    register: output_drain_1

  - name: Try to set node availability as drained
    docker_node:
      hostname: "{{ nodeid }}"
      availability: drain
    register: output_drain_2

  - name: Try to set node availability as drained (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: drain
    register: output_drain_3

  - name: Try to set node availability as drained (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: drain
    check_mode: yes
    register: output_drain_4

  - name: assert node changed availability to drained
    assert:
      that:
         - 'output_drain_1 is changed'
         - 'output_drain_2 is changed'
         - 'output_drain_3 is not changed'
         - 'output_drain_4 is not changed'
         - 'output_drain_2.node.Spec.Availability == "drain"'


####################################################################
## Set node as active ##############################################
####################################################################

  - name: Try to set node availability as active (check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: active
    check_mode: yes
    register: output_active_1

  - name: Try to set node availability as active
    docker_node:
      hostname: "{{ nodeid }}"
      availability: active
    register: output_active_2

  - name: Try to set node availability as active (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: active
    register: output_active_3

  - name: Try to set node availability as active (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      availability: active
    check_mode: yes
    register: output_active_4

  - name: assert node changed availability to active
    assert:
      that:
         - 'output_active_1 is changed'
         - 'output_active_2 is changed'
         - 'output_active_3 is not changed'
         - 'output_active_4 is not changed'
         - 'output_active_2.node.Spec.Availability == "active"'

####################################################################
## Add single label ###############################################
####################################################################

  - name: Try to add single label to swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1
    check_mode: yes
    register: output_add_single_label_1

  - name: Try to add single label to swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1
    register: output_add_single_label_2

  - name: Try to add single label to swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1
    register: output_add_single_label_3

  - name: Try to add single label to swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1
    check_mode: yes
    register: output_add_single_label_4

  - name: assert adding single label to swarm node
    assert:
      that:
         - 'output_add_single_label_1 is changed'
         - 'output_add_single_label_2 is changed'
         - 'output_add_single_label_3 is not changed'
         - 'output_add_single_label_4 is not changed'
         - 'output_add_single_label_2.node.Spec.Labels | length == 1'
         - 'output_add_single_label_2.node.Spec.Labels.label1 == "value1"'

####################################################################
## Add multiple labels #############################################
####################################################################

  - name: Try to add five labels to swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2
        label3: value3
        label4: value4
        label5: value5
        label6: value6
    check_mode: yes
    register: output_add_multiple_labels_1

  - name: Try to add five labels to swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2
        label3: value3
        label4: value4
        label5: value5
        label6: value6
    register: output_add_multiple_labels_2

  - name: Try to add five labels to swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2
        label3: value3
        label4: value4
        label5: value5
        label6: value6
    register: output_add_multiple_labels_3

  - name: Try to add five labels to swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2
        label3: value3
        label4: value4
        label5: value5
        label6: value6
    check_mode: yes
    register: output_add_multiple_labels_4

  - name: assert adding multiple labels to swarm node
    assert:
      that:
         - 'output_add_multiple_labels_1 is changed'
         - 'output_add_multiple_labels_2 is changed'
         - 'output_add_multiple_labels_3 is not changed'
         - 'output_add_multiple_labels_4 is not changed'
         - 'output_add_multiple_labels_2.node.Spec.Labels | length == 6'
         - 'output_add_multiple_labels_2.node.Spec.Labels.label1 == "value1"'
         - 'output_add_multiple_labels_2.node.Spec.Labels.label6 == "value6"'

####################################################################
## Update label value ##############################################
####################################################################

  - name: Update value of existing label (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1111
    check_mode: yes
    register: output_update_label_1

  - name: Update value of existing label
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1111
    register: output_update_label_2

  - name: Update value of existing label (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1111
    register: output_update_label_3

  - name: Update value of existing label (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label1: value1111
    check_mode: yes
    register: output_update_label_4

  - name: assert updating single label assigned to swarm node
    assert:
      that:
         - 'output_update_label_1 is changed'
         - 'output_update_label_2 is changed'
         - 'output_update_label_3 is not changed'
         - 'output_update_label_4 is not changed'
         - 'output_update_label_2.node.Spec.Labels | length == 6'
         - 'output_update_label_2.node.Spec.Labels.label1 == "value1111"'
         - 'output_update_label_2.node.Spec.Labels.label5 == "value5"'

####################################################################
## Update multiple labels values ###################################
####################################################################

  - name: Update value of multiple existing label (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2222
        label3: value3333
    check_mode: yes
    register: output_update_labels_1

  - name: Update value of multiple existing label
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2222
        label3: value3333
    register: output_update_labels_2

  - name: Update value of multiple existing label (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2222
        label3: value3333
    register: output_update_labels_3

  - name: Update value of multiple existing label (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label2: value2222
        label3: value3333
    check_mode: yes
    register: output_update_labels_4

  - name: assert updating multiple labels assigned to swarm node
    assert:
      that:
         - 'output_update_labels_1 is changed'
         - 'output_update_labels_2 is changed'
         - 'output_update_labels_3 is not changed'
         - 'output_update_labels_4 is not changed'
         - 'output_update_labels_2.node.Spec.Labels | length == 6'
         - 'output_update_labels_2.node.Spec.Labels.label1 == "value1111"'
         - 'output_update_labels_2.node.Spec.Labels.label3 == "value3333"'
         - 'output_update_labels_2.node.Spec.Labels.label5 == "value5"'

####################################################################
## Remove single label #############################################
####################################################################

  - name: Try to remove single existing label from swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label1
    check_mode: yes
    register: output_remove_label_1

  - name: Try to remove single existing label from swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label1
    register: output_remove_label_2

  - name: Try to remove single existing label from swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label1
    register: output_remove_label_3

  - name: Try to remove single existing label from swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label1
    check_mode: yes
    register: output_remove_label_4

  - name: assert removing single label from swarm node
    assert:
      that:
         - 'output_remove_label_1 is changed'
         - 'output_remove_label_2 is changed'
         - 'output_remove_label_3 is not changed'
         - 'output_remove_label_4 is not changed'
         - 'output_remove_label_2.node.Spec.Labels | length == 5'
         - '"label1" not in output_remove_label_2.node.Spec.Labels'
         - 'output_remove_label_2.node.Spec.Labels.label3 == "value3333"'
         - 'output_remove_label_2.node.Spec.Labels.label5 == "value5"'


####################################################################
## Remove single not assigned to swarm label #######################
####################################################################

  - name: Try to remove single non-existing label from swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - labelnotexist
    check_mode: yes
    register: output_remove_nonexist_label_1

  - name: Try to remove single non-existing label from swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - labelnotexist
    register: output_remove_nonexist_label_2

  - name: Try to remove single non-existing label from swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - labelnotexist
    register: output_remove_nonexist_label_3

  - name: Try to remove single non-existing label from swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - labelnotexist
    check_mode: yes
    register: output_remove_nonexist_label_4

  - name: assert removing single non-existing label from swarm node
    assert:
      that:
         - 'output_remove_nonexist_label_1 is not changed'
         - 'output_remove_nonexist_label_2 is not changed'
         - 'output_remove_nonexist_label_3 is not changed'
         - 'output_remove_nonexist_label_4 is not changed'
         - 'output_remove_nonexist_label_2.node.Spec.Labels | length == 5'
         - '"label1" not in output_remove_nonexist_label_2.node.Spec.Labels'
         - 'output_remove_nonexist_label_2.node.Spec.Labels.label3 == "value3333"'
         - 'output_remove_nonexist_label_2.node.Spec.Labels.label5 == "value5"'

####################################################################
## Remove multiple labels ##########################################
####################################################################

  - name: Try to remove two existing labels from swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label2
        - label3
    check_mode: yes
    register: output_remove_label_1

  - name: Try to remove two existing labels from swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label2
        - label3
    register: output_remove_label_2

  - name: Try to remove two existing labels from swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label2
        - label3
    register: output_remove_label_3

  - name: Try to remove two existing labels from swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label2
        - label3
    check_mode: yes
    register: output_remove_label_4

  - name: assert removing multiple labels from swarm node
    assert:
      that:
         - 'output_remove_label_1 is changed'
         - 'output_remove_label_2 is changed'
         - 'output_remove_label_3 is not changed'
         - 'output_remove_label_4 is not changed'
         - 'output_remove_label_2.node.Spec.Labels | length == 3'
         - '"label1" not in output_remove_label_2.node.Spec.Labels'
         - '"label2" not in output_remove_label_2.node.Spec.Labels'
         - 'output_remove_label_2.node.Spec.Labels.label5 == "value5"'

####################################################################
## Remove multiple labels, mix assigned and not assigned  ##########
####################################################################

  - name: Try to remove mix of existing amd non-existing labels from swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label4
        - labelisnotthere
    check_mode: yes
    register: output_remove_mix_labels_1

  - name: Try to remove mix of existing amd non-existing labels from swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label4
        - labelisnotthere
    register: output_remove_mix_labels_2

  - name: Try to remove mix of existing amd non-existing labels from swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label4
        - labelisnotthere
    register: output_remove_mix_labels_3

  - name: Try to remove mix of existing amd non-existing labels from swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_to_remove:
        - label4
        - labelisnotthere
    check_mode: yes
    register: output_remove_mix_labels_4

  - name: assert removing mix of existing and non-existing labels from swarm node
    assert:
      that:
        - 'output_remove_mix_labels_1 is changed'
        - 'output_remove_mix_labels_2 is changed'
        - 'output_remove_mix_labels_3 is not changed'
        - 'output_remove_mix_labels_4 is not changed'
        - 'output_remove_mix_labels_2.node.Spec.Labels | length == 2'
        - '"label1" not in output_remove_mix_labels_2.node.Spec.Labels'
        - '"label4" not in output_remove_mix_labels_2.node.Spec.Labels'
        - 'output_remove_mix_labels_2.node.Spec.Labels.label5 == "value5"'

####################################################################
## Add and remove labels ###########################################
####################################################################

  - name: Try to add and remove nonoverlapping labels at the same time (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label7: value7
        label8: value8
      labels_to_remove:
        - label5
    check_mode: yes
    register: output_add_del_labels_1

  - name: Try to add and remove nonoverlapping labels at the same time
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label7: value7
        label8: value8
      labels_to_remove:
        - label5
    register: output_add_del_labels_2

  - name: Try to add and remove nonoverlapping labels at the same time (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label7: value7
        label8: value8
      labels_to_remove:
        - label5
    register: output_add_del_labels_3

  - name: Try to add and remove nonoverlapping labels at the same time (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label7: value7
        label8: value8
      labels_to_remove:
        - label5
    check_mode: yes
    register: output_add_del_labels_4

  - name: assert adding and removing nonoverlapping labels from swarm node
    assert:
      that:
        - 'output_add_del_labels_1 is changed'
        - 'output_add_del_labels_2 is changed'
        - 'output_add_del_labels_3 is not changed'
        - 'output_add_del_labels_4 is not changed'
        - 'output_add_del_labels_2.node.Spec.Labels | length == 3'
        - '"label5" not in output_add_del_labels_2.node.Spec.Labels'
        - 'output_add_del_labels_2.node.Spec.Labels.label8 == "value8"'

####################################################################
## Add and remove labels with label in both lists ##################
####################################################################

  - name: Try to add or update and remove overlapping labels at the same time (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label22: value22
        label6: value6666
      labels_to_remove:
        - label6
        - label7
    check_mode: yes
    register: output_add_del_overlap_lables_1

  - name: Try to add or update and remove overlapping labels at the same time
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label22: value22
        label6: value6666
      labels_to_remove:
        - label6
        - label7
    register: output_add_del_overlap_lables_2

  - name: Try to add or update and remove overlapping labels at the same time (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label22: value22
        label6: value6666
      labels_to_remove:
        - label6
        - label7
    register: output_add_del_overlap_lables_3

  - name: Try to add or update and remove overlapping labels at the same time (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label22: value22
        label6: value6666
      labels_to_remove:
        - label6
        - label7
    check_mode: yes
    register: output_add_del_overlap_lables_4

  - name: assert adding or updating and removing overlapping labels from swarm node
    assert:
      that:
        - 'output_add_del_overlap_lables_1 is changed'
        - 'output_add_del_overlap_lables_2 is changed'
        - 'output_add_del_overlap_lables_3 is not changed'
        - 'output_add_del_overlap_lables_4 is not changed'
        - 'output_add_del_overlap_lables_2.node.Spec.Labels | length == 3'
        - '"label7" not in output_add_del_overlap_lables_2.node.Spec.Labels'
        - 'output_add_del_overlap_lables_2.node.Spec.Labels.label6 == "value6666"'
        - 'output_add_del_overlap_lables_2.node.Spec.Labels.label22 == "value22"'

####################################################################
## Replace labels #############################################
####################################################################

  - name: Replace labels on swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label11: value11
        label12: value12
      labels_state: replace
    check_mode: yes
    register: output_replace_labels_1

  - name: Replace labels on swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label11: value11
        label12: value12
      labels_state: replace
    register: output_replace_labels_2

  - name: Replace labels on swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label11: value11
        label12: value12
      labels_state: replace
    register: output_replace_labels_3

  - name: Replace labels on swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels:
        label11: value11
        label12: value12
      labels_state: replace
    check_mode: yes
    register: output_replace_labels_4

  - name: assert replacing labels from swarm node
    assert:
      that:
        - 'output_replace_labels_1 is changed'
        - 'output_replace_labels_2 is changed'
        - 'output_replace_labels_3 is not changed'
        - 'output_replace_labels_4 is not changed'
        - 'output_replace_labels_2.node.Spec.Labels | length == 2'
        - '"label6" not in output_replace_labels_2.node.Spec.Labels'
        - 'output_replace_labels_2.node.Spec.Labels.label12 == "value12"'

####################################################################
## Remove all labels #############################################
####################################################################

  - name: Remove all labels from swarm node (check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_state: replace
    check_mode: yes
    register: output_remove_labels_1

  - name: Remove all labels from swarm node
    docker_node:
      hostname: "{{ nodeid }}"
      labels_state: replace
    register: output_remove_labels_2

  - name: Remove all labels from swarm node (idempotent)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_state: replace
    register: output_remove_labels_3

  - name: Remove all labels from swarm node (idempotent check)
    docker_node:
      hostname: "{{ nodeid }}"
      labels_state: replace
    check_mode: yes
    register: output_remove_labels_4

  - name: assert removing all lables from swarm node
    assert:
      that:
        - 'output_remove_labels_1 is changed'
        - 'output_remove_labels_2 is changed'
        - 'output_remove_labels_3 is not changed'
        - 'output_remove_labels_4 is not changed'
        - 'output_remove_labels_2.node.Spec.Labels | length == 0'

  always:
  - name: Cleanup
    docker_swarm:
      state: absent
      force: true