md
Script de sauvegarde de Domoticz
Mise à jour : 2020-06-12, version originale : 2020-05-29

Il y a eu beaucoup de changements dans mon "manoir du chaos" (peut-être que le lecteur se souviendra de la rubrique du même nom de feu Jerry Pournelle dans Byte). Déplacer mon bureau pour qu'il soit maintenant adjacent à l'atelier a demandé beaucoup de travail. En fait, je n'ai pas encore terminé de tout réorganiser. Cependant, l'une des premières choses que je voulais mettre en place était une stratégie de sauvegarde raisonnable ... encore une fois. Dans cet article, je discute d'une partie importante de cette entreprise, la sauvegarde des données du serveur domotique.

Table des matières

  1. Réseau de sauvegarde local
  2. Pousser une sauvegarde de la base de données de Domoticz
  3. Obtenir une sauvegarde de la base de données de Domoticz
  4. Suppléments
  5. Conclusion

Réseau de sauvegarde local toc

L'image suivante montre une partie du réseau domestique hybride puisqu'il est sans-fil et filaire. Appelons cette partie le réseau de sauvegarde local.

reseay de sauvegarde local

Un Raspberry Pi, exécutant la dernière version de Raspbian avant l' introduction de Raspberry Pi OS, est le système hôte de Domoticz, qui est le système domotique supervisant de nombreux appareils IdO de la maison. Le système domotique est principalement sans fil, fonctionnant sur la bande Wi-Fi 2,4 MHz. Comme on peut s'y attendre d'un contrôleur domotique, ce Raspberry Pi fonctionne toujours.

Le serveur de sauvegarde et mon ordinateur bureau sont connectés au réseau local avec un bus Ethernet de 1 Gb/s. Malheureusement, la carte réseau du serveur de sauvegarde ne roule qu'à 100 Mb/s. D'alleur ce système n'est pas très puissant, c'est un ordinateur excédentaire Pentium 4 de 3,2 GHz avec deux coeurs acheté de mon employeur un peu avant ma retraite. Il dispose de 3 Go de mémoire et d'un disque dur de 1 To. C'est un serveur étêté (sans moniteur ni clavier) sur lequel Debian 4.19.118-2 (2020-04-29) x86_64 a tout récemment été installé. J'ai été un peu surpris de constater que cette distribution de Linux était encore plus austère que les versions « lite » de Raspbian et Armbian destinées aux petits ordinateurs monocarte comme le Raspberry Pi, La Frite et ainsi de suite. Le serveur est connecté à l'alimentation secteur via un commutateur Wi-Fi, ce qui signifie qu'il peut être allumé ou éteint à distance à l'aide de Domoticz. La plupart du temps, il est éteint ce qui est important pour ce qui suit.

L'ordinateur de bureau est un appareil de qualité grand public basé une puce I7 déjà six ou sept ans de vieille. Je viens de remplacer deux disques durs de 1 To de cette machine par deux disques électroniques (SSD) de 0,5 To. Il y a un disque dur supplémentaire avec trois partitions de 1 To chacune. L'une est dédiée aux instantanés Timeshift du système, la seconde est utilisée pour stocker des photographies et la troisième contient des sauvegardes de répertoires importants qui étaient sur les deux disques durs et anciennement sur le serveur de sauvegarde que je voulais enregistrer et que je n'ai pas encore réinstallés sur les disques électroniques. Comme le serveur de sauvegarde, cette machine peut être éteinte à tout moment, bien que typiquement l'ordinateur demeure en marche pendant plusieurs jours consécutifs.

Ce sont les modifications matérielles du bureau qui ont précipité l'élaboration d'une nouvelle stratégie de sauvegarde. Voici ce qui est prévu pour le moment.

Auparavant, la base de données de Domoticz était sauvegardée sur les autres systèmes avec Syncthing. Cependant, il faut revoir cette approche, car la base de données est mise à jour très fréquemment. Cela entraînerait des transferts fréquents de la base de données complète. Bien que je n'aie jamais remarqué de problème de bande passante, je préférerais quelque chose de moins intrusif. D'où cet article sur l'envoi de copies de sauvegarde compressées de la base de données à des intervalles moins fréquents du Raspeberry Pi vers les autres machines du réseau.

