# Sauvegarde automatique des VMs sous Proxmox

**URL:** <https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142>\
**Category:** Général\
**Created:** [Juin 8, 2024, 10:09 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142 "2024-06-08T10:09:09Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon49275192](https://forum.hacf.fr/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@anon49275192](https://forum.hacf.fr/u/anon49275192)\
**Post date:** [Juin 8, 2024, 10:09 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/1 "2024-06-08T10:09:09Z")

</div>

Bonjour a tous,

**Sauvegarde automatique des VMs sous Proxmox**

Faire des sauvegardes ? De toutes nos petites VMs ?? Ah bah oui ! Et vous avez plutôt intérêt si vous avez une machine de sauvegarde. Moi, j'ai un QNAP. J'ai donc mis un petit programme en langage Bash dans mon QNAP qui s'occupe de sauvegarder toutes mes petites VMs en mode snapshot. Donc, sans interruption de service.

Evidemment, c'est un tout petit script, une bidouille. Il n'a pas l'intention de remplacer un proxmox backup server ou autre système de sauvegarde évolué.

Mais, il a l'avantage d'être simple et de sauvegarder mes VMs Proxmox à l'endroit désiré au fil des mois de l'année en cours. Même si je rajoute des VMs au fil du temps, elles seront prisent en compte par le script et sauvegardées chaque mois. Je n'aurai rien à faire.

Donc, vous êtes ainsi assuré d'avoir une sauvegarde de chaque VM de votre Proxmox, chaque mois de l'année en cours. Une sauvegarde pour janvier, une sauvegarde pour février etc.  
L'année suivante, la sauvegarde de l'année précédente pour le mois en cours est écrasée. Votre répertoire de sauvegarde n'enfle donc pas comme un pop-corn au fil du temps.  
C'était **mon besoin, encore une fois. Avoir au moins une sauvegarde de chacune de mes VMs. Un minimum.** Et avec un script bash car **si un jour je change mon QNAP pour un autre système de sauvegarde sous Linux, il me suffira simplement de copier et d'executer ce petit script dans celui-ci. Je gagne ainsi du temps. Et surtout, je me prends pas le chou si je change de système de sauvegarde dans l'avenir.**

Voici le script, livré tel qu'il est. A vous de l'adapter à votre besoin. Je l'ai un peu plus commenté pour l'occasion :  
En crontab, sur votre serveur de sauvegarde, le script s'execute tout les premiers du mois à minuit :

```auto
0 0 1 * * /share/theo/scriptNAS/backupvm.sh

```

Le script :

```auto
#!/bin/bash

## Fonction Bash qui prends un répertoire avec des fichiers 100.conf, 101.conf, etc.
## et qui va retourner un tableau de nombres, 100,101,etc.
get_numbers_from_files() {
    dir=$1
    declare -a numbers
    for file in "$dir"/*.conf
    do
        number=$(basename "$file" .conf)
        numbers+=("$number")
    done
    echo "${numbers[@]}"
}

## La fonction Bash de backup avec ses 2 paramètres, $1, $2
backup_node() {
cd /root/
# Hostname de l'hyperviseur Proxmox
HYPERVISEUR="${1}"
# IP de l'hyperviseur Proxmox
CIBLE="${2}"
SYS="sys"
VMS="vms"
# Dossier partagé ou je vais sauvegarder mes VMs sur mon QNAP
SHARE="/share/backup"
DIRHYP="$SHARE/$HYPERVISEUR"
DIRSYS="$SHARE/$HYPERVISEUR/$SYS"
DIRVMS="$SHARE/$HYPERVISEUR/$VMS"
USER="root"

if [-f "$SHARE/NOBACKUP"]; then
 exit 0
fi

if [! -d "$DIRSYS"]; then
 mkdir -p $DIRSYS
fi
if [! -d "$DIRVMS"]; then
 mkdir -p $DIRVMS
fi
ladate=$(date)
echo $ladate > $DIRHYP/debut.txt
mkdir -p /tmp/conf
# Je recupere l'ensemble des fichiers de configuration des VMs de mon hyperviseur Proxmox
/usr/bin/ssh $USER@$CIBLE "tar czf - /etc/pve/qemu-server/*.conf" | tar xzf - -C /tmp/conf
# Avec cet ensemble, je génère un tableau des numéros de mes VMs
tab=($(get_numbers_from_files "/tmp/conf/etc/pve/qemu-server"))
rm -Rf /tmp/conf
# Je prends soin ici de supprimer tout dump manuel que j'aurai pu faire 
# Le premier du mois, tout vos dumps manuels ou programmés sur Proxmox
# sont détruits. On préserve ainsi l'espace disque de l'hyperviseur le plus simplement du monde.
/usr/bin/ssh $USER@$CIBLE "rm -f /srv/data/dump/*"
/usr/bin/scp $USER@$CIBLE:/etc/pve/qemu-server/*.conf $DIRVMS/
vmdate=$(date "+%d-%m")
cd $DIRHYP
rm -Rf $SYS/*
cd /root/
# Je sauve aussi sur mon serveur de sauvegarde toute la configuration de mon hyperviseur Proxmox.
/usr/bin/scp -r $USER@$CIBLE:/etc $DIRSYS/
if [! -f "$SHARE/NOBACKUPVM"]; then
    # Une boucle qui va me faire un snapshot de chaque VM par mois.
    for novm in ${tab[*]}
    do
    # Je génère le snapshot de la VM novm
    /usr/bin/ssh $USER@$CIBLE "vzdump $novm --compress zstd --mode snapshot --stdout > /var/lib/vz/dump/vzdump-qemu-$novm-$vmdate.vma.zst"
    /usr/bin/ssh $USER@$CIBLE "rm -f /var/lib/vz/dump/*.log"
    # Je rapatrie le snapshot de la VM sur mon serveur de sauvegarde
    /usr/bin/scp $USER@$CIBLE:/var/lib/vz/dump/* $DIRVMS/
    # J'efface les dumps au fur et à mesure pour ne pas saturer le disque de l'hyperviseur
    /usr/bin/ssh $USER@$CIBLE "rm -f /var/lib/vz/dump/*"
    done
fi
ladate=$(date)
echo $ladate > $DIRHYP/fin.txt
chmod -R 777 $DIRHYP
}

# PROGRAMME PRINCIPAL :
backup_node p1 192.168.2.2

# p1 étant le nom (hostname) de mon hyperviseur Proxmox
# et 192.168.2.2, sont IP sur le réseau

exit 0

```

> Avec ce petit script, vous n'aurez plus besoin de le modifier si il vous prenait l'envie de créer des VMs supplémentaires sur votre Proxmox. Elles ne seront pas oubliées par ce script 🙂 et seront sauvegardées le premier du mois suivant.

PS : Vous avez un Synology ? Ca devrait le faire aussi. Le Synology, c'est aussi du Linux. Vous avez un serveur de sauvegarde dont le système d'exploitation est Linux. Ce petit script devrait fonctionner sans problème avec les indications données ici.

Attention toutefois. les commandes sont indiquées avec leur chemin absolu.  
Par exemple, la commande `ssh` dans le script est indiqué via son chemin absolu `/usr/bin/ssh`

J'aurai donc dû ajouter pour plus de portabilité en début de mon script, pour chaque commande, ici pour la commande `ssh` :

```auto
SSH=$(which ssh)

```

et pour chaque ligne contenant le chemin absolu de la commande `ssh` :

```auto
/usr/bin/ssh $USER@$CIBLE "rm -f /srv/data/dump/*"

```

changer (ré-écrire) comme ceci :

```auto
$SSH $USER@$CIBLE "rm -f /srv/data/dump/*"

```

A faire également, pour la commande /usr/bin/scp, /bin/date, rm,  
Mais bon, pas eu le temps de tester. Ce script est fonctionnel en l'état sur un système QNAP mais son écriture est à améliorer grandement !

La commande `which` vous permet donc de connaitre le chemin absolu de la commande que vous lui indiquez en paramètre.

executer une commande avec son chemin absolu est parfois nécessaire quand cette commande est appelé via un script en crontab.

Donc, si il vous prenait l'idée d'utiliser ce petit script, pensez à vérifier le chemin absolu de chaque commande avec `which`, sur votre système Linux 🙂

Euh, et le chemin absolu de `which` sur mon système ?  
Bah,

```auto
[~] # which which
/usr/bin/which
[~] #

```

Je n'ai pas variabilisé le répertoire `/srv/data` qui est le répertoire ou se trouve entre autre les disques des VMs (sous la forme de fichiers) dans Proxmox. Et c'est pas bien ! 😢

L'espace disque sur mon Proxmox a la tête suivante :

```auto
root@p1:~# df -h
Filesystem Size Used Avail Use% Mounted on
udev 3.9G 0 3.9G 0% /dev
tmpfs 786M 1.3M 785M 1% /run
/dev/mapper/pve-root 94G 6.0G 84G 7% /
tmpfs 3.9G 40M 3.8G 2% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/mapper/pve-data 393G 187G 187G 51% /srv/data
/dev/fuse 128M 28K 128M 1% /etc/pve
tmpfs 786M 0 786M 0% /run/user/0
root@p1:~#

```

Le répertoire `/srv/data` est configuré ainsi dans l'interface WEB de Proxmox :

 ![image](https://forum.hacf.fr/uploads/default/original/3X/b/6/b6eb9e37fbac0358a03d192938bdad9c0a03bea2.png)

Et enfin, lorsque vous créez vos propres VMs, utilisez LVM à chaque fois que vous en avez la possibilité. Vous pourrez ainsi réduire ou augmenter vos disques virtuels assez facilement.

Alors, ces sauvegardes. Elles sont où ? J'indique que j'utilise ce petit script sous un serveur de sauvegarde de la marque QNAP.  
Et bien, elles sont dans un répertoire partagé sous QNAP. Ce qui me permet de les avoir à disposition simplement sur mon Windows (pas taper la tête !).

 ![image](https://forum.hacf.fr/uploads/default/original/3X/a/a/aabeab18948ba8c9083cab006582c1f2a324118d.png)

Voilà donc. J'ai fait une petite bidouille de script pour mes propres besoins. Je partage ce que j'ai fait sans autres prétentions 🙂

---

<div class="post-metadata">

**Author:** ![anon49275192](https://forum.hacf.fr/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@anon49275192](https://forum.hacf.fr/u/anon49275192)\
**Post date:** [Juin 8, 2024, 11:27 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/2 "2024-06-08T11:27:13Z")

</div>

Ohhh, vous avez un cluster Proxmox avec au moins 2 noeuds. Un noeud p1 comme moi mais aussi un noeud p2.

Il vous suffit dans la partie `#PROGRAMME PRINCIPAL` du script de rajouter votre noeud p2 à celui p1 déjà présent. Comme ceci :

```auto
# PROGRAMME PRINCIPAL :
backup_node p1 192.168.2.2
backup_node p2 192.168.2.3

```

---

<div class="post-metadata">

**Author:** ![barto\_95](https://forum.hacf.fr/user_avatar/forum.hacf.fr/barto_95/32/172_2.png) [@barto\_95](https://forum.hacf.fr/u/barto_95)\
**Post date:** [Juin 8, 2024, 11:41 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/3 "2024-06-08T11:41:19Z")

</div>

Tu peut aussi utiliser le système de backup par défauts de proxmox

Ou si tu veut des choses plus évoluer (backup full, incremental, etc…) installer backup proxmox server qui est disponible chez proxmox et gratuit

---

<div class="post-metadata">

**Author:** ![anon49275192](https://forum.hacf.fr/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@anon49275192](https://forum.hacf.fr/u/anon49275192)\
**Post date:** [Juin 8, 2024, 11:50 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/4 "2024-06-08T11:50:24Z")

</div>

oui. Merci à toi pour ta remarque pertinente. Mais je voulais que cela soit QNAP qui ordonne les snapshots sur Proxmox. Et qui les rapatrient ensuite sur son disque. Je ne souhaitais pas l’inverse. Proxmox n’est pas en mesure d’accéder au serveur QNAP. Mais QNAP a les droits pour accéder à PROXMOX. QNAP est un élément sensible … Donc l’idée d’un script m’est venu.

Lorsque dans le script je fais un` /usr/bin/ssh` ou un `/usr/bin/scp`, ce sont des commandes initiées sur la machine QNAP vers PROXMOX. Les règles de parefeu autorisent cela. QNAP vers PROXMOX donc. Pas l’inverse.

QNAP: Serveur de sauvegarde.  
PROXMOX: Hyperviseur de machines virtuelles (VM)

---

<div class="post-metadata">

**Author:** ![barto\_95](https://forum.hacf.fr/user_avatar/forum.hacf.fr/barto_95/32/172_2.png) [@barto\_95](https://forum.hacf.fr/u/barto_95)\
**Post date:** [Juin 8, 2024, 12:04 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/5 "2024-06-08T12:04:06Z")

</div>

Chacun voie midi à sa porte comme on dit

Mais je préfère utiliser l’outils fournie par l’éditeur de la solution puisque par exemple tu peut faire de la de duplication, compression etc… que tu ne peut gérez avec ton script

Mais si cette solution te conviens c’est tt bon 👍

---

<div class="post-metadata">

**Author:** ![anon49275192](https://forum.hacf.fr/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@anon49275192](https://forum.hacf.fr/u/anon49275192)\
**Post date:** [Juin 8, 2024, 12:20 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/6 "2024-06-08T12:20:46Z")

</div>

Bien sûr. Pour la duplication, il faudrait un système de fichier ZFS par exemple qui gère ce genre de chose. Ce que contient d’ailleurs Proxmox Backup Server.

Mais, mes VMs sont ridiculement petites. La plus grosse fait 32 Go et est HA OS. Donc la duplication n’est pas utile pour moi. 1 bonne demi-heure de sauvegarde pour mon cas, cela prends.

Mais tu as raison 🙂 , **il vaut mieux utiliser l’outil de l’éditeur de la solution.** Et Proxmox Backup Server est un super outil de sauvegarde pour Proxmox.

---

<div class="post-metadata">

**Author:** ![WarC0zes](https://forum.hacf.fr/user_avatar/forum.hacf.fr/warc0zes/32/137471_2.png) [@WarC0zes](https://forum.hacf.fr/u/WarC0zes)\
**Post date:** [Juin 8, 2024, 2:00 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/7 "2024-06-08T14:00:42Z")

</div>

Bonjour @anon49275192,  
merci pour ce tuto.  
N’oublie pas de commencer par un bonjour, quand tu créer un nouveau sujet.

---

<div class="post-metadata">

**Author:** ![anon49275192](https://forum.hacf.fr/letter_avatar_proxy/v4/letter/a/d07c76/32.png) [@anon49275192](https://forum.hacf.fr/u/anon49275192)\
**Post date:** [Juin 8, 2024, 2:46 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/8 "2024-06-08T14:46:40Z")

</div>

Re bonjour @WarC0zes. Oui, je l’ajouterai quand ma limite de quota de modifications sera levée 😊

---

<div class="post-metadata">

**Author:** ![WarC0zes](https://forum.hacf.fr/user_avatar/forum.hacf.fr/warc0zes/32/137471_2.png) [@WarC0zes](https://forum.hacf.fr/u/WarC0zes)\
**Post date:** [Juin 8, 2024, 2:47 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/9 "2024-06-08T14:47:27Z")

</div>

Allez! je te le rajoute 😉  
tu auras pas a attendre le quota.

---

<div class="post-metadata">

**Author:** ![shadda](https://forum.hacf.fr/user_avatar/forum.hacf.fr/shadda/32/85684_2.png) [@shadda](https://forum.hacf.fr/u/shadda)\
**Post date:** [Décembre 6, 2024, 6:34 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/10 "2024-12-06T06:34:26Z")

</div>

Salut super ton idée bravo  
Je suis novice mais tu fais un autorun.sh pour ton script?

---

<div class="post-metadata">

**Author:** ![Elmago](https://forum.hacf.fr/user_avatar/forum.hacf.fr/elmago/32/100064_2.png) [@Elmago](https://forum.hacf.fr/u/Elmago)\
**Post date:** [Juin 23, 2025, 7:48 UTC](https://forum.hacf.fr/t/sauvegarde-automatique-des-vms-sous-proxmox/43142/11 "2025-06-23T07:48:59Z")

</div>

Bonjour,

pour moi j'ai utilisé un montage reseau tout simple :

 ![image](https://forum.hacf.fr/uploads/default/original/3X/d/5/d5c5fcb06059a974e9eceefd7bb3531d2784a6bc.png)

La configuration via l'interface graphique, mais je surveille via HA :

 ![image](https://forum.hacf.fr/uploads/default/original/3X/a/c/acd0df9ab0a17e5fb13080f752893355870ca706.png)  
 ![image](https://forum.hacf.fr/uploads/default/original/3X/f/1/f11f2e774974f013279aaaba5045633eb7ff1a58.png)

J'ai de alerte si le fichier de sauvegarde a plus de 12h,

```auto
command_line:
  - sensor:
      name: "Backup LXC 108"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-108-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup LXC 107"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-107-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup LXC 106"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-106-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600
      
  - sensor:
      name: "Backup LXC 101"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-101-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600
      
  - sensor:
      name: "Backup LXC 102"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-102-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup LXC 103"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name 'vzdump-lxc-103-*.tar.zst' -mmin -300 -print -quit | grep -q vzdump && echo 1 || echo 0"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup LXC 104"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-104-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup LXC 105"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17
        "bash -c 'find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name \"vzdump-lxc-105-*.tar.zst\" -mmin -300 | grep -q . && echo 1 || echo 0'"
      value_template: "{{ value | int }}"
      scan_interval: 600

  - sensor:
      name: "Backup QEMU 100"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no
        -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -maxdepth 1 -name 'vzdump-qemu-100-*.vma.zst' -mmin -300 -print -quit);
          if [-n \"\$FILE\"]; then echo 1; else echo 0; fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unique_id: backup_qemu_100

  - sensor:
      name: "Age dernière sauvegarde LXC 101"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-101-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_101

  - sensor:
      name: "Age dernière sauvegarde LXC 102"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-102-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_102

  - sensor:
      name: "Age dernière sauvegarde LXC 103"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-103-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_103

  - sensor:
      name: "Age dernière sauvegarde LXC 104"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-104-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_104

  - sensor:
      name: "Age dernière sauvegarde LXC 105"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-105-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_105

  - sensor:
      name: "Age dernière sauvegarde QEMU 100"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-qemu-100-*.vma.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_qemu_100

  - sensor:
      name: "Age dernière sauvegarde LXC 106"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-106-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_106

  - sensor:
      name: "Age dernière sauvegarde LXC 107"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-107-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_107

  - sensor:
      name: "Age dernière sauvegarde LXC 108"
      command: >
        ssh -i /config/ssh/id_ed25519 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@192.168.1.17 "
          FILE=\$(find /var/www/owncloud/data/admin/files/Save_Proxmox/dump -name 'vzdump-lxc-108-*.tar.zst' -printf '%T@ %p\n' 2>/dev/null | sort -nr | head -n1 | cut -d' ' -f1);
          if [-z \"\$FILE\"]; then echo 0; else NOW=\$(date +%s); echo \$(( (NOW - \${FILE%.*}) / 60 )); fi
        "
      value_template: "{{ value | int }}"
      scan_interval: 600
      unit_of_measurement: "min"
      unique_id: age_derniere_sauvegarde_lxc_108

template:
    - sensor:
      - name: "Sauvegarde LXC 101 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_101') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_101') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_101') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_101') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

    - sensor:
      - name: "Sauvegarde LXC 102 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_102') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_102') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_102') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_102') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"
        
      - name: "Sauvegarde LXC 103 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_103') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_103') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_103') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_103') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde LXC 104 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_104') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_104') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_104') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_104') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde LXC 105 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_105') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_105') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_105') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_105') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde QEMU 100 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_qemu_100') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_qemu_100') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_qemu_100') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_qemu_100') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde LXC 106 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_106') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_106') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_106') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_106') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde LXC 107 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_107') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_107') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_107') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_107') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

      - name: "Sauvegarde LXC 108 trop vieille"
        state: >-
          {{ states('sensor.age_derniere_sauvegarde_lxc_108') | int(0) > 720 }}
        icon: >-
          {% if states('sensor.age_derniere_sauvegarde_lxc_108') | int(0) > 720 %}
            mdi:alert-circle
          {% else %}
            mdi:check-circle
          {% endif %}
        attributes:
          age_minutes: "{{ states('sensor.age_derniere_sauvegarde_lxc_108') | int(0) }}"
          age_human: >-
            {% set age = states('sensor.age_derniere_sauvegarde_lxc_108') | int(0) %}
            {{ (age // 60) }}h{{ '%02d' % (age % 60) }}
          seuil: "12h"

          

binary_sensor:
  - platform: template
    sensors:
      backup_lxc_101_ok:
        friendly_name: "Backup LXC 101 OK"
        value_template: "{{ is_state('sensor.backup_lxc_101', '1') }}"
      backup_lxc_102_ok:
        friendly_name: "Backup LXC 102 OK"
        value_template: "{{ is_state('sensor.backup_lxc_102', '1') }}"
      backup_lxc_103_ok:
        friendly_name: "Backup LXC 103 OK"
        value_template: "{{ is_state('sensor.backup_lxc_103', '1') }}"
      backup_lxc_104_ok:
        friendly_name: "Backup LXC 104 OK"
        value_template: "{{ is_state('sensor.backup_lxc_104', '1') }}"
      backup_lxc_105_ok:
        friendly_name: "Backup LXC 105 OK"
        value_template: "{{ is_state('sensor.backup_lxc_105', '1') }}"
      backup_qemu_100_ok:
        friendly_name: "Backup QEMU 100 OK"
        value_template: "{{ is_state('sensor.backup_qemu_100', '1') }}"
      backup_lxc_106_ok:
        friendly_name: "Backup LXC 106 OK"
        value_template: "{{ is_state('sensor.backup_lxc_106', '1') }}"
      backup_lxc_107_ok:
        friendly_name: "Backup LXC 107 OK"
        value_template: "{{ is_state('sensor.backup_lxc_107', '1') }}"
      backup_lxc_108_ok:
        friendly_name: "Backup LXC 108 OK"
        value_template: "{{ is_state('sensor.backup_lxc_108', '1') }}"

      backup_owncloud_global_ok:
        friendly_name: "Sauvegardes OwnCloud OK"
        value_template: >
          {{ is_state('sensor.backup_lxc_101', '1')
             and is_state('sensor.backup_lxc_102', '1')
             and is_state('sensor.backup_lxc_106', '1')
             and is_state('sensor.backup_lxc_103', '1')
             and is_state('sensor.backup_lxc_104', '1')
             and is_state('sensor.backup_lxc_105', '1')
             and is_state('sensor.backup_lxc_107', '1')
             and is_state('sensor.backup_lxc_108', '1')
             and is_state('sensor.backup_qemu_100', '1') }}
        icon_template: >
          {% if is_state('binary_sensor.backup_owncloud_global_ok', 'on') %}
            mdi:check-circle
          {% else %}
            mdi:alert-circle
          {% endif %}

automation:
  - alias: "Alerte sauvegardes OwnCloud KO"
    id: alerte_sauvegardes_owncloud_ko
    trigger:
      - trigger: state
        entity_id: binary_sensor.backup_owncloud_global_ok
        to: "off"
    action:
      - action: notify.mobile_app_pixel_7_pro_mm
        data:
          message: >
            ⚠️ Sauvegardes OwnCloud manquantes ou obsolètes :
            {% for id in [101, 106, 102, 103, 104, 105, 107, 108] %}
              {% if not is_state('sensor.backup_lxc_' ~ id, '1') %}
                ❌ LXC {{ id }}
              {% endif %}
            {% endfor %}
            {% if not is_state('sensor.backup_qemu_100', '1') %}
              ❌ QEMU 100
            {% endif %}

```
