--- # MONTER NEXTCLOUD D'UNE VERSION A UNE AUTRE (2026-10-03). # # Le role savait INSTALLER, pas monter : l'extraction portait `creates: occ`, et une machine # deja installee gardait son code quelle que soit la version demandee. Cette procedure suit # la mise a jour manuelle documentee par Nextcloud : # # maintenance ON -> ancien code mis de cote -> nouveau code extrait -> on y ramene # `data/` (qui vit DANS le code chez nous), la configuration, et tout ce que l'ancien # repertoire portait EN PLUS de la livraison (applications ajoutees, theme, logo) -> # `occ upgrade` -> php-fpm recharge -> maintenance OFF. # # L'ANCIEN CODE RESTE, sous `-` : c'est le retour arriere. Le retirer est un # geste humain, une fois la nouvelle version eprouvee. # # REFUSE : une RETROGRADATION (Nextcloud ne sait pas descendre), et un SAUT de branche # (34 -> 36 interdit : il faut passer par 35). - name: Montée — Nextcloud est-il déjà installé ? ansible.builtin.stat: path: "{{ serveur_nextcloud_racine }}/occ" register: serveur_nextcloud_occ_present - name: Montée — quelle version est en place ? ansible.builtin.command: argv: [php, "{{ serveur_nextcloud_racine }}/occ", status, --output=json] become: true become_user: "{{ serveur_nextcloud_utilisateur }}" register: serveur_nextcloud_statut changed_when: false check_mode: false when: serveur_nextcloud_occ_present.stat.exists - name: Montée — comparer à la version demandée ansible.builtin.set_fact: serveur_nextcloud_en_place: >- {{ (serveur_nextcloud_statut.stdout | from_json).versionstring if (serveur_nextcloud_occ_present.stat.exists and serveur_nextcloud_statut.rc | default(1) == 0) else '' }} - name: Montée — décider ansible.builtin.set_fact: serveur_nextcloud_a_monter: >- {{ serveur_nextcloud_en_place | length > 0 and serveur_nextcloud_en_place != serveur_nextcloud_version }} - name: Montée — refuser une rétrogradation ou un saut de branche ansible.builtin.assert: that: - serveur_nextcloud_version is version(serveur_nextcloud_en_place, '>') - (serveur_nextcloud_version.split('.')[0] | int) - (serveur_nextcloud_en_place.split('.')[0] | int) <= 1 fail_msg: >- Nextcloud {{ serveur_nextcloud_en_place }} en place, {{ serveur_nextcloud_version }} demandé. Nextcloud ne rétrograde pas, et ne saute pas de branche : monter d'une branche à la fois (34 -> 35 -> 36). when: serveur_nextcloud_a_monter | bool - name: Montée — remplacer le code et mettre à jour la base when: - serveur_nextcloud_a_monter | bool - not ansible_check_mode vars: serveur_nextcloud_ancien: "{{ serveur_nextcloud_racine }}-{{ serveur_nextcloud_en_place }}" block: - name: Montée — le répertoire de l'ancienne version est-il libre ? ansible.builtin.stat: path: "{{ serveur_nextcloud_ancien }}" register: serveur_nextcloud_ancien_present - name: Montée — refuser d'écraser un ancien code déjà mis de côté ansible.builtin.assert: that: - not serveur_nextcloud_ancien_present.stat.exists fail_msg: >- {{ serveur_nextcloud_ancien }} existe déjà : une montée précédente l'a laissé. Le vérifier, puis le retirer à la main avant de recommencer. - name: Montée — passer en maintenance ansible.builtin.command: argv: [php, "{{ serveur_nextcloud_racine }}/occ", maintenance:mode, --on] become: true become_user: "{{ serveur_nextcloud_utilisateur }}" changed_when: true - name: Montée — mettre l'ancien code de côté ansible.builtin.command: argv: [mv, "{{ serveur_nextcloud_racine }}", "{{ serveur_nextcloud_ancien }}"] changed_when: true - name: Montée — extraire la nouvelle version ansible.builtin.unarchive: src: "/tmp/nextcloud-{{ serveur_nextcloud_version }}.tar.bz2" dest: "/var/www/" remote_src: true owner: "{{ serveur_nextcloud_utilisateur }}" group: "{{ serveur_nextcloud_utilisateur }}" # `data/` DANS le code (defaut du role) : on la DEPLACE, on ne la copie pas — meme # systeme de fichiers, un renommage, quelle que soit sa taille. - name: Montée — ramener les données ansible.builtin.command: argv: - mv - "{{ serveur_nextcloud_ancien }}/{{ serveur_nextcloud_data_dir | relpath(serveur_nextcloud_racine) }}" - "{{ serveur_nextcloud_data_dir }}" changed_when: true when: serveur_nextcloud_data_dir.startswith(serveur_nextcloud_racine ~ '/') # LA CONFIGURATION, PUIS TOUT CE QUE LA LIVRAISON N'APPORTE PAS — a la racine, dans # `apps/` et dans `themes/`. On ne remplace rien de livre : seul ce qui MANQUE est repris # (applications installees, theme de l'organisation, logo pose a la racine). - name: Montée — reprendre la configuration et ce que la livraison n'apporte pas ansible.builtin.shell: | set -euo pipefail A="{{ serveur_nextcloud_ancien }}"; N="{{ serveur_nextcloud_racine }}" cp -a "$A/config/." "$N/config/" for d in . apps themes; do [ -d "$A/$d" ] || continue for e in "$A/$d"/* "$A/$d"/.[!.]*; do [ -e "$e" ] || continue b=$(basename "$e") if [ "$d" = . ] && [ "$b" = "{{ serveur_nextcloud_data_dir | basename }}" ]; then continue; fi if [ ! -e "$N/$d/$b" ]; then cp -a "$e" "$N/$d/"; echo "repris : $d/$b"; fi done done args: executable: /bin/bash register: serveur_nextcloud_repris changed_when: true - name: Montée — mettre à jour la base (occ upgrade) ansible.builtin.command: argv: [php, "{{ serveur_nextcloud_racine }}/occ", upgrade, --no-interaction] become: true become_user: "{{ serveur_nextcloud_utilisateur }}" environment: PGSSLMODE: "{{ serveur_nextcloud_pg_sslmode }}" PGSSLROOTCERT: "{{ serveur_nextcloud_ca_racine }}" register: serveur_nextcloud_upgrade changed_when: true # php-fpm revalide son cache d'opcodes toutes les 60 s (`opcache.revalidate_freq`) : # sans rechargement, la premiere minute servirait l'ancien code compile. - name: Montée — recharger php-fpm (cache d'opcodes) ansible.builtin.systemd: name: "php{{ serveur_nextcloud_php_version }}-fpm" state: reloaded - name: Montée — sortir de maintenance ansible.builtin.command: argv: [php, "{{ serveur_nextcloud_racine }}/occ", maintenance:mode, --off] become: true become_user: "{{ serveur_nextcloud_utilisateur }}" changed_when: true - name: Montée — ce qui a été repris de l'ancienne version ansible.builtin.debug: msg: >- Nextcloud {{ serveur_nextcloud_en_place }} -> {{ serveur_nextcloud_version }}. Repris : {{ serveur_nextcloud_repris.stdout_lines | default([]) | join(', ') or 'rien' }}. Ancien code gardé dans {{ serveur_nextcloud_ancien }} (retour arrière). # SI UNE ETAPE ECHOUE, ON DIT COMMENT REVENIR — et on ne devine pas a la place de # l'exploitant : Nextcloud reste en maintenance, l'ancien code et les donnees sont intacts. rescue: - name: Montée — échec ; dire comment revenir en arrière ansible.builtin.fail: msg: >- La montée de Nextcloud {{ serveur_nextcloud_en_place }} -> {{ serveur_nextcloud_version }} a échoué à « {{ ansible_failed_task.name | default('?') }} ». Nextcloud est en maintenance. Retour arrière, sur l'hôte : (1) si {{ serveur_nextcloud_racine }}/data existe, `mv {{ serveur_nextcloud_racine }}/data {{ serveur_nextcloud_ancien }}/` ; (2) `mv {{ serveur_nextcloud_racine }} {{ serveur_nextcloud_racine }}-echec-{{ serveur_nextcloud_version }}` puis `mv {{ serveur_nextcloud_ancien }} {{ serveur_nextcloud_racine }}` ; (3) `sudo -u {{ serveur_nextcloud_utilisateur }} php {{ serveur_nextcloud_racine }}/occ maintenance:mode --off`. Si `occ upgrade` a déjà modifié la base, restaurer aussi la base (setops-restaurer).