From 449448e8205c4a9427a09d23c7ee5bca29de8f01 Mon Sep 17 00:00:00 2001 From: tpourcelot Date: Sun, 3 Aug 2025 13:12:29 +0200 Subject: [PATCH] docker_swarm_service: add support for replicated jobs (#1108) * feat(docker_swarm_service): Add support for replicated jobs * chore(docker_swarm_plugin): Fixes after review * chore(docker_swarm_service): Add a check for minimum version * chore(docker_swarm_service): Add changelog fragment for #1108 * fix(docker_swarm_service): Fix typo in version check * Apply suggestions from code review Co-authored-by: Felix Fontein --------- Co-authored-by: Tristan Pourcelot Co-authored-by: Felix Fontein --- .../fragments/1108-replicated-job-support.yml | 2 + plugins/modules/docker_swarm_service.py | 15 ++++++- .../tasks/tests/options.yml | 45 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 changelogs/fragments/1108-replicated-job-support.yml diff --git a/changelogs/fragments/1108-replicated-job-support.yml b/changelogs/fragments/1108-replicated-job-support.yml new file mode 100644 index 00000000..7642753f --- /dev/null +++ b/changelogs/fragments/1108-replicated-job-support.yml @@ -0,0 +1,2 @@ +minor_changes: + - docker_swarm_service - add support for ``replicated-job`` mode for Swarm services (https://github.com/ansible-collections/community.docker/issues/626, https://github.com/ansible-collections/community.docker/pull/1108). diff --git a/plugins/modules/docker_swarm_service.py b/plugins/modules/docker_swarm_service.py index 210ebd01..8be5b243 100644 --- a/plugins/modules/docker_swarm_service.py +++ b/plugins/modules/docker_swarm_service.py @@ -237,11 +237,13 @@ options: - Service replication mode. - Service will be removed and recreated when changed. - Corresponds to the C(--mode) option of C(docker service create). + - The value V(replicated-job) was added in community.docker 4.7.0, and requires API version >= 1.41 and Docker SDK for Python >= 6.0.0. type: str default: replicated choices: - replicated - global + - replicated-job mounts: description: - List of dictionaries describing the service mounts. @@ -400,7 +402,7 @@ options: type: bool replicas: description: - - Number of containers instantiated in the service. Valid only if O(mode=replicated). + - Number of containers instantiated in the service. Valid only if O(mode=replicated) or O(mode=replicated-job). - If set to V(-1), and service is not present, service replicas will be set to V(1). - If set to V(-1), and service is present, service replicas will be unchanged. - Corresponds to the C(--replicas) option of C(docker service create). @@ -2210,6 +2212,9 @@ class DockerServiceManager(object): ds.replicas = mode['Replicated']['Replicas'] elif 'Global' in mode.keys(): ds.mode = 'global' + elif 'ReplicatedJob' in mode.keys(): + ds.mode = to_text('replicated-job', encoding='utf-8') + ds.replicas = mode['ReplicatedJob']['TotalCompletions'] else: raise Exception('Unknown service mode: %s' % mode) @@ -2605,7 +2610,7 @@ def main(): mode=dict( type='str', default='replicated', - choices=['replicated', 'global'] + choices=['replicated', 'global', 'replicated-job'] ), replicas=dict(type='int', default=-1), endpoint_mode=dict(type='str', choices=['vip', 'dnsrr']), @@ -2753,6 +2758,12 @@ def main(): ) is not None, usage_msg='set rollback_config.order' ), + mode_replicated_job=dict( + docker_py_version='6.0.0', + docker_api_version='1.41', + detect_usage=lambda c: c.module.params.get('mode') == 'replicated-job', + usage_msg='set mode' + ), ) required_if = [ ('state', 'present', ['image']) diff --git a/tests/integration/targets/docker_swarm_service/tasks/tests/options.yml b/tests/integration/targets/docker_swarm_service/tasks/tests/options.yml index 385f655a..d66eda36 100644 --- a/tests/integration/targets/docker_swarm_service/tasks/tests/options.yml +++ b/tests/integration/targets/docker_swarm_service/tasks/tests/options.yml @@ -1301,6 +1301,38 @@ replicas: 1 register: mode_3 +- name: mode (change) + docker_swarm_service: + name: "{{ service_name }}" + image: "{{ docker_test_image_alpine }}" + resolve_image: false + command: '/bin/sh -v -c "sleep 10m"' + mode: "replicated-job" + replicas: 1 + register: mode_4 + ignore_errors: true + +- name: mode (idempotency) + docker_swarm_service: + name: "{{ service_name }}" + image: "{{ docker_test_image_alpine }}" + resolve_image: false + command: '/bin/sh -v -c "sleep 10m"' + mode: "replicated-job" + replicas: 1 + register: mode_5 + ignore_errors: true + +- name: mode (change) + docker_swarm_service: + name: "{{ service_name }}" + image: "{{ docker_test_image_alpine }}" + resolve_image: false + command: '/bin/sh -v -c "sleep 10m"' + mode: "replicated" + replicas: 1 + register: mode_6 + - name: cleanup docker_swarm_service: name: "{{ service_name }}" @@ -1313,6 +1345,19 @@ - mode_2 is not changed - mode_3 is changed +- assert: + that: + - mode_4 is changed + - mode_5 is not changed and mode_5 is not failed + - mode_6 is changed + when: docker_api_version is version('1.41', '>=') and docker_py_version is version('6.0.0', '>=') + +- assert: + that: + - mode_4 is failed + - "'Minimum version required' in mode_4.msg" + when: docker_api_version is version('1.41', '<') or docker_py_version is version('6.0.0', '<') + #################################################################### ## stop_grace_period ############################################### ####################################################################