Pousser une sauvegarde de la base de données de Domoticz toc

Il a été facile de trouver un script pour réaliser ce que je voulais. Le wiki de Domoticz contient une page consacrée à ce sujet, Script to backup to FTP-server (only Domoticz database). Voici une version légèrement modifiée d'un des scripts qu'on y retrouve. En plus d'utiliser le protocole SFTP (transfert de fichiers via SSH) au lieu du protocole FTP, j'ai inclus des rapports d'erreur qui seront consignés dans le journal système le cas échéant.

#!/bin/bash # Bash script on Domoticz server that will back up its database to a # local machine (mDns host name: backserver.local) as a compressed # file: /home/becky/DomoticzBackups/domoticz_20200528-1342.db.gz # Local SFTP server parameters, must be set correctly # SERVER="backserver.local" # could be IP address USERNAME="becky" PASSWORD="xxxxxxxx" DESTDIR="~/DomoticzBackups/" # trailing "/" necessary # Domoticz parameters # HOST="goldserver.local" # or explicit IP address ok; "127.0.0.1" and "localhost" may not work DOMOTICZ_PORT="8080" # default HTTP port, could be different # Create timestamped backup files # TIMESTAMP=`/bin/date +%Y-%m-%d_%H-%M` BACKUPFILE="domoticz_$TIMESTAMP.db" # backups will be named "domoticz_YYYY-MM-DD_HH-MM.db.gz" BACKUPFILEGZ="$BACKUPFILE".gz # Ask Domoticz to backup the database # curl -s http://$HOST:$DOMOTICZ_PORT/backupdatabase.php > /tmp/$BACKUPFILE curlerr=$? # Stop if this did not work, logging error # if [ $curlerr -ne 0 ]; then logger -p err "Domoticz backup database not created (error: $curlerr)" exit 1 fi # Compress the database # gzip -9 /tmp/$BACKUPFILE # and upload it # curl -k -u "$USERNAME:$PASSWORD" -T "/tmp/$BACKUPFILEGZ" "sftp://$SERVER/$DESTDIR" curlerr=$? # delete the backup up data base # /bin/rm /tmp/$BACKUPFILEGZ # log error if one has occured # if [ $curlerr -ne 0 ]; then logger -p err "Domoticz database not backed up (error: $curlerr)" exit 2 fi
Source : upload-domoticzdb.sh à copier vers ~/.local/bin/upload

Le script du wiki suspend le service Domoticz avant de lui demander de créer la base de données de sauvegarde.
service domoticz.sh stop /usr/bin/curl -s http://$DOMO_IP:$DOMO_PORT/backupdatabase.php > /tmp/$BACKUPFILE service domoticz.sh start
Il me semble que c'est un exploit impossible à réaliser. Il est judicieux de suspendre Domoticz pendant que l'on copie directement la base de données, mais ici, le serveur est chargé de sauvegarder sa propre base de données comme lorsque la fonction est lancée manuellement à partir de l'interface Web.

Le script, nommé avec beaucoup d'imagination upload, est rendu exécutable. Comme il se trouve dans le répertoire ~/.local/bin inclus dans la variable PATH, il peut être lancé très simplement.

woopi@goldserver:~ $ chmod +x .local/bin/upload woopi@goldserver:~ $ printenv PATH /home/woopi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games woopi@goldserver:~ $ ls -l domoticz/domoticz.db -rw-r--r-- 1 woopi woopi 1048576 Jun 1 17:45 domoticz/domoticz.db woopi@goldserver:~ $ upload % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 243k 0 0 100 243k 0 153k 0:00:01 0:00:01 --:--:-- 153k 100 243k 0 0 100 243k 0 153k 0:00:01 0:00:01 --:--:-- 153k

Alors que la base de données dépassait légèrement le 1000 Ko, seulement 243 Ko octets sont transférés vers le serveur de sauvegarde après la compression.

