From 49263d6af51069591f58815c61d32a3ed73c2728 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Sat, 14 Dec 2024 21:32:14 +0100 Subject: [PATCH] [stable-3] docker_compose_v2: ignore build events for changed status (#1012) * docker_compose_v2: add ignore_build_events option; ignore build events by default (#1011) * Add ignore_build_events option. * Adjust docs and tests. * Switch default to true. * Remove unnecessary parts from tests. (cherry picked from commit 2e7b4e4605c31a7788895e42f59c97b1687ee1e5) * Remove the new option. --- .../1011-docker_compose_v2-build-changed.yml | 5 + plugins/module_utils/compose_v2.py | 26 ++- plugins/modules/docker_compose_v2.py | 5 +- .../docker_compose_v2/tasks/tests/build.yml | 192 ++---------------- 4 files changed, 52 insertions(+), 176 deletions(-) create mode 100644 changelogs/fragments/1011-docker_compose_v2-build-changed.yml diff --git a/changelogs/fragments/1011-docker_compose_v2-build-changed.yml b/changelogs/fragments/1011-docker_compose_v2-build-changed.yml new file mode 100644 index 00000000..7ae960df --- /dev/null +++ b/changelogs/fragments/1011-docker_compose_v2-build-changed.yml @@ -0,0 +1,5 @@ +bugfixes: + - "docker_compose_v2 - when using Compose 2.31.0 or newer, revert to the old behavior that image rebuilds, for example if ``rebuild=always``, only + result in ``changed`` if a container has been restarted + (https://github.com/ansible-collections/community.docker/issues/1005, https://github.com/ansible-collections/community.docker/issues/pull/1011, + https://github.com/ansible-collections/community.docker/pull/1012)." diff --git a/plugins/module_utils/compose_v2.py b/plugins/module_utils/compose_v2.py index 5e3571f1..c25a88c3 100644 --- a/plugins/module_utils/compose_v2.py +++ b/plugins/module_utils/compose_v2.py @@ -57,6 +57,8 @@ DOCKER_STATUS_DONE = frozenset(( 'Recreated', # Extras for pull events 'Pulled', + # Extras for built events + 'Built', )) DOCKER_STATUS_WORKING = frozenset(( 'Creating', @@ -76,6 +78,10 @@ DOCKER_STATUS_PULL = frozenset(( 'Pulled', 'Pulling', )) +DOCKER_STATUS_BUILD = frozenset(( + 'Built', + 'Building', +)) DOCKER_STATUS_ERROR = frozenset(( 'Error', )) @@ -542,11 +548,13 @@ def parse_events(stderr, dry_run=False, warn_function=None, nonzero_rc=False): return events -def has_changes(events, ignore_service_pull_events=False): +def has_changes(events, ignore_service_pull_events=False, ignore_build_events=False): for event in events: if event.status in DOCKER_STATUS_WORKING: if ignore_service_pull_events and event.status in DOCKER_STATUS_PULL: continue + if ignore_build_events and event.status in DOCKER_STATUS_BUILD: + continue return True if event.resource_type == ResourceType.IMAGE_LAYER and event.status in DOCKER_PULL_PROGRESS_WORKING: return True @@ -802,8 +810,20 @@ class BaseComposeManager(DockerBaseClass): def emit_warnings(self, events): emit_warnings(events, warn_function=self.client.warn) - def update_result(self, result, events, stdout, stderr, ignore_service_pull_events=False): - result['changed'] = result.get('changed', False) or has_changes(events, ignore_service_pull_events=ignore_service_pull_events) + def update_result( + self, + result, + events, + stdout, + stderr, + ignore_service_pull_events=False, + ignore_build_events=False, + ): + result['changed'] = result.get('changed', False) or has_changes( + events, + ignore_service_pull_events=ignore_service_pull_events, + ignore_build_events=ignore_build_events, + ) result['actions'] = result.get('actions', []) + extract_actions(events) result['stdout'] = combine_text_output(result.get('stdout'), to_native(stdout)) result['stderr'] = combine_text_output(result.get('stderr'), to_native(stderr)) diff --git a/plugins/modules/docker_compose_v2.py b/plugins/modules/docker_compose_v2.py index 5ed873bb..89d5e8b5 100644 --- a/plugins/modules/docker_compose_v2.py +++ b/plugins/modules/docker_compose_v2.py @@ -433,6 +433,7 @@ class ServicesManager(BaseComposeManager): self.dependencies = parameters['dependencies'] self.pull = parameters['pull'] self.build = parameters['build'] + self.ignore_build_events = True self.recreate = parameters['recreate'] self.remove_images = parameters['remove_images'] self.remove_volumes = parameters['remove_volumes'] @@ -508,7 +509,7 @@ class ServicesManager(BaseComposeManager): rc, stdout, stderr = self.client.call_cli(*args, cwd=self.project_src) events = self.parse_events(stderr, dry_run=self.check_mode, nonzero_rc=rc != 0) self.emit_warnings(events) - self.update_result(result, events, stdout, stderr, ignore_service_pull_events=True) + self.update_result(result, events, stdout, stderr, ignore_service_pull_events=True, ignore_build_events=self.ignore_build_events) self.update_failed(result, events, args, stdout, stderr, rc) return result @@ -539,7 +540,7 @@ class ServicesManager(BaseComposeManager): rc_1, stdout_1, stderr_1 = self.client.call_cli(*args_1, cwd=self.project_src) events_1 = self.parse_events(stderr_1, dry_run=self.check_mode, nonzero_rc=rc_1 != 0) self.emit_warnings(events_1) - self.update_result(result, events_1, stdout_1, stderr_1, ignore_service_pull_events=True) + self.update_result(result, events_1, stdout_1, stderr_1, ignore_service_pull_events=True, ignore_build_events=self.ignore_build_events) is_failed_1 = is_failed(events_1, rc_1) if not is_failed_1 and not self._are_containers_stopped(): # Make sure all containers are stopped diff --git a/tests/integration/targets/docker_compose_v2/tasks/tests/build.yml b/tests/integration/targets/docker_compose_v2/tasks/tests/build.yml index 1ba9182a..86d5a413 100644 --- a/tests/integration/targets/docker_compose_v2/tasks/tests/build.yml +++ b/tests/integration/targets/docker_compose_v2/tasks/tests/build.yml @@ -13,6 +13,7 @@ {{ cname }}: build: ./build image: "{{ iname }}" + pull_policy: never stop_grace_period: 1s block: @@ -30,10 +31,6 @@ - '{{ project_src }}' - '{{ project_src }}/build' -#################################################################### -## Present ######################################################### -#################################################################### - - name: Template default project file copy: dest: '{{ project_src }}/docker-compose.yml' @@ -72,6 +69,21 @@ state: present register: present_2 + - name: Present (idempotent check, build=always) + docker_compose_v2: + project_src: '{{ project_src }}' + state: present + build: always + check_mode: true + register: present_4_check + + - name: Present (idempotent, build=always) + docker_compose_v2: + project_src: '{{ project_src }}' + state: present + build: always + register: present_4 + - assert: that: - present_1_check is changed @@ -88,175 +100,13 @@ - present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - present_2 is not changed - present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 + - present_4_check is changed + - present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 + - present_4 is not changed + - present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 -#################################################################### -## Absent ########################################################## -#################################################################### - - - name: Absent (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: absent - check_mode: true - register: absent_1_check - - - name: Absent - docker_compose_v2: - project_src: '{{ project_src }}' - state: absent - register: absent_1 - - - name: Absent (idempotent check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: absent - check_mode: true - register: absent_2_check - - - name: Absent (idempotent) - docker_compose_v2: - project_src: '{{ project_src }}' - state: absent - register: absent_2 - - - assert: - that: - - absent_1_check is changed - - absent_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - absent_1 is changed - - absent_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - absent_2_check is not changed - - absent_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - absent_2 is not changed - - absent_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - -#################################################################### -## Stopping and starting ########################################### -#################################################################### - - - name: Present stopped (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - check_mode: true - register: present_1_check - - - name: Present stopped - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - register: present_1 - - - name: Present stopped (idempotent check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - check_mode: true - register: present_2_check - - - name: Present stopped (idempotent) - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - register: present_2 - - - name: Started (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: present - check_mode: true - register: present_3_check - - - name: Started - docker_compose_v2: - project_src: '{{ project_src }}' - state: present - register: present_3 - - - name: Started (idempotent check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: present - check_mode: true - register: present_4_check - - - name: Started (idempotent) - docker_compose_v2: - project_src: '{{ project_src }}' - state: present - register: present_4 - - - name: Restarted (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: restarted - check_mode: true - register: present_5_check - - - name: Restarted - docker_compose_v2: - project_src: '{{ project_src }}' - state: restarted - register: present_5 - - - name: Stopped (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - check_mode: true - register: present_6_check - - - name: Stopped - docker_compose_v2: - project_src: '{{ project_src }}' - state: stopped - register: present_6 - - - name: Restarted (check) - docker_compose_v2: - project_src: '{{ project_src }}' - state: restarted - check_mode: true - register: present_7_check - - - name: Restarted - docker_compose_v2: - project_src: '{{ project_src }}' - state: restarted - register: present_7 - + always: - name: Cleanup docker_compose_v2: project_src: '{{ project_src }}' state: absent - - - assert: - that: - - present_1_check is changed - - present_1_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_1 is changed - - present_1.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_2_check is not changed - - present_2_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_2 is not changed - - present_2.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_3_check is changed - - present_3_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_3 is changed - - present_3.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_4_check is not changed - - present_4_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_4 is not changed - - present_4.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_5_check is changed - - present_5_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_5 is changed - - present_5.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_6_check is changed - - present_6_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_6 is changed - - present_6.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_7_check is changed - - present_7_check.warnings | default([]) | select('regex', ' Please report this at ') | length == 0 - - present_7 is changed - - present_7.warnings | default([]) | select('regex', ' Please report this at ') | length == 0