Actualiser synology_upgrade_ssh.yml
This commit is contained in:
parent
6d2c2e86fd
commit
e13d89b123
|
|
@ -1,12 +1,12 @@
|
||||||
---
|
---
|
||||||
- name: Synology DSM - télécharger puis installer une mise à jour via SSH (robuste Semaphore)
|
- name: Synology DSM - télécharger puis installer mise à jour via SSH (robuste Semaphore)
|
||||||
hosts: synology
|
hosts: synology
|
||||||
gather_facts: false
|
gather_facts: false
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
download_timeout: 3600
|
download_timeout: 7200 # 2h max pour download
|
||||||
reboot_timeout: 1800
|
reboot_timeout: 2400 # 40 min max reboot/upgrade
|
||||||
poll_delay: 20
|
poll_delay: 30 # intervalle de polling
|
||||||
|
|
||||||
synoupgrade_candidates:
|
synoupgrade_candidates:
|
||||||
- "/usr/syno/sbin/synoupgrade"
|
- "/usr/syno/sbin/synoupgrade"
|
||||||
|
|
@ -26,9 +26,9 @@
|
||||||
- "--install"
|
- "--install"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Détecter synoupgrade (sans [ ] ; fallback PATH)
|
- name: Détecter synoupgrade (sans [ ])
|
||||||
ansible.builtin.raw: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -eu
|
||||||
FOUND=""
|
FOUND=""
|
||||||
for p in {{ synoupgrade_candidates | join(' ') }}; do
|
for p in {{ synoupgrade_candidates | join(' ') }}; do
|
||||||
if test -x "$p"; then
|
if test -x "$p"; then
|
||||||
|
|
@ -45,122 +45,148 @@
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "FOUND=$FOUND"
|
echo "$FOUND"
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
register: detect
|
register: detect
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Enregistrer le chemin synoupgrade détecté
|
- name: Enregistrer le binaire synoupgrade
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
synoupgrade_bin: "{{ (detect.stdout | regex_search('FOUND=(.*)', '\\1')) | default('') | trim }}"
|
synoupgrade_bin: "{{ detect.stdout | trim }}"
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Fail si synoupgrade introuvable
|
- name: Fail si synoupgrade introuvable
|
||||||
ansible.builtin.fail:
|
ansible.builtin.fail:
|
||||||
msg: >-
|
msg: "synoupgrade introuvable. stdout='{{ detect.stdout }}' stderr='{{ detect.stderr }}'"
|
||||||
synoupgrade introuvable. Sortie détection:
|
|
||||||
{{ detect.stdout | default('') }}
|
|
||||||
when: synoupgrade_bin == ""
|
when: synoupgrade_bin == ""
|
||||||
|
|
||||||
- name: Afficher le binaire trouvé
|
- name: Afficher le binaire retenu
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg: "synoupgrade utilisé: {{ synoupgrade_bin }}"
|
msg: "synoupgrade utilisé: {{ synoupgrade_bin }}"
|
||||||
|
|
||||||
# 1) Check update
|
# 1) Check update
|
||||||
- name: Check mise à jour disponible
|
- name: Check mise à jour disponible
|
||||||
ansible.builtin.raw: "{{ synoupgrade_bin }} --check || true"
|
ansible.builtin.shell: |
|
||||||
|
set -eu
|
||||||
|
{{ synoupgrade_bin }} --check || true
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
register: check_out
|
register: check_out
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
- name: Afficher le résultat du check
|
- name: Afficher stdout/stderr du check
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
var: check_out.stdout_lines
|
msg:
|
||||||
|
- "CHECK STDOUT: {{ check_out.stdout | default('') }}"
|
||||||
|
- "CHECK STDERR: {{ check_out.stderr | default('') }}"
|
||||||
|
|
||||||
# Si check ne renvoie rien, on NE STOP pas automatiquement, car certains DSM sont muets.
|
# Heuristique: stop uniquement si on voit clairement "up to date"
|
||||||
# On stop seulement si on voit des motifs "no update".
|
|
||||||
- name: Stop si aucune mise à jour détectée (heuristique)
|
- name: Stop si aucune mise à jour détectée (heuristique)
|
||||||
ansible.builtin.meta: end_play
|
ansible.builtin.meta: end_play
|
||||||
when: >
|
when: >
|
||||||
(check_out.stdout | lower) is search('no update')
|
(check_out.stdout | lower) is search('up to date')
|
||||||
or (check_out.stdout | lower) is search('no newer')
|
or (check_out.stdout | lower) is search('no update')
|
||||||
or (check_out.stdout | lower) is search('already')
|
or (check_out.stdout | lower) is search('already')
|
||||||
or (check_out.stdout | lower) is search('up to date')
|
or (check_out.stdout | lower) is search('no newer')
|
||||||
|
|
||||||
# 2) Download
|
# 2) Download
|
||||||
- name: Lancer le téléchargement
|
- name: Lancer le téléchargement
|
||||||
ansible.builtin.raw: "{{ synoupgrade_bin }} --download"
|
ansible.builtin.shell: |
|
||||||
|
set -eu
|
||||||
|
{{ synoupgrade_bin }} --download
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
register: download_start
|
register: download_start
|
||||||
changed_when: true
|
changed_when: true
|
||||||
|
|
||||||
- name: Afficher retour download start
|
- name: Afficher stdout/stderr du download start
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
var: download_start.stdout_lines
|
msg:
|
||||||
|
- "DL START STDOUT: {{ download_start.stdout | default('') }}"
|
||||||
|
- "DL START STDERR: {{ download_start.stderr | default('') }}"
|
||||||
|
|
||||||
# 3) Poll download
|
# 3) Poll download until "ready"
|
||||||
- name: Attendre fin du téléchargement (status/log)
|
- name: Attendre fin du téléchargement (status ou logs)
|
||||||
ansible.builtin.raw: |
|
ansible.builtin.shell: |
|
||||||
set -e
|
set -eu
|
||||||
if {{ synoupgrade_bin }} --status >/dev/null 2>&1; then
|
if {{ synoupgrade_bin }} --status >/dev/null 2>&1; then
|
||||||
{{ synoupgrade_bin }} --status || true
|
{{ synoupgrade_bin }} --status || true
|
||||||
else
|
else
|
||||||
(tail -n 80 /var/log/synoupgrade.log 2>/dev/null || true)
|
(tail -n 120 /var/log/synoupgrade.log 2>/dev/null || true)
|
||||||
(tail -n 120 /var/log/messages 2>/dev/null | grep -i upgrad || true)
|
|
||||||
fi
|
fi
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
register: dl_poll
|
register: dl_poll
|
||||||
changed_when: false
|
changed_when: false
|
||||||
until: >
|
until: >
|
||||||
(dl_poll.stdout | lower) is search('downloaded')
|
(dl_poll.stdout | lower) is search('downloaded')
|
||||||
or (dl_poll.stdout | lower) is search('ready')
|
or (dl_poll.stdout | lower) is search('ready')
|
||||||
or (dl_poll.stdout | lower) is search('finish')
|
or (dl_poll.stdout | lower) is search('complete')
|
||||||
or (dl_poll.stdout | lower) is search('completed')
|
or (dl_poll.stdout | lower) is search('completed')
|
||||||
|
or (dl_poll.stdout | lower) is search('finish')
|
||||||
or (dl_poll.stdout | lower) is search('done')
|
or (dl_poll.stdout | lower) is search('done')
|
||||||
retries: "{{ (download_timeout // poll_delay) | int }}"
|
retries: "{{ (download_timeout // poll_delay) | int }}"
|
||||||
delay: "{{ poll_delay }}"
|
delay: "{{ poll_delay }}"
|
||||||
|
|
||||||
- name: Afficher statut fin téléchargement
|
- name: Afficher statut fin téléchargement
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
var: dl_poll.stdout_lines
|
msg: "{{ dl_poll.stdout_lines | default([]) }}"
|
||||||
|
|
||||||
# 4) Start install (best effort)
|
# 4) Start install (best effort)
|
||||||
- name: Tenter de démarrer l'installation (plusieurs sous-commandes)
|
- name: Tenter de démarrer l'installation (plusieurs méthodes)
|
||||||
ansible.builtin.raw: "{{ synoupgrade_bin }} {{ item }} || true"
|
ansible.builtin.shell: |
|
||||||
|
set -eu
|
||||||
|
{{ synoupgrade_bin }} {{ item }} || true
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
loop: "{{ start_subcommands }}"
|
loop: "{{ start_subcommands }}"
|
||||||
register: start_attempts
|
register: start_attempts
|
||||||
changed_when: true
|
changed_when: true
|
||||||
failed_when: false
|
failed_when: false
|
||||||
|
|
||||||
- name: Choisir la première tentative OK (pas de mots d'erreur)
|
- name: Afficher résultats des tentatives start
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: >
|
||||||
|
{{ start_attempts.results
|
||||||
|
| map(attribute='item')
|
||||||
|
| zip(start_attempts.results | map(attribute='stdout'))
|
||||||
|
| list }}
|
||||||
|
|
||||||
|
- name: Choisir la première tentative qui ne contient pas "invalid/unknown/usage/error"
|
||||||
ansible.builtin.set_fact:
|
ansible.builtin.set_fact:
|
||||||
start_ok: >-
|
start_ok: >-
|
||||||
{{
|
{{
|
||||||
(start_attempts.results
|
(start_attempts.results
|
||||||
| rejectattr('stdout', 'search', '(?i)(invalid|unknown|usage|not found|permission|error|failed)')
|
| rejectattr('stdout', 'search', '(?i)(invalid|unknown|usage|error|failed)')
|
||||||
| rejectattr('stderr', 'search', '(?i)(invalid|unknown|usage|not found|permission|error|failed)')
|
| rejectattr('stderr', 'search', '(?i)(invalid|unknown|usage|error|failed)')
|
||||||
| list
|
| list
|
||||||
| first) | default({})
|
| first) | default({})
|
||||||
}}
|
}}
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
- name: Fail si aucune commande start ne marche
|
- name: Fail si aucune tentative start ne marche
|
||||||
ansible.builtin.fail:
|
ansible.builtin.fail:
|
||||||
msg: >-
|
msg: >
|
||||||
Impossible de démarrer l'installation via synoupgrade.
|
Impossible de démarrer l'installation.
|
||||||
stdout: {{ start_attempts.results | map(attribute='stdout') | list }}
|
Détails stdout/stderr:
|
||||||
stderr: {{ start_attempts.results | map(attribute='stderr') | list }}
|
{{ start_attempts.results | to_nice_json }}
|
||||||
when: start_ok | length == 0
|
when: start_ok | length == 0
|
||||||
|
|
||||||
- name: Afficher la commande start retenue
|
- name: Afficher la commande start retenue
|
||||||
ansible.builtin.debug:
|
ansible.builtin.debug:
|
||||||
msg:
|
msg:
|
||||||
- "Commande retenue: {{ start_ok.item }}"
|
- "Start retenu: {{ start_ok.item }}"
|
||||||
- "stdout: {{ start_ok.stdout | default('') }}"
|
- "stdout: {{ start_ok.stdout | default('') }}"
|
||||||
- "stderr: {{ start_ok.stderr | default('') }}"
|
- "stderr: {{ start_ok.stderr | default('') }}"
|
||||||
|
|
||||||
# 5) Wait reboot (SSH down/up)
|
# 5) Attendre reboot (SSH down/up)
|
||||||
- name: Attendre que le NAS coupe SSH (reboot probable)
|
- name: Attendre que SSH tombe (reboot probable)
|
||||||
ansible.builtin.wait_for:
|
ansible.builtin.wait_for:
|
||||||
host: "{{ inventory_hostname }}"
|
host: "{{ inventory_hostname }}"
|
||||||
port: 22
|
port: 22
|
||||||
state: drained
|
state: drained
|
||||||
timeout: 300
|
timeout: 600
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|
||||||
- name: Attendre le retour SSH
|
- name: Attendre le retour SSH
|
||||||
|
|
@ -172,11 +198,15 @@
|
||||||
delegate_to: localhost
|
delegate_to: localhost
|
||||||
|
|
||||||
# 6) Post-check
|
# 6) Post-check
|
||||||
- name: Post-check version / statut
|
- name: Post-check version DSM
|
||||||
ansible.builtin.raw: |
|
ansible.builtin.shell: |
|
||||||
uname -a || true
|
set -eu
|
||||||
|
echo "=== /etc/VERSION ==="
|
||||||
cat /etc/VERSION 2>/dev/null || true
|
cat /etc/VERSION 2>/dev/null || true
|
||||||
|
echo "=== synoupgrade --status ==="
|
||||||
{{ synoupgrade_bin }} --status 2>/dev/null || true
|
{{ synoupgrade_bin }} --status 2>/dev/null || true
|
||||||
|
args:
|
||||||
|
executable: /bin/sh
|
||||||
register: post
|
register: post
|
||||||
changed_when: false
|
changed_when: false
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue