--- # UNE APPLICATION NEXTCLOUD, SANS L'APP STORE (2026-10-08) — voir `serveur_nextcloud_apps`. # # entree : serveur_nextcloud_app_id (user_oidc, richdocuments) # # Le depot du SITE d'abord, l'amont ensuite (meme patron que l'archive de Nextcloud, # `installer.yml`) ; la somme verifiee dans les deux cas ; puis la signature du code ; puis # l'activation. Une version installee qui differe de l'epinglee ARRETE : une mise a niveau # d'application est une decision (et un `occ upgrade`), pas un effet de bord. - name: "Application Nextcloud — l'application epinglee ({{ serveur_nextcloud_app_id }})" ansible.builtin.set_fact: serveur_nextcloud_app: >- {{ serveur_nextcloud_apps | selectattr('id', 'equalto', serveur_nextcloud_app_id) | first }} - name: "Application Nextcloud — deja presente ? ({{ serveur_nextcloud_app_id }})" ansible.builtin.slurp: src: "{{ serveur_nextcloud_racine }}/apps/{{ serveur_nextcloud_app.id }}/appinfo/info.xml" register: serveur_nextcloud_app_info failed_when: false - name: "Application Nextcloud — la version presente est-elle l'epinglee ? ({{ serveur_nextcloud_app_id }})" vars: presente: >- {{ (serveur_nextcloud_app_info.content | b64decode | regex_search('([^<]+)', '\\1') | default([''], true) | first) if serveur_nextcloud_app_info.content is defined else '' }} ansible.builtin.assert: that: - presente | length == 0 or presente == serveur_nextcloud_app.version fail_msg: >- {{ serveur_nextcloud_app.id }} {{ presente }} est installee, {{ serveur_nextcloud_app.version }} est epinglee. Une mise a niveau d'application se decide (et passe par `occ upgrade`) : ajuster `serveur_nextcloud_apps`, ou mettre a niveau a la main. quiet: true - name: "Application Nextcloud — l'obtenir et la deposer ({{ serveur_nextcloud_app_id }})" when: serveur_nextcloud_app_info.content is not defined block: - name: "Application Nextcloud — le cache du controleur ({{ serveur_nextcloud_app_id }})" ansible.builtin.file: path: "{{ serveur_nextcloud_cache_local }}" state: directory mode: "0700" delegate_to: localhost become: false # `failed_when: false` : le depot est une COMMODITE ; sans lui, on retombe sur l'amont. # La somme est verifiee ici aussi : un fichier altere chez le site ne passe pas. - name: "Application Nextcloud — au depot du site, avant de sortir sur Internet ({{ serveur_nextcloud_app_id }})" ansible.builtin.get_url: url: "{{ setops_depot_binaires }}/{{ serveur_nextcloud_app.nom }}" dest: "{{ serveur_nextcloud_cache_local }}/{{ serveur_nextcloud_app.nom }}" checksum: "sha256:{{ serveur_nextcloud_app.sha256 }}" mode: "0644" timeout: 30 delegate_to: localhost become: false register: serveur_nextcloud_app_site failed_when: false when: setops_depot_binaires | default('') | length > 0 - name: "Application Nextcloud — dans le cache du controleur ? ({{ serveur_nextcloud_app_id }})" ansible.builtin.stat: path: "{{ serveur_nextcloud_cache_local }}/{{ serveur_nextcloud_app.nom }}" checksum_algorithm: sha256 register: serveur_nextcloud_app_cache delegate_to: localhost become: false # ON LE DIT, FORT : une reconstruction qui sort sur Internet doit se voir. - name: "Application Nextcloud — absente du depot du site : prise en amont ({{ serveur_nextcloud_app_id }})" ansible.builtin.debug: msg: >- {{ serveur_nextcloud_app.nom }} n'est pas au depot du site ({{ setops_depot_binaires | default('aucun depot declare') }}) : prise sur Internet. when: not (serveur_nextcloud_app_cache.stat.exists and serveur_nextcloud_app_cache.stat.checksum == serveur_nextcloud_app.sha256) - name: "Application Nextcloud — en amont (repli) ({{ serveur_nextcloud_app_id }})" ansible.builtin.get_url: url: "{{ serveur_nextcloud_app.url }}" dest: "{{ serveur_nextcloud_cache_local }}/{{ serveur_nextcloud_app.nom }}" checksum: "sha256:{{ serveur_nextcloud_app.sha256 }}" mode: "0644" timeout: 60 delegate_to: localhost become: false when: not (serveur_nextcloud_app_cache.stat.exists and serveur_nextcloud_app_cache.stat.checksum == serveur_nextcloud_app.sha256) - name: "Application Nextcloud — deposer le code dans apps/ ({{ serveur_nextcloud_app_id }})" ansible.builtin.unarchive: src: "{{ serveur_nextcloud_cache_local }}/{{ serveur_nextcloud_app.nom }}" dest: "{{ serveur_nextcloud_racine }}/apps" owner: "{{ serveur_nextcloud_utilisateur }}" group: "{{ serveur_nextcloud_utilisateur }}" creates: "{{ serveur_nextcloud_racine }}/apps/{{ serveur_nextcloud_app.id }}/appinfo/info.xml" - name: "Application Nextcloud — signature du code, puis activation ({{ serveur_nextcloud_app_id }})" become: true become_user: "{{ serveur_nextcloud_utilisateur }}" environment: PGSSLMODE: "{{ serveur_nextcloud_pg_sslmode }}" PGSSLROOTCERT: "{{ serveur_nextcloud_ca_racine }}" when: not ansible_check_mode block: # Contre l'autorite de signature de Nextcloud, sans reseau. Rien a dire = intact. - name: "Application Nextcloud — le code est-il celui que Nextcloud a signe ? ({{ serveur_nextcloud_app_id }})" ansible.builtin.command: argv: ["php", "{{ serveur_nextcloud_racine }}/occ", "integrity:check-app", "{{ serveur_nextcloud_app.id }}"] register: serveur_nextcloud_app_integrite changed_when: false failed_when: serveur_nextcloud_app_integrite.rc != 0 or serveur_nextcloud_app_integrite.stdout | trim | length > 0 - name: "Application Nextcloud — activer ({{ serveur_nextcloud_app_id }})" ansible.builtin.shell: executable: /bin/bash cmd: | set -eo pipefail OCC="php {{ serveur_nextcloud_racine }}/occ" APP="{{ serveur_nextcloud_app.id }}" if $OCC app:list --enabled | grep -qw "$APP"; then echo SETOPS_OK else $OCC app:enable "$APP" && echo SETOPS_CHANGED; fi register: serveur_nextcloud_app_active changed_when: "'SETOPS_CHANGED' in serveur_nextcloud_app_active.stdout"