From e2014b9b599dc82258c8f9af65a78cbaeef570fe Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Wed, 13 Aug 2025 18:15:50 +0200 Subject: [PATCH] =?UTF-8?q?nextcloud(role):=20remove=20async=20=E2=86=92?= =?UTF-8?q?=20use=20batched=20shell;=20more=20robust=20changed=5Fwhen/fail?= =?UTF-8?q?ed=5Fwhen;=20fix=20quoting;=20refactor=20plugin=20routines;=20c?= =?UTF-8?q?lean=20up=20vars?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • 02_add_missing_indices.yml: switched to shell (+ansible_command_timeout), removed async/poll. • 04_system_config.yml: batch OCC calls (set -euo pipefail, /bin/bash), safer quoting, change detection via ' set to '. • 05_plugin.yml: disable task with stricter failed_when/changed_when (combine stdout+stderr). • 06_plugin_routines.yml: disable incompatible plugins in a single batch; no async_status; robust changed_when. • 07_plugin_enable_and_configure.yml: batch config:app:set, safe quoting, clear changed_when/failed_when. • config/main.yml & vars/main.yml: removed performance.async.wait_for and nextcloud_wait_for_async_enabled. --- roles/web-app-nextcloud/config/main.yml | 2 - .../tasks/02_add_missing_indices.yml | 20 +++----- .../tasks/04_system_config.yml | 43 ++++++---------- roles/web-app-nextcloud/tasks/05_plugin.yml | 11 ++-- .../tasks/06_plugin_routines.yml | 50 ++++++------------- .../tasks/07_plugin_enable_and_configure.yml | 47 ++++++----------- roles/web-app-nextcloud/vars/main.yml | 2 - 7 files changed, 60 insertions(+), 115 deletions(-) diff --git a/roles/web-app-nextcloud/config/main.yml b/roles/web-app-nextcloud/config/main.yml index 96b085ef..48083764 100644 --- a/roles/web-app-nextcloud/config/main.yml +++ b/roles/web-app-nextcloud/config/main.yml @@ -70,8 +70,6 @@ performance: memory_limit: "{{ ((ansible_memtotal_mb | int) / 30)|int }}M" # Dynamic set memory limit upload_limit: "5G" # Set upload limit to 5GB for big media files opcache_memory_consumption: "{{ ((ansible_memtotal_mb | int) / 30)|int }}M" # Dynamic set memory consumption - async: - wait_for: "{{ enable_debug }}" # If debug is enabled wait_for async jobs plugins_enabled: true # Implemented for speeding up testing and debugging process. For productive environments keep it true and steer the apps via the plugins config diff --git a/roles/web-app-nextcloud/tasks/02_add_missing_indices.yml b/roles/web-app-nextcloud/tasks/02_add_missing_indices.yml index 304fd65b..c158e96e 100644 --- a/roles/web-app-nextcloud/tasks/02_add_missing_indices.yml +++ b/roles/web-app-nextcloud/tasks/02_add_missing_indices.yml @@ -1,17 +1,13 @@ -- name: "Launch async: add missing DB indices in Nextcloud" - ansible.builtin.command: > +- name: "Add missing DB indices in Nextcloud (single run)" + ansible.builtin.shell: | + set -e {{ nextcloud_docker_exec_occ }} db:add-missing-indices - async: 3600 - poll: 0 - register: db_indices_job - -- name: "Wait for DB indices job" - ansible.builtin.async_status: - jid: "{{ db_indices_job.ansible_job_id }}" + args: + executable: /bin/bash + vars: + # Give the command enough time without async/poll overhead + ansible_command_timeout: 3600 register: db_indices_result - until: db_indices_result.finished - retries: 600 - delay: 1 failed_when: db_indices_result.rc != 0 changed_when: > ('Adding additional' in (db_indices_result.stdout | default(''))) or diff --git a/roles/web-app-nextcloud/tasks/04_system_config.yml b/roles/web-app-nextcloud/tasks/04_system_config.yml index 68215b3e..dfcef188 100644 --- a/roles/web-app-nextcloud/tasks/04_system_config.yml +++ b/roles/web-app-nextcloud/tasks/04_system_config.yml @@ -2,33 +2,18 @@ include_vars: file: system.yml -- name: "Launch async: apply Nextcloud system configs" - ansible.builtin.command: > - {{ nextcloud_docker_exec_occ }} - config:system:set {{ item.parameter }} - {% if item.type is defined %} --type {{ item.type }}{% endif %} - --value {{ item.value }} - loop: "{{ nextcloud_system_config }}" - loop_control: - label: "{{ item.parameter }}" - async: 300 - poll: 0 - register: syscfg_jobs - -- name: "Wait for system config jobs" - ansible.builtin.async_status: - jid: "{{ item.ansible_job_id }}" - loop: "{{ syscfg_jobs.results | default([]) }}" - loop_control: - label: "{{ item._ansible_item_label | default(item.item.parameter) }}" - register: syscfg_wait - until: syscfg_wait.finished - retries: 100 - delay: 1 - failed_when: > - (syscfg_wait.rc is defined and syscfg_wait.rc|int != 0) +- name: "Apply Nextcloud system configs (batched shell)" + ansible.builtin.shell: | + set -euo pipefail + {% for item in nextcloud_system_config %} + {{ nextcloud_docker_exec_occ }} \ + config:system:set {{ item.parameter }}{% if item.type is defined %} --type {{ item.type }}{% endif %} \ + --value '{{ (item.value | string) | regex_replace("'", "'" ~ '"' ~ "'" ~ '"' ~ "'") }}' + {% endfor %} + args: + executable: /bin/bash + register: syscfg_shell changed_when: > - (syscfg_wait.stdout is defined) and - ("Value not changed" not in syscfg_wait.stdout) - when: - - nextcloud_wait_for_async_enabled | bool + ( ((syscfg_shell.stdout | default('')) ~ (syscfg_shell.stderr | default(''))) + is search(' set to ') ) + failed_when: syscfg_shell.rc != 0 diff --git a/roles/web-app-nextcloud/tasks/05_plugin.yml b/roles/web-app-nextcloud/tasks/05_plugin.yml index c9b5883b..ed083088 100644 --- a/roles/web-app-nextcloud/tasks/05_plugin.yml +++ b/roles/web-app-nextcloud/tasks/05_plugin.yml @@ -3,7 +3,12 @@ when: plugin_value.enabled | bool - name: disable {{ plugin_key }} nextcloud plugin - command: "{{nextcloud_docker_exec_occ}} app:disable {{ plugin_key }}" + command: "{{ nextcloud_docker_exec_occ }} app:disable {{ plugin_key }}" register: disable_result - changed_when: disable_result.rc == 0 and ("No such app enabled" not in disable_result.stdout) - when: not (plugin_value.enabled | bool) \ No newline at end of file + failed_when: > + (disable_result.rc | int != 0) + and ('No such app enabled' not in (disable_result.stdout | default('') ~ disable_result.stderr | default(''))) + changed_when: > + ((disable_result.stdout | default('') ~ disable_result.stderr | default('')) is search('disabled')) + and (((disable_result.stdout | default('') ~ disable_result.stderr | default('')) is not search('already disabled'))) + when: not (plugin_value.enabled | bool) diff --git a/roles/web-app-nextcloud/tasks/06_plugin_routines.yml b/roles/web-app-nextcloud/tasks/06_plugin_routines.yml index 4d486763..2e707277 100644 --- a/roles/web-app-nextcloud/tasks/06_plugin_routines.yml +++ b/roles/web-app-nextcloud/tasks/06_plugin_routines.yml @@ -1,41 +1,23 @@ -# roles/web-app-nextcloud/tasks/06_plugin_routines.yml -- name: "Launch async: disable incompatible plugins for {{ plugin_key }}" - ansible.builtin.command: "{{ nextcloud_docker_exec_occ }} app:disable {{ incompatible_plugin }}" - loop: "{{ plugin_value.incompatible_plugins }}" - loop_control: - loop_var: incompatible_plugin - label: "{{ incompatible_plugin }}" +- name: "Disable incompatible plugins for {{ plugin_key }} (batched shell, no async)" + ansible.builtin.shell: | + # do not set -e here; allow per-line fallbacks + {% for incompatible_plugin in (plugin_value.incompatible_plugins | default([])) %} + {{ nextcloud_docker_exec_occ }} app:disable {{ incompatible_plugin }} || true + {% endfor %} + args: + executable: /bin/bash when: - plugin_value.incompatible_plugins is defined - plugin_value.incompatible_plugins | length > 0 - async: 180 - poll: 0 - register: disable_incompat_jobs - -- name: "Wait for disable jobs" - vars: - jobs_with_id: >- - {{ (disable_incompat_jobs.results | default([])) - | selectattr('ansible_job_id','defined') - | list }} - ansible.builtin.async_status: - jid: "{{ item.ansible_job_id }}" - loop: "{{ jobs_with_id }}" - loop_control: - label: "{{ item._ansible_item_label }}" - register: disable_incompat_wait - until: disable_incompat_wait.finished - retries: 100 - delay: 1 - when: - - jobs_with_id | length > 0 - - nextcloud_wait_for_async_enabled | bool - failed_when: > - (disable_incompat_wait.rc is defined and disable_incompat_wait.rc|int != 0) - and ('No such app enabled' not in (disable_incompat_wait.stdout | default(''))) + register: disable_incompat changed_when: > - (disable_incompat_wait.rc | default(0) | int == 0) - and ('No such app enabled' not in (disable_incompat_wait.stdout | default(''))) + (((disable_incompat.stdout | default('')) ~ (disable_incompat.stderr | default(''))) + is search('disabled')) + and ( + (((disable_incompat.stdout | default('')) ~ (disable_incompat.stderr | default(''))) + is not search('already disabled')) + ) + failed_when: false - name: install {{ plugin_key }} nextcloud plugin command: "{{ nextcloud_docker_exec_occ }} app:install {{ plugin_key }}" diff --git a/roles/web-app-nextcloud/tasks/07_plugin_enable_and_configure.yml b/roles/web-app-nextcloud/tasks/07_plugin_enable_and_configure.yml index 199c3b09..230d1afb 100644 --- a/roles/web-app-nextcloud/tasks/07_plugin_enable_and_configure.yml +++ b/roles/web-app-nextcloud/tasks/07_plugin_enable_and_configure.yml @@ -15,41 +15,22 @@ file: "{{nextcloud_control_node_plugin_vars_directory}}{{ plugin_key }}.yml" when: plugin_vars_file.stat.exists -- name: "Launch async: set {{ item.configkey }} for {{ item.appid }}" - ansible.builtin.command: > - {{ nextcloud_docker_exec_occ }} config:app:set {{ item.appid }} {{ item.configkey }} - --value '{{ item.configvalue | to_json if item.configvalue is mapping else item.configvalue }}' - loop: "{{ plugin_configuration }}" - loop_control: - label: "{{ item.appid }}:{{ item.configkey }}" +- name: "Set plugin configuration (batched shell, no async)" + ansible.builtin.shell: | + set -euo pipefail + {% for item in (plugin_configuration | default([])) %} + {{ nextcloud_docker_exec_occ }} \ + config:app:set {{ item.appid }} {{ item.configkey }} \ + --value '{{ ( (item.configvalue | to_json) if (item.configvalue is mapping) else (item.configvalue | string) ) + | regex_replace("'", "'" ~ '"' ~ "'" ~ '"' ~ "'") }}' + {% endfor %} + args: + executable: /bin/bash when: plugin_vars_file.stat.exists - async: 300 # max runtime per call (seconds) — adjust as needed - poll: 0 # don't wait; run in background - register: config_set_jobs - -- name: "Wait for async jobs" - vars: - jobs_with_id: >- - {{ (config_set_jobs.results | default([])) - | selectattr('ansible_job_id','defined') - | list }} - ansible.builtin.async_status: - jid: "{{ item.ansible_job_id }}" - register: config_set_wait - until: config_set_wait.finished - retries: 100 - delay: 1 - loop: "{{ jobs_with_id }}" - loop_control: - label: "{{ item._ansible_item_label | default(item.item.appid ~ ':' ~ item.item.configkey) }}" - when: - - jobs_with_id | length > 0 - - nextcloud_wait_for_async_enabled | bool - failed_when: > - (config_set_wait.rc is defined and config_set_wait.rc|int != 0) + register: config_set_shell changed_when: > - (config_set_wait.stdout is defined) and - ("Config value were not updated" not in config_set_wait.stdout) + (config_set_shell.stdout | default('')) is search(' set to ') + failed_when: config_set_shell.rc != 0 - name: Check if {{nextcloud_control_node_plugin_tasks_directory}}{{ plugin_key }}.yml exists stat: diff --git a/roles/web-app-nextcloud/vars/main.yml b/roles/web-app-nextcloud/vars/main.yml index c910fd53..656babab 100644 --- a/roles/web-app-nextcloud/vars/main.yml +++ b/roles/web-app-nextcloud/vars/main.yml @@ -11,8 +11,6 @@ http_port: "{{ ports.localhost.http[applica database_password: "{{ applications | get_app_conf(application_id, 'credentials.database_password', True)}}" database_type: "mariadb" # Database flavor -nextcloud_wait_for_async_enabled: "{{applications | get_app_conf(application_id, 'performance.async.wait_for')}}" - nextcloud_plugins_enabled: "{{ applications | get_app_conf(application_id, 'plugins_enabled', True) }}" nextcloud_administrator_username: "{{ applications | get_app_conf(application_id, 'users.administrator.username', True) }}"