diff --git a/synology_upgrade_ssh.yml b/synology_upgrade_ssh.yml new file mode 100644 index 0000000..8a84131 --- /dev/null +++ b/synology_upgrade_ssh.yml @@ -0,0 +1,146 @@ +--- +- name: Synology DSM - télécharger puis installer une mise à jour via SSH (synoupgrade) + hosts: synology + gather_facts: false + + vars: + # Chemin habituel sur Synology + synoupgrade_bin: "/usr/syno/sbin/synoupgrade" + + # Temps max (en secondes) pour attendre download / reboot + download_timeout: 3600 + reboot_timeout: 1200 + poll_delay: 20 + + # Certaines versions DSM n'ont pas exactement les mêmes options, + # on essaie plusieurs commandes possibles pour démarrer l'upgrade. + upgrade_start_cmds: + - "{{ synoupgrade_bin }} --start" + - "{{ synoupgrade_bin }} --upgrade" + - "{{ synoupgrade_bin }} --apply" + - "{{ synoupgrade_bin }} --run" + - "{{ synoupgrade_bin }} --install" + + tasks: + - name: Vérifier que synoupgrade existe + ansible.builtin.raw: "test -x {{ synoupgrade_bin }} && echo OK || echo MISSING" + register: synoupgrade_exists + changed_when: false + failed_when: "'MISSING' in synoupgrade_exists.stdout" + + - name: Check mise à jour disponible (synoupgrade --check) + ansible.builtin.raw: "{{ synoupgrade_bin }} --check || true" + register: check_out + changed_when: false + + - name: Afficher le résultat du check + ansible.builtin.debug: + var: check_out.stdout_lines + + # Heuristique : si "no update" / "no newer version" etc, on stop proprement. + - name: Stop si aucune mise à jour détectée (heuristique) + ansible.builtin.meta: end_play + when: > + (check_out.stdout | lower) is search('no update') + or (check_out.stdout | lower) is search('no newer') + or (check_out.stdout | lower) is search('already up') + or (check_out.stdout | lower) is search('up to date') + + - name: Lancer le téléchargement (synoupgrade --download) + ansible.builtin.raw: "{{ synoupgrade_bin }} --download" + register: download_start + changed_when: true + + - name: Afficher retour download start + ansible.builtin.debug: + var: download_start.stdout_lines + + # Suivi du téléchargement : selon DSM, --status peut exister ou pas. + # On fait un poll best-effort sur --status, sinon on se base sur le log. + - name: Attendre fin du téléchargement (poll status/log) + ansible.builtin.raw: | + set -e + if {{ synoupgrade_bin }} --status >/dev/null 2>&1; then + {{ synoupgrade_bin }} --status || true + else + # fallback log courant (chemins variables selon DSM) + (tail -n 60 /var/log/synoupgrade.log 2>/dev/null || true) + (tail -n 60 /var/log/messages 2>/dev/null | grep -i synoupgrade || true) + fi + register: dl_poll + changed_when: false + until: > + (dl_poll.stdout | lower) is search('downloaded') + or (dl_poll.stdout | lower) is search('ready') + or (dl_poll.stdout | lower) is search('finish') + or (dl_poll.stdout | lower) is search('completed') + or (dl_poll.stdout | lower) is search('done') + retries: "{{ (download_timeout // poll_delay) | int }}" + delay: "{{ poll_delay }}" + + - name: Afficher statut fin téléchargement + ansible.builtin.debug: + var: dl_poll.stdout_lines + + # Démarrage de l'upgrade : on teste plusieurs commandes. + - name: Démarrer l'installation DSM (essais multi-commandes) + ansible.builtin.raw: "{{ item }}" + loop: "{{ upgrade_start_cmds }}" + register: start_attempts + changed_when: true + failed_when: false + + - name: Choisir la première commande start qui a l'air OK + ansible.builtin.set_fact: + start_ok: >- + {{ + (start_attempts.results + | rejectattr('stdout', 'search', '(?i)(invalid|unknown|usage|not found|error)') + | list + | first) | default({}) + }} + + - name: Fail si aucune commande start ne fonctionne + ansible.builtin.fail: + msg: >- + Impossible de démarrer l'installation via synoupgrade. + Sorties: + {{ start_attempts.results | map(attribute='stdout') | list }} + when: start_ok | length == 0 + + - name: Afficher la commande start retenue + ansible.builtin.debug: + msg: + - "Commande retenue: {{ start_ok.item }}" + - "stdout: {{ start_ok.stdout | default('') }}" + - "stderr: {{ start_ok.stderr | default('') }}" + + # Beaucoup de Synology rebootent pendant/après l’upgrade. + # On attend que SSH tombe puis revienne. + - name: Attendre que le NAS coupe SSH (reboot en cours) + ansible.builtin.wait_for: + host: "{{ inventory_hostname }}" + port: 22 + state: drained + timeout: 300 + delegate_to: localhost + + - name: Attendre le retour SSH (après reboot) + ansible.builtin.wait_for: + host: "{{ inventory_hostname }}" + port: 22 + state: started + timeout: "{{ reboot_timeout }}" + delegate_to: localhost + + - name: Re-check version / statut après reboot (best effort) + ansible.builtin.raw: | + uname -a || true + cat /etc/VERSION 2>/dev/null || true + {{ synoupgrade_bin }} --status 2>/dev/null || true + register: post + changed_when: false + + - name: Afficher post-check + ansible.builtin.debug: + var: post.stdout_lines