Lorsque le serveur de sauvegarde n'est pas en ligne, l'erreur suivante se produit.

woopi@goldserver:~ $ upload % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- 0:00:04 --:--:-- 0curl: (6) Could not resolve host: backserver.local

On peut vérifier que le code d'erreur est enregistré dans le système de journalisation.

woopi@goldserver:~ $ journalctl -t 'woopi' -- Logs begin at Sun 2020-05-31 20:53:38 ADT, end at Mon 2020-06-01 17:29:46 ADT. -- Jun 01 17:24:34 goldserver woopi[3771]: Domoticz database not backed up (error: 6)

Les codes d'erreur de curl sont répertoriés à la fin de la fin de la page de son manuel.

woopi@goldserver:~ $ man curl ... EXIT CODES There are a bunch of different error codes and their corresponding error messages that may appear during bad con‐ ditions. At the time of this writing, the exit codes are: 1 Unsupported protocol. This build of curl has no support for this protocol. 2 Failed to initialize. ...

Examinez attentivement la taille du fichier transféré. Au départ, celle-ci était bien trop petite, soit 111 octets comme indiqué ci-dessous.

woopi@goldserver:~ $ bash upload % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 111 0 0 100 111 0 240 --:--:-- --:--:-- --:--:-- 240 100 111 0 0 100 111 0 240 --:--:-- --:--:-- --:--:-- 240

Lorsque cela s'est produit, j'ai exécuté la commande curl sans rediriger la sortie vers un fichier pour voir ce qui se passait.

woopi@goldserver:~ $ curl -s http://localhost:9071/backupdatabase.php <html><head><title>Unauthorized</title></head><body><h1>401 Unauthorized</h1></body></html>

J'aurais pu regarder le fichier téléchargé sur backserver pour obtenir les mêmes informations. Le fait est que le serveur Web de Domoticz signale une erreur d'autorisation. En l'occurrence, la protection par mot de passe est activée et 127.0.0.1 ne figure pas dans la liste des réseaux locaux qui n'exige pas d'autorisation. Par conséquent, Domoticz n'acceptait aucune requête vers l'adresse 127.0.0.1 sans mot de passe. De même localhost, qui n'est qu'un alias de 127.0.0.1, ne fonctionnait pas.

Obtenir une sauvegarde de la base de données de Domoticz toc

Il y a un problème avec le script précédent. Clairement, il échouera si le serveur de sauvegarde n'est pas en ligne, ce qui est souvent vrai dans mon système domestique. La solution est que le serveur de sauvegarde obtienne la base de données de Domoticz plutôt que laisser ce dernier amorcer la sauvegarde. C'est en fait assez facile à faire.

#!/bin/bash # Bash script on backup server that will obtain the Domoticz database from the host server # and save to file: /home/becky/DomoticzBackups/domoticz-20200528-1342.db.gz # Domoticz parameters # HOST="goldserver.local" # or explicit IP address ok; "127.0.0.1" and "localhost" may not work PORT="8080" # default HTTP port, could be different # Local directory to contain downloaded database DESTDIR=/home/becky/DomoticzBackups/ # Create timestamped backup files # TIMESTAMP=`/bin/date +%Y%m%d-%H%M` BACKUPFILE="domoticz_$TIMESTAMP.db" # backups will be named something like "domoticz-20200622-1042.db" # Ask Domoticz to copy the database to the local destination directory # curl -s "http://$HOST:$PORT/backupdatabase.php" > $DESTDIR$BACKUPFILE curlerr=$? # Stop if this did not work, logging error # if [ $curlerr -ne 0 ]; then logger -p err "Domoticz backup database not created (error: $curlerr)" exit 1 fi # Compress the database # gzip -9 $DESTDIR$BACKUPFILE
Source téléchargeable : download-domoticzdb.sh

