From 17c1b4311635239aa446be8da575865cf9f5406a Mon Sep 17 00:00:00 2001 From: "martin.fencl" Date: Wed, 24 Dec 2025 00:54:52 +0100 Subject: [PATCH] edit --- nextcloud/update_nextcloud_v2.yml | 319 ++++++++++-------------------- 1 file changed, 109 insertions(+), 210 deletions(-) diff --git a/nextcloud/update_nextcloud_v2.yml b/nextcloud/update_nextcloud_v2.yml index 3a7cf73..e39143f 100644 --- a/nextcloud/update_nextcloud_v2.yml +++ b/nextcloud/update_nextcloud_v2.yml @@ -1,7 +1,7 @@ # nextcloud/update_nextcloud.yml - name: Update Nextcloud on VM via Proxmox - hosts: proxmox_nextcloud + hosts: proxmox_nextcloud # linux_servers gather_facts: false become: true become_user: root @@ -31,20 +31,7 @@ # Docker command prefix (consistent behavior and quiet hints) docker_prefix: "unalias docker 2>/dev/null || true; DOCKER_CLI_HINTS=0; command docker" - - # SSH argv base (always run remote command via bash -lc) - ssh_argv_base: - - sshpass - - -e - - ssh - - -o - - StrictHostKeyChecking=no - - -o - - ConnectTimeout=15 - - "{{ vm_user }}@{{ vm_ip }}" - - bash - - -lc - + # --- Backup phase commands (run on VM) --- nextcloud_backup_commands: - >- @@ -60,6 +47,23 @@ - >- {{ docker_prefix }} exec nextcloud-db sh -c 'command -v mariadb-dump >/dev/null && mariadb-dump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" || mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' > "{{ backup_dir }}/db.sql" + # --- Upgrade phase commands (run on VM) --- + nextcloud_upgrade_commands: + - >- + {{ docker_prefix }} compose -p {{ nextcloud_project }} -f {{ nextcloud_compose_file }} pull {{ nextcloud_service }} + - >- + {{ docker_prefix }} compose -p {{ nextcloud_project }} -f {{ nextcloud_compose_file }} up -d --no-deps --force-recreate {{ nextcloud_service }} + - >- + {{ docker_prefix }} exec -u www-data nextcloud php occ maintenance:mode --off + - >- + {{ docker_prefix }} exec -u www-data nextcloud php occ upgrade + - >- + {{ docker_prefix }} exec -u www-data nextcloud php occ app:update --all || true + - >- + {{ docker_prefix }} exec -u www-data nextcloud php occ maintenance:repair --include-expensive || true + - >- + {{ docker_prefix }} exec -u www-data nextcloud php occ maintenance:mode --on + tasks: - name: Ensure sshpass is installed (for password-based SSH) ansible.builtin.apt: @@ -69,29 +73,40 @@ - name: Nextcloud | Show current version before upgrade (DEBUG) ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ -V || true' ] - }} + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - bash + - -lc + - 'docker exec -u www-data nextcloud php occ -V || true' environment: SSHPASS: "{{ vm_pass }}" register: nc_version_before changed_when: false failed_when: false when: DEBUG == 1 - no_log: "{{ DEBUG == 0 }}" # ------------------------- # Backup phase # ------------------------- - - name: Nextcloud | Run backup commands on VM (via SSH) + - name: Nextcloud | Run backup commands on VM (via SSH) # run plain commands via SSH ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ ((use_sudo | bool) | ternary('sudo -n ' ~ item, item)) ] - }} + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - "{{ ('sudo ' if use_sudo else '') + item }}" environment: SSHPASS: "{{ vm_pass }}" loop: "{{ nextcloud_backup_commands }}" @@ -100,7 +115,6 @@ label: "backup-cmd-{{ idx }}" register: nc_backup_cmds changed_when: false - failed_when: false no_log: "{{ DEBUG == 0 }}" - name: Nextcloud | Show outputs of backup commands (DEBUG) @@ -126,208 +140,78 @@ label: "backup-cmd-{{ idx }}" # ------------------------- - # Upgrade phase (robust) + # Upgrade phase # ------------------------- - - name: Nextcloud | Pull image + + - name: Nextcloud | Run upgrade commands on VM (via SSH) ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' compose -p ' ~ nextcloud_project ~ ' -f ' ~ nextcloud_compose_file ~ ' pull ' ~ nextcloud_service ] - }} + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - bash + - -lc + - "{{ ('sudo ' if use_sudo else '') + item }}" environment: SSHPASS: "{{ vm_pass }}" - register: nc_pull + loop: "{{ nextcloud_upgrade_commands }}" + loop_control: + index_var: idx + label: "upgrade-cmd-{{ idx }}" + register: nc_upgrade_cmds changed_when: false failed_when: false no_log: "{{ DEBUG == 0 }}" - - name: Nextcloud | Recreate service - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' compose -p ' ~ nextcloud_project ~ ' -f ' ~ nextcloud_compose_file ~ ' up -d --no-deps --force-recreate ' ~ nextcloud_service ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_up - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Ensure maintenance mode is OFF before occ upgrade - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ maintenance:mode --off || true' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_maint_off_before_upgrade - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | occ upgrade (attempt 1) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ upgrade' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_upgrade_1 - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Remediation if occ upgrade complains about maintenance/upgrade-in-progress - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ item ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - loop: - # Force-disable maintenance flag in config.php (works even if maintenance command is blocked) - - >- - {{ docker_prefix }} exec -u www-data nextcloud php occ config:system:set maintenance --type=boolean --value=false || true - # Repair can move stale updater step files and clear related state - - >- - {{ docker_prefix }} exec -u www-data nextcloud php occ maintenance:repair || true - # Ensure maintenance is off before retry - - >- - {{ docker_prefix }} exec -u www-data nextcloud php occ maintenance:mode --off || true - register: nc_remediate - changed_when: false - failed_when: false - when: >- - nc_upgrade_1.rc != 0 and ( - ('Maybe an upgrade is already in process' in (nc_upgrade_1.stdout | default(''))) or - ('Maybe an upgrade is already in process' in (nc_upgrade_1.stderr | default(''))) or - ('Nextcloud is in maintenance mode' in (nc_upgrade_1.stdout | default(''))) or - ('Nextcloud is in maintenance mode' in (nc_upgrade_1.stderr | default(''))) - ) - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | occ upgrade (attempt 2 after remediation) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ upgrade' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_upgrade_2 - changed_when: false - failed_when: false - when: nc_upgrade_1.rc != 0 - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Decide final upgrade result - ansible.builtin.set_fact: - nc_upgrade_final: "{{ (nc_upgrade_2 if (nc_upgrade_2 is defined) else nc_upgrade_1) }}" - - - name: Nextcloud | Show occ upgrade output (DEBUG) + - name: Nextcloud | Show outputs of upgrade commands (DEBUG) ansible.builtin.debug: msg: | - RC: {{ nc_upgrade_final.rc }} + CMD: {{ item.item }} + RC: {{ item.rc }} STDOUT: - {{ (nc_upgrade_final.stdout | default('')).strip() }} + {{ (item.stdout | default('')).strip() }} STDERR: - {{ (nc_upgrade_final.stderr | default('')).strip() }} + {{ (item.stderr | default('')).strip() }} + loop: "{{ nc_upgrade_cmds.results }}" when: DEBUG == 1 - - name: Nextcloud | Fail if occ upgrade did not succeed + - name: Nextcloud | Fail play if any upgrade command failed ansible.builtin.assert: - that: - - nc_upgrade_final.rc == 0 - fail_msg: >- - Nextcloud occ upgrade failed (rc={{ nc_upgrade_final.rc }}). - stdout={{ (nc_upgrade_final.stdout | default('') | trim) }} - stderr={{ (nc_upgrade_final.stderr | default('') | trim) }} + that: "item.rc == 0" + fail_msg: "Nextcloud upgrade step failed on VM: {{ item.item }} (rc={{ item.rc }})" + success_msg: "All Nextcloud upgrade commands succeeded." + loop: "{{ nc_upgrade_cmds.results }}" + loop_control: + index_var: idx + label: "upgrade-cmd-{{ idx }}" - # Keep the rest under maintenance mode to avoid user activity during app updates/repairs - - name: Nextcloud | Enable maintenance mode for post-upgrade steps + - name: Nextcloud | Disable maintenance mode (only after successful upgrade) ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ maintenance:mode --on' ] - }} + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - "{{ ('sudo ' if use_sudo else '') }}docker exec -u www-data nextcloud php occ maintenance:mode --off" environment: SSHPASS: "{{ vm_pass }}" - register: nc_maint_on_post + register: nc_maint_off changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Update apps (best-effort) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ app:update --all || true' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_app_update - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Run maintenance repair (include expensive) (best-effort) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ maintenance:repair --include-expensive || true' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_repair - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Disable maintenance mode (end) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ maintenance:mode --off' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_maint_off_end - changed_when: false - failed_when: false - no_log: "{{ DEBUG == 0 }}" - - - name: Nextcloud | Show current version after upgrade (DEBUG) - ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ docker_prefix ~ ' exec -u www-data nextcloud php occ -V || true' ] - }} - environment: - SSHPASS: "{{ vm_pass }}" - register: nc_version_after - changed_when: false - failed_when: false - when: DEBUG == 1 no_log: "{{ DEBUG == 0 }}" # ------------------------- # Readiness check (status.php) # ------------------------- + - name: Nextcloud | Wait for status.php (controller first) ansible.builtin.uri: url: "{{ nextcloud_status_url }}" @@ -346,11 +230,26 @@ - name: Nextcloud | VM-side fetch status.php (JSON via Python) ansible.builtin.command: - argv: >- - {{ - ssh_argv_base - + [ "python3 - <<'PY'\nimport sys, urllib.request\ntry:\n with urllib.request.urlopen(\"" ~ nextcloud_status_url ~ "\", timeout=15) as r:\n sys.stdout.write(r.read().decode())\nexcept Exception:\n pass\nPY" ] - }} + argv: + - sshpass + - -e + - ssh + - -o + - StrictHostKeyChecking=no + - -o + - ConnectTimeout=15 + - "{{ vm_user }}@{{ vm_ip }}" + - bash + - -lc + - | + python3 - <<'PY' + import json, urllib.request, sys + try: + with urllib.request.urlopen("{{ nextcloud_status_url }}", timeout=15) as r: + sys.stdout.write(r.read().decode()) + except Exception: + pass + PY environment: SSHPASS: "{{ vm_pass }}" register: nc_status_vm