Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docker_swarm_service: Set minimum docker-py version to 2.0.2 #53295

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
bugfixes:
- "docker_swarm_service - Raise minimum required docker-py version for module to 2.0.2."
- "docker_swarm_service - Raise minimum required docker-py version for ``secrets`` to 2.4.0."
- "docker_swarm_service - Validate minimum docker-py version of 2.4.0 for option ``constraints``."
28 changes: 22 additions & 6 deletions lib/ansible/modules/cloud/docker/docker_swarm_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@
- docker
- docker.docker_py_2_documentation
requirements:
- "docker >= 2.0"
- "docker >= 2.0.2"
- "Docker API >= 1.24"
notes:
- "Images will only resolve to the latest digest when using Docker API >= 1.30 and docker-py >= 3.2.0.
Expand Down Expand Up @@ -1784,7 +1784,12 @@ def get_service(self, name):

hosts = task_template_data['ContainerSpec'].get('Hosts')
if hosts:
hosts = [host.split(' ', 1) for host in hosts]
hosts = [
list(reversed(host.split(":", 1)))
if ":" in host
else host.split(" ", 1)
for host in hosts
]
ds.hosts = dict((hostname, ip) for ip, hostname in hosts)
ds.tty = task_template_data['ContainerSpec'].get('TTY')

Expand Down Expand Up @@ -1943,7 +1948,10 @@ def get_image_digest(self, name, resolve=True):

def can_update_networks(self):
# Before Docker API 1.29 adding/removing networks was not supported
return self.client.docker_api_version >= LooseVersion('1.29')
return (
self.client.docker_api_version >= LooseVersion('1.29') and
self.client.docker_py_version >= LooseVersion('2.7')
)

def run(self):
self.diff_tracker = DifferenceTracker()
Expand Down Expand Up @@ -2197,17 +2205,18 @@ def main():
)

option_minimal_versions = dict(
constraints=dict(docker_py_version='2.4.0'),
dns=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
dns_options=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
dns_search=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
endpoint_mode=dict(docker_py_version='3.0.0', docker_api_version='1.25'),
force_update=dict(docker_py_version='2.1.0', docker_api_version='1.25'),
healthcheck=dict(docker_py_version='2.0.0', docker_api_version='1.25'),
healthcheck=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
hostname=dict(docker_py_version='2.2.0', docker_api_version='1.25'),
hosts=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
groups=dict(docker_py_version='2.6.0', docker_api_version='1.25'),
tty=dict(docker_py_version='2.4.0', docker_api_version='1.25'),
secrets=dict(docker_py_version='2.1.0', docker_api_version='1.25'),
secrets=dict(docker_py_version='2.4.0', docker_api_version='1.25'),
configs=dict(docker_py_version='2.6.0', docker_api_version='1.30'),
update_max_failure_ratio=dict(docker_py_version='2.1.0', docker_api_version='1.25'),
update_monitor=dict(docker_py_version='2.1.0', docker_api_version='1.25'),
Expand Down Expand Up @@ -2259,6 +2268,13 @@ def main():
) is not None,
usage_msg='set placement.preferences'
),
placement_config_constraints=dict(
docker_py_version='2.4.0',
detect_usage=lambda c: (c.module.params['placement'] or {}).get(
'constraints'
) is not None,
usage_msg='set placement.constraints'
),
)

required_if = [
Expand All @@ -2269,7 +2285,7 @@ def main():
argument_spec=argument_spec,
required_if=required_if,
supports_check_mode=True,
min_docker_version='2.0.0',
min_docker_version='2.0.2',
min_docker_api_version='1.24',
option_minimal_versions=option_minimal_versions,
)
Expand Down
4 changes: 2 additions & 2 deletions test/integration/targets/docker_swarm_service/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
force: yes
ignore_errors: yes
# Maximum of 1.24 (docker API version for docker_swarm_service) and 1.25 (docker API version for docker_swarm) is 1.25
when: docker_py_version is version('2.0.0', '>=') and docker_api_version is version('1.25', '>=')
when: docker_py_version is version('2.0.2', '>=') and docker_api_version is version('1.25', '>=')