Il y a deux problèmes associés à cette approche. Comme avant, le premier est assez évident : aucune sauvegarde ne sera effectuée si le serveur de sauvegarde n'est pas en marche. J'ai une solution de contournement, mais examinons le second problème avant. Avec cette nouvelle approche, la base de données plutôt volumineuse, car non compressée, transite par le réseau local vers le serveur de sauvegarde et c'est ce dernier qui compresse le fichier. Ici la solution est simple : le serveur de sauvegarde n'a qu'à lancer le script de sauvegarde sur le Raspberry Pi.

Le protocole polyvalent SSH facilite l'exécution d'une commande sur une machine distante. Voici un exemple où la commande uname sera exécutée sur le Raspberry Pi à partir du serveur de sauvegarde.

becky@backserver:~$ ssh woopi@goldserver.local uname -a woopi@goldserver.local's password: xxxxxxxx not echoed to screen Linux goldserver 4.19.75-v7+ #1270 SMP Tue Sep 24 18:45:11 BST 2019 armv7l GNU/Linux

Si uname a été exécutée comme souhaité, il a été nécessaire de saisir un mot de passe. Ce n'est pas acceptable pour un utilitaire qui devrait éventuellement être exécuté automatiquement à intervalles réguliers. Puisque, c'est Linux, quelqu'un a déjà rencontré cette situation et propose une solution aux simples mortels comme moi. En fait, je connais deux solutions. Le premier que j'ai essayé était l'installation sshpass.

becky@backserver:~$ sudo apt install sshpass ... becky@backserver:~$ sshpass -p 'xxxxxxxx' ssh woopi@goldserver.local uname -a Linux goldserver 4.19.75-v7+ #1270 SMP Tue Sep 24 18:45:11 BST 2019 armv7l GNU/Linux

Puisque cela fonctionne, aller à l'étape suivante pour lancer upload sur le Raspberry Pi est très simple à franchir.

becky@backserver:~$ sshpass -p 'xxxxxxxx' ssh woopi@goldserver.local /home/woopi/.local/bin/upload % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 243k 0 0 100 243k 0 322k --:--:-- --:--:-- --:--:-- 322k 100 243k 0 0 100 243k 0 322k --:--:-- --:--:-- --:--:-- 322k

Cependant, Il existe une solution encore plus simple que j'évitais de mettre en place depuis bien trop longtemps. Il suffit de configurer une paire de clés de chiffrement SSH. En plus de la méthode habituelle de nom d'utilisateur / mot de passe commun pour établir l'identité d'un utilisateur essayant de se connecter, SSH utilise la cryptographie à clé publique (également appelée asymétrique). Contrairement à ce que je pensais, il s'agit d'une simple procédure réalisée avec seulement deux commandes. En premier, il faut générer une clé publique et une clé privée sur le serveur de sauvegarde.

becky@backserver:~ $ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/becky/.ssh/id_rsa): Created directory '/home/becky/.ssh'. Enter passphrase (empty for no passphrase): champ laissé vide Enter same passphrase again: laissé vide encore Your identification has been saved in /home/becky/.ssh/id_rsa. Your public key has been saved in /home/becky/.ssh/id_rsa.pub. The key fingerprint is: SHA256:eeJ4nkIGdCARLviKw6XUpJWGl7E1Thbg6OCspRomTxr becky@backserver The key's randomart image is: +---[RSA 2048]----+ | @ | | + . | | . B . | | o * . | | X * S | | + O + . . | | . . S . o | | . . o | | . . | +----[SHA256]-----+

Puis il faut envoyer la clé publique générée au Raspberry Pi.

becky@backserver:~ $ ssh-copy-id woopi@goldserver.local /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/becky/.ssh/id_rsa.pub" The authenticity of host 'goldserver.local (192.168.1.22)' can't be established. ECDSA key fingerprint is SHA256:JsUTFyRmvXsFVhgxKV5QrJsUT4ECMgeeJ4nkIGhbg6O. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys woopi@goldserver.local's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'woopi@goldserver.local'" and check to make sure that only the key(s) you wanted were added.

Si une connexion SSH a déjà été établie entre le serveur de sauvegarde et le Raspberry Pi alors il ne sera pas nécessaire d'avaliser la continuation de la connexion. Suivant la suggestion, essayons d'exécuter une commande à distance.

