From da8574c56775db14e3ba7bafada2740c9f7d62c3 Mon Sep 17 00:00:00 2001 From: Hannes Ljungberg Date: Thu, 21 Feb 2019 12:47:06 +0100 Subject: [PATCH] docker_swarm_service: Allow passing period strings on relevant options (#52530) * Allow duration to be passed as duration strings * Remove whitespace * Add changelog fragment * Fix broken test * Better error handling --- ...19-docker_swarm_service-period_options.yml | 5 ++ .../cloud/docker/docker_swarm_service.py | 67 +++++++++++++++---- .../tasks/tests/options.yml | 22 +++--- .../cloud/docker/test_docker_swarm_service.py | 14 ++++ 4 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 changelogs/fragments/52519-docker_swarm_service-period_options.yml diff --git a/changelogs/fragments/52519-docker_swarm_service-period_options.yml b/changelogs/fragments/52519-docker_swarm_service-period_options.yml new file mode 100644 index 0000000000..7dbf5f1b9e --- /dev/null +++ b/changelogs/fragments/52519-docker_swarm_service-period_options.yml @@ -0,0 +1,5 @@ +minor_changes: + - "docker_swarm_service - Added support for passing period as string to ``restart_policy_delay``." + - "docker_swarm_service - Added support for passing period as string to ``restart_policy_window``." + - "docker_swarm_service - Added support for passing period as string to ``update_delay``." + - "docker_swarm_service - Added support for passing period as string to ``update_monitor``." diff --git a/lib/ansible/modules/cloud/docker/docker_swarm_service.py b/lib/ansible/modules/cloud/docker/docker_swarm_service.py index 43ca2e343e..8962301de6 100644 --- a/lib/ansible/modules/cloud/docker/docker_swarm_service.py +++ b/lib/ansible/modules/cloud/docker/docker_swarm_service.py @@ -403,19 +403,25 @@ options: restart_policy_delay: description: - Delay between restarts. + - "Accepts a duration as an integer in nanoseconds or as a string in a format that look like: + C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)." - Corresponds to the C(--restart-delay) option of C(docker service create). - type: int + type: raw restart_policy_window: description: - Restart policy evaluation window. + - "Accepts a duration as an integer in nanoseconds or as a string in a format that look like: + C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)." - Corresponds to the C(--restart-window) option of C(docker service create). - type: int + type: raw update_delay: description: - - Rolling update delay in nanoseconds. + - Rolling update delay. + - "Accepts a duration as an integer in nanoseconds or as a string in a format that look like: + C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)." - Corresponds to the C(--update-delay) option of C(docker service create). - Before Ansible 2.8, the default value for this option was C(10). - type: int + type: raw update_parallelism: description: - Rolling update parallelism. @@ -432,10 +438,12 @@ options: - pause update_monitor: description: - - Time to monitor updated tasks for failures, in nanoseconds. + - Time to monitor updated tasks for failures. + - "Accepts a duration as an integer in nanoseconds or as a string in a format that look like: + C(5h34m56s), C(1m30s) etc. The supported units are C(us), C(ms), C(s), C(m) and C(h)." - Corresponds to the C(--update-monitor) option of C(docker service create). - Requires API version >= 1.25. - type: int + type: raw update_max_failure_ratio: description: - Fraction of tasks that may fail during an update before the failure action is invoked. @@ -714,6 +722,23 @@ def get_docker_environment(env, env_files): return sorted(env_list) +def get_nanoseconds_from_raw_option(name, value): + if value is None: + return None + elif isinstance(value, int): + return value + elif isinstance(value, string_types): + try: + return int(value) + except ValueError: + return convert_duration_to_nanosecond(value) + else: + raise ValueError( + 'Invalid type for %s %s (%s). Only string or int allowed.' + % (name, value, type(value)) + ) + + class DockerService(DockerBaseClass): def __init__(self): super(DockerService, self).__init__() @@ -837,12 +862,8 @@ class DockerService(DockerBaseClass): s.stop_signal = ap['stop_signal'] s.restart_policy = ap['restart_policy'] s.restart_policy_attempts = ap['restart_policy_attempts'] - s.restart_policy_delay = ap['restart_policy_delay'] - s.restart_policy_window = ap['restart_policy_window'] - s.update_delay = ap['update_delay'] s.update_parallelism = ap['update_parallelism'] s.update_failure_action = ap['update_failure_action'] - s.update_monitor = ap['update_monitor'] s.update_max_failure_ratio = ap['update_max_failure_ratio'] s.update_order = ap['update_order'] s.user = ap['user'] @@ -879,6 +900,23 @@ class DockerService(DockerBaseClass): s.env = get_docker_environment(ap['env'], ap['env_files']) + s.restart_policy_delay = get_nanoseconds_from_raw_option( + 'restart_policy_delay', + ap['restart_policy_delay'] + ) + s.restart_policy_window = get_nanoseconds_from_raw_option( + 'restart_policy_window', + ap['restart_policy_window'] + ) + s.update_delay = get_nanoseconds_from_raw_option( + 'update_delay', + ap['update_delay'] + ) + s.update_monitor = get_nanoseconds_from_raw_option( + 'update_monitor', + ap['update_monitor'] + ) + if ap['force_update']: s.force_update = int(str(time.time()).replace('.', '')) @@ -945,6 +983,7 @@ class DockerService(DockerBaseClass): service_s['gid'] = param_m['gid'] service_s['mode'] = param_m['mode'] s.secrets.append(service_s) + return s def compare(self, os): @@ -1725,13 +1764,13 @@ def main(): reserve_memory=dict(type='str'), resolve_image=dict(type='bool', default=True), restart_policy=dict(type='str', choices=['none', 'on-failure', 'any']), - restart_policy_delay=dict(type='int'), + restart_policy_delay=dict(type='raw'), restart_policy_attempts=dict(type='int'), - restart_policy_window=dict(type='int'), - update_delay=dict(type='int'), + restart_policy_window=dict(type='raw'), + update_delay=dict(type='raw'), update_parallelism=dict(type='int'), update_failure_action=dict(type='str', choices=['continue', 'pause']), - update_monitor=dict(type='int'), + update_monitor=dict(type='raw'), update_max_failure_ratio=dict(type='float'), update_order=dict(type='str'), user=dict(type='str'), diff --git a/test/integration/targets/docker_swarm_service/tasks/tests/options.yml b/test/integration/targets/docker_swarm_service/tasks/tests/options.yml index fda12130d8..7be008d100 100644 --- a/test/integration/targets/docker_swarm_service/tasks/tests/options.yml +++ b/test/integration/targets/docker_swarm_service/tasks/tests/options.yml @@ -2099,7 +2099,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_delay: 5 + restart_policy_delay: 5000000000 register: restart_policy_delay_1 - name: restart_policy_delay (idempotency) @@ -2107,7 +2107,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_delay: 5 + restart_policy_delay: 5s register: restart_policy_delay_2 - name: restart_policy_delay (change) @@ -2115,7 +2115,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_delay: 10 + restart_policy_delay: 10000000000 register: restart_policy_delay_3 - name: cleanup @@ -2139,7 +2139,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_window: 10 + restart_policy_window: 10000000000 register: restart_policy_window_1 - name: restart_policy_window (idempotency) @@ -2147,7 +2147,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_window: 10 + restart_policy_window: 10s register: restart_policy_window_2 - name: restart_policy_window (change) @@ -2155,7 +2155,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - restart_policy_window: 20 + restart_policy_window: 20s register: restart_policy_window_3 - name: cleanup @@ -2301,7 +2301,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - update_delay: 5 + update_delay: 5000000000 register: update_delay_1 - name: update_delay (idempotency) @@ -2309,7 +2309,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - update_delay: 5 + update_delay: 5s register: update_delay_2 - name: update_delay (change) @@ -2317,7 +2317,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - update_delay: 12 + update_delay: 12000000000 register: update_delay_3 - name: cleanup @@ -2429,7 +2429,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - update_monitor: 10000000000 + update_monitor: 10s register: update_monitor_2 - name: update_monitor (change) @@ -2437,7 +2437,7 @@ name: "{{ service_name }}" image: alpine:3.8 command: '/bin/sh -v -c "sleep 10m"' - update_monitor: 6000000000 + update_monitor: 60s register: update_monitor_3 - name: cleanup diff --git a/test/units/modules/cloud/docker/test_docker_swarm_service.py b/test/units/modules/cloud/docker/test_docker_swarm_service.py index 8542f5ee2f..d7779c30fd 100644 --- a/test/units/modules/cloud/docker/test_docker_swarm_service.py +++ b/test/units/modules/cloud/docker/test_docker_swarm_service.py @@ -98,3 +98,17 @@ def test_get_docker_environment(mocker, docker_swarm_service): None, env_files=[] ) assert result == [] + + +def test_get_nanoseconds_from_raw_option(docker_swarm_service): + value = docker_swarm_service.get_nanoseconds_from_raw_option('test', None) + assert value is None + + value = docker_swarm_service.get_nanoseconds_from_raw_option('test', '1m30s535ms') + assert value == 90535000000 + + value = docker_swarm_service.get_nanoseconds_from_raw_option('test', 10000000000) + assert value == 10000000000 + + with pytest.raises(ValueError): + docker_swarm_service.get_nanoseconds_from_raw_option('test', [])