- fail: msg="Too old docker / docker-py version to run docker_swarm_service tests!"
when: not(docker_py_version is version('2.0.0', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
when: not(docker_py_version is version('2.0.2', '>=') and docker_api_version is version('1.25', '>=')) and (ansible_distribution != 'CentOS' or ansible_distribution_major_version|int > 6)
187 changes: 94 additions & 93 deletions test/integration/targets/docker_swarm_service/tasks/tests/misc.yml
Original file line number Diff line number Diff line change
@@ -1,108 +1,109 @@
---
- block:
- name: Create a swarm service without name
register: output
docker_swarm_service:
state: present
ignore_errors: yes

- name: Create a swarm service without name
register: output
docker_swarm_service:
state: present
ignore_errors: yes
- name: assert failure when name not set
assert:
that:
- output is failed
- 'output.msg == "missing required arguments: name"'

- name: assert failure when name not set
assert:
that:
- output is failed
- 'output.msg == "missing required arguments: name"'
- name: Remove an non-existing service
register: output
docker_swarm_service:
state: absent
name: non_existing_service

- name: Remove an non-existing service
register: output
docker_swarm_service:
state: absent
name: non_existing_service
- name: assert output not changed when deleting non-existing service
assert:
that:
- output is not changed

- name: assert output not changed when deleting non-existing service
assert:
that:
- output is not changed
- name: create sample service
register: output
docker_swarm_service:
name: test_service
endpoint_mode: dnsrr
image: busybox
args:
- sleep
- "3600"

- name: create sample service
register: output
docker_swarm_service:
name: test_service
endpoint_mode: dnsrr
image: busybox
args:
- sleep
- "3600"
- name: assert sample service is created
assert:
that:
- output is changed

- name: assert sample service is created
assert:
that:
- output is changed
- name: change service args
register: output
docker_swarm_service:
name: test_service
image: busybox
args:
- sleep
- "1800"

- name: change service args
register: output
docker_swarm_service:
name: test_service
image: busybox
args:
- sleep
- "1800"
- name: assert service args are correct
assert:
that:
- output.swarm_service.args == ['sleep', '1800']

- name: assert service args are correct
assert:
that:
- output.swarm_service.args == ['sleep', '1800']
- name: set service mode to global
register: output
docker_swarm_service:
name: test_service
image: busybox
endpoint_mode: vip
mode: global
args:
- sleep
- "1800"

- name: set service mode to global
register: output
docker_swarm_service:
name: test_service
image: busybox
endpoint_mode: vip
mode: global
args:
- sleep
- "1800"
- name: assert service mode changed caused service rebuild
assert:
that:
- output.rebuilt

- name: assert service mode changed caused service rebuild
assert:
that:
- output.rebuilt
- name: add published ports to service
register: output
docker_swarm_service:
name: test_service
image: busybox
mode: global
args:
- sleep
- "1800"
endpoint_mode: vip
publish:
- protocol: tcp
published_port: 60001
target_port: 60001
- protocol: udp
published_port: 60001
target_port: 60001

- name: add published ports to service
register: output
docker_swarm_service:
name: test_service
image: busybox
mode: global
args:
- sleep
- "1800"
endpoint_mode: vip
publish:
- protocol: tcp
published_port: 60001
target_port: 60001
- protocol: udp
published_port: 60001
target_port: 60001
- name: fake image key as it is not predictable
set_fact:
ansible_docker_service_output: "{{ output.swarm_service|combine({'image': 'busybox'}) }}"

- name: fake image key as it is not predictable
set_fact:
ansible_docker_service_output: "{{ output.swarm_service|combine({'image': 'busybox'}) }}"
- name: assert service matches expectations
assert:
that:
- ansible_docker_service_output == service_expected_output

- name: assert service matches expectations
assert:
that:
- ansible_docker_service_output == service_expected_output
- name: delete sample service
register: output
docker_swarm_service:
name: test_service
state: absent

- name: delete sample service
register: output
docker_swarm_service:
name: test_service
state: absent

- name: assert service deletion returns changed
assert:
that:
- output is success
- output is changed
- name: assert service deletion returns changed
assert:
that:
- output is success
- output is changed
when: docker_api_version is version('1.24', '>=') and docker_py_version is version('3.0.0', '>=')