becky@backserver:~$ ssh woopi@goldserver.local uname -a Linux goldserver 4.19.75-v7+ #1270 SMP Tue Sep 24 18:45:11 BST 2019 armv7l GNU/Linux

Parce que cela fonctionnait alors, sans surprise, il est possible de télécharger la base de données de Domoticz en appelant à distance le script de sauvegarde de celle-ci du Raspberry Pi sans avoir à fournir de mot de passe.

becky@backserver:~ $ ssh woopi@goldserver.local /home/woopi/.local/bin/upload % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 237k 0 0 100 237k 0 411k --:--:-- --:--:-- --:--:-- 410k 100 237k 0 0 100 237k 0 408k --:--:-- --:--:-- --:--:-- 408k

Lors de l'utilisation de ssh pour exécuter à distance le script upload sur le Raspberry Pi, il est nécessaire de spécifier le chemin d'accès complet du script. En effet, le répertoire /home/woopi/.local/bin n'est ajouté à la variable PATH de l'environnement à partir du fichier de configuration .profile lorsque l'utilisateur woopise connecte. Mais, cela ne se produit pas dans cette situation.

Suppléments toc

Si le serveur de sauvegarde était toujours allumé, je ne prendrais pas la peine d'obtenir la base de données pour la sauvegarder comme indiqué dans la dernière section. Au lieu de cela, il suffirait de créer une tâche régulièrement exécutée par le service cron du Raspberry Pi pour transmettre la base de données vers le serveur de sauvegarde. Voici un exemple.

woopi@goldserver:~ $ crontab -e

Ajouter la ligne suivante, en ajustant l'heure si désiré.

# Twice a day, backup the Domoticz database 30 6,18 * * * /home/woopi/.local/bin/upload

Comme indiqué ci-dessus, upload sera exécuté deux fois par jour, à 6h30 et 18h30. Il s'agit d'une fréquence beaucoup plus faible que les sauvegardes horaires effectuées par Domoticz lui-même si la sauvegarde automatique est activée (RéglagesParamètresSystèmeSauvegarde automatique). Actuellement, peu de modifications sont apportées au système domotique, de sorte que seuls les journaux des dispositifs sont susceptibles d'être perdus en 12 heures, ce qui dans mon cas n'est pas si important. De toute façon, la fréquence des sauvegardes est facilement modifiée.

Comme je l'ai expliqué, le serveur de sauvegarde est principalement hors ligne et lorsqu'il est mis en marche pour pousser les modifications vers un référentiel VCS local, il ne sera pas en ligne pendant très longtemps. J'ai donc adopté une approche différente. J'ai créé une tâche cron sur le serveur de sauvegarde qui est exécutée à chaque démarrage. En substance, la base de données de Domoticz sera sauvegardée chaque fois que je sauvegarde du code source.

Comme c'était la première modification du fichier crontab sur le serveur de sauvegarde, l'éditeur à utiliser devait être spécifié. Il n'y avait que deux choix offerts sur ce système Debian allégé, mais, heureusement, nano était un des choix. Je continue à éviter obstinément d'apprendre vim.

becky@backserver:~$ crontab -e no crontab for becky - using an empty one Select an editor. To change later, run 'select-editor'. 1. /bin/nano <---- easiest 2. /usr/bin/vim.tiny Choose 1-2 [1]: 1

J'ai ajouté la ligne suivante au fichier.

@reboot sleep 240 && /home/becky/.local/bin/saveddb

À chaque démarrage du serveur de sauvegarde, le script saveddb (pour "save domoticz database") sera exécuté après un délai de quatre minutes. Le script local a été ajouté pour fournir des fonctionnalités supplémentaires. Je ne veux pas que les sauvegardes de base de données s'accumulent, donc tout fichier de sauvegarde datant de plus d'un mois est supprimé avant de télécharger la base de données Domoticz actuelle. Toutefois, les anciennes sauvegardes ne sont supprimées que s'il reste au moins une ancienne base de données de sauvegarde (datant nécessairement de moins d'un mois).

#!/bin/bash ### User params ############### # Number of days to keep old Domoticz databases DAYS=31 # Directory where Domoticz databases are saved with trailing separator SAVE_DIR=/home/becky/DomoticzBackups/ # Rmote SSH account on computer hosting Domoticz REMOTE_USER=woopi@goldserver.local # Path to the upload script on the computer hosting Domoticz UPLOAD_PATH=/home/woopi/.local/bin/upload ############################### COUNT=$(find $SAVE_DIR -name "domoticz*db.gz" -mtime -$DAYS | wc -l) if [ $COUNT -gt 0 ] then echo "$COUNT files younger than $DAYS days, deleting older files (if any)" find $SAVE_DIR -name "domoticz*db.gz" -mtime +$DAYS -delete else echo "No files younger than $DAYS days, older files (if any) not deleted" fi ssh $REMOTE_USER $UPLOAD_PATH
Source téléchargeable : pull-domoticzdb.sh

Ce n'est pas tout... du genre distrait, j'ai décidé d'ajouter un avertissement par courriel si plus de 15 jours se sont écoulés depuis la dernière sauvegarde de la base de données. C'est assez simple de mettre en oeuvre sur le Raspberry Pi. Fondamentalement, un horodatage est créé chaque fois que la base de données est sauvegardée avec le script upload. Puisque l'heure actuelle est déjà utilisée dans ce script, une seule ligne a dû être ajoutée à sa fin. echo $TIMESTAMP > ~/domoticz/backup.stamp

Mettre touch ~/domoticz/backup.stamp aurait suffi puisque le contenu du fichier n'est jamais utilisé. Voici le script Python qui vérifie l'âge de l'horodatage et envoie un avis par courriel si nécessaire.

#!/home/woopi/.syspy/bin/python # coding: utf-8 from urllib.request import urlopen # with python 3.x #from urllib2 import urlopen # with python 2.7 import os, time try: delta = time.time() - os.path.getmtime("/home/woopi/domoticz/backup.stamp") #print("Time since last modified: {} seconds".format(delta)) except: delta = -1 backup.stamp not found # Send e-mail if it's been more than 15 days (1296000 seconds) since # the Domoticz database has been saved. # if (delta > 1296000) or (delta < 0): cmd = "/home/woopi/.syspy/bin/python /home/woopi/.syspy/pymail -s 'Alerte' -m 'Plus de 15 jours depuis la sauvegarde de la base de données de Domoticz'" #print('Excuting ', cmd) os.system(cmd)
Source téléchargeable : checkbackup.py

Le script Python, nommé checkbackup, a été enregistré dans le même environnement virtuel Python 3, ~/.syspy que le script pymail qu'il utilise (voirChien de garde pour le Raspberry Pi et Domoticz pour plus de détails). La dernière étape pour rendre cette fonction est d'exécuter le script à intervalles réguliers avec cron. N'oubliez pas de rendre le script exécutable au préalable.

woopi@goldserver:~ $ chmod +x .syspy/checkbackup woopi@goldserver:~ $ crontab -e

La ligne suivante est ajoutée au fichier crontab.

# Once a day, send e-mail if Domoticz db not backed up 15 7 * * * /home/woopi/.syspy/checkbackup

Chaque matin, à 7h15, je recevrai un courriel si une sauvegarde n'a pas été effectuée au cours des 15 derniers jours.

Conclusion toc

Ce n'est pas vraiment une conclusion, car faire des sauvegardes appropriées est un problème permanent qui justifie de nouvelles approches de temps en temps. La prochaine étape de cette quête sans fin est la sauvegarde hors site. Peut-être que si je trouve une solution inusitée, je la présenterai dans un prochain article.

Il y a plusieurs façons d'atteindre un objectif. Je suis sûr qu'il serait possible d'obtenir à peu près la même chose que celle décrite ci-dessus avec Syncthing avec les paramètres appropriés. Je pourrais revenir à cette approche. D'ailleurs, je pourrais essayer les deux simultanément pendant un certain temps. Une autre possibilité est le vénérable rsync.