md
Chien de garde pour le Raspberry Pi et Domoticz
2019-04-09

On peut dire que je suis quelque peu obsédé par les chiens de garde. Il y a environ six articles sur le sujet sur ce site et je travaille sur quelques projets de chiens de garde matériels. J'aurais dû installer un chien de garde sur le Raspberry Pi qui héberge mon système domotique auparavant, mais mieux vaut tard que jamais.

Il existe un minuteur de surveillance matériel intégré au SOC (système sur puce) du Raspberry Pi. Donc, il devrait être activé pour redémarrer le Raspberry Pi si le système d'exploitation se bloque. De plus, je souhaite surveiller Domoticz pour redémarrer le système si le service devait cesser de fonctionner pendant que le système d’exploitation reste intact. Le site de Domoticz contient deux pages sur le sujet.

Ce dernier prône l'utilisation de Monit pour surveiller Domoticz. C'est une solution générale qui pourrait surveiller de nombreux services supplémentaires. Éventuellement, j'examinerai ce système, mais actuellement, je quelque chose de plus simple capable de

Il y a beaucoup d'informations sur le Web, mais certaines sont obsolètes (comme le sera sans doute ce billet dans un avenir plus ou moins proche). La leçon est d'essayer de vérifier les choses avant d'installer quoi que ce soit. À titre d'exemple, le module de noyau du chien de garde est déjà installé dans la dernière image Raspbian (Stretch nov. 2018) et rien ne doit être fait à cet effet.

pi@raspberry:~ $ dmesg | grep wdt [ 0.845696] bcm2835-wdt 20100000.watchdog: Broadcom BCM2835 watchdog timer ... pi@raspberry:~ $ ls -l /dev/wat* crw------- 1 root root 10, 130 Mar 17 12:14 /dev/watchdog crw------- 1 root root 252, 0 Mar 17 12:14 /dev/watchdog0

Cependant, il n'est pas opérationnel. Pour vérifier cela, j'ai exécuté le script "forkbomb".

nestor@domo:~/wdt $ cat forkbomb.sh swapoff -a :(){ :|:& };: nestor@domo:~/wdt $ chmod +x forkbomb.sh nestor@domo:~/wdt $ sudo ./forkbomb.sh

Après un moment, le Raspberry Pi se figea, Domoticz cessa de fonctionner et je ne pouvais plus ouvrir de sessions SSH. La seule option était de couper le courant, puis de rallumer le Raspberry Pi. Pour remédier à cette situation, il faut installer le service watchdog et modifier son fichier de configuration.

pi@raspberry:~ $ sudo apt install watchdog ... pi@raspberry:~ $ sudo nano /etc/watchdog.conf
... max-load-1 = 24 ... watchdog-device = /dev/watchdog watchdog-timeout = 15

Les deux premières lignes se trouvaient déjà dans le fichier, mais il s’agissait de commentaires. Cela signifie que le "#" figurant au début de ces deux lignes doit être effacé. La troisième ligne, relative au délai d'attente, est nécessaire, car sans elle watchdog définit un délai d'attente de 60 secondes alors que le temporisateur de surveillance Raspberry Pi ne prend en charge qu'un délai d'attente de 15 secondes. Si la ligne n'est pas insérée, l'erreur suivante sera rencontrée.

Apr 09 15:29:39 domo watchdog[1336]: cannot set timeout 60 (errno = 22 = 'Invalid argument')

Merci beaucoup à Florian Harr pour cette correction. Ensuite, démarrez le service surveillance et vérifiez que tout fonctionne correctement.

pi@raspberry:~ $ sudo systemctl start watchdog.service pi@raspberry:~ $ sudo systemctl status watchdog.service ● watchdog.service - watchdog daemon Loaded: loaded (/lib/systemd/system/watchdog.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2019-04-09 15:29:39 ADT; 7s ago Process: 1334 ExecStart=/bin/sh -c [ $run_watchdog != 1 ] || exec /usr/sbin/watchdog $watchdog_options (code=exited, st Process: 1330 ExecStartPre=/bin/sh -c [ -z "${watchdog_module}" ] || [ "${watchdog_module}" = "none" ] || /sbin/modprob Main PID: 1336 (watchdog) CGroup: /system.slice/watchdog.service └─1336 /usr/sbin/watchdog ...

Un nouveau lancement du script "forkbomb" a montré que le chien de garde est efficace. Après un certain temps, la session ouverte a gelé, mais le Raspberry Pi a redémarré et une nouvelle session SSH pourrait être ouverte. En regardant le journal, il était possible de voir la "morsure" du chien de garde.

pi@raspberry:~ $ cat /var/log/syslog ... Apr 9 15:38:05 domo watchdog[1958]: watchdog now set to 15 seconds Apr 9 15:38:05 domo watchdog[1958]: hardware watchdog identity: Broadcom BCM2835 Watchdog timer Apr 9 15:38:05 domo watchdog[1958]: loadavg 27 6 2 is higher than the given threshold 24 18 12! Apr 9 15:38:05 domo watchdog[1958]: shutting down the system because of error 253 = 'load average too high' Apr 9 15:38:05 domo watchdog[1958]: /usr/lib/sendmail does not exist or is not executable (errno = 2) ...

Fait intéressant, il semble que watchdog pourrait envoyer un message à l'aide sendmail lors qu'il arrête le système ce qui pourrait être la réponse à mon troisième désir. J'ai utilisé une approche différente, comme on le verra plus tard. Pour l'instant, voyons comment surveiller Domoticz J'ai suivi l'exemple dans Setting up the raspberry pi watchdog, mais sans activer le journal de Domoticz. Au lieu de cela, le truc Linux de "toucher" un fichier vide pour mettre à jour régulièrement sa dernière date de modification sera le moyen de "nourrir" le chien de garde. Tout ce qu'il faut, c'est un simple script Lua qui sera exécuté à chaque minute Domoticz.

pi@raspberry:~ $ nano domoticz/scripts/lua/script_time_domotizAlive.lua
-- Updates the access time of file /tmp/domoticz.alive -- once every minute. The watchdog service will reboot -- the machine if the time stamp of the file does not -- change over 5 minutes. commandArray = {} os.execute('sudo touch /tmp/domoticz.alive') return commandArray

Vérifiez régulièrement l'heure de la dernière modification du fichier pour constater qu'elle est mise à jour toutes les minutes.

pi@raspberry:~ $ ls -l /tmp total 4 -rw-r----- 1 root root 0 Apr 9 16:36 domoticz.alive ... pi@raspberry:~ $ ls -l /tmp total 4 -rw-r----- 1 root root 0 Apr 9 16:37 domoticz.alive ...

Le fichier de configuration du chien de garde doit être mis à jour. Deux lignes en début de celui-ci doivent être changées.

pi@raspberry:~ $ sudo nano /etc/watchdog.conf
file = /tmp/domoticz.alive change = 300

Arrêtez et redémarrez le service de surveillance, puis attendez plus de cinq minutes (300 secondes) pour vous assurer que le système ne redémarre pas. Arrêtez ensuite le service Domoticz et le Raspberry Pi devrait être redémarré dans cinq minutes environ.

pi@raspberry:~ $ sudo systemctl stop watchdog.service pi@raspberry:~ $ sudo systemctl start watchdog.service ... wait 10 minutes - nothing should happen pi@raspberry:~ $ sudo systemctl stop domoticz.service ... wait at most 6 minutes, the system should reboot

Tenez compte de l'avertissement concernant les redémarrages: n'oubliez pas [que le système redémarrera] lorsque vous arrêtez le service Domoticz.

Alors qu'en est-il de la notification par courrier électronique? Encore une fois, j'utiliserai l'approche proposée dans la première référence. Elle consiste à envoyer un courrier électronique chaque fois que le Raspberry Pi est redémarré. C'est plus simple que d'essayer de faire envoyer le message par le service watchdog. Je suis sûr que cela est possible et qu’il serait alors aussi possible d’envoyer un courrier électronique différent indiquant la raison du redémarrage. Cela reste quelque chose à faire plus tard.

Dans la section 3. Mail Alert Using syslog d'un billet récent, j'ai modifié un court script Python pour envoyer un courriel. J'ai décidé de réutiliser ce script pour le rendre un peu plus polyvalent. Cela évite l'installation sendmail qui semble être une tâche plutôt redoutable. Voici le script Python 3.

#!/usr/bin/python3 # coding: utf-8 # email smtp server credentials SMPT = '--your-smtp-server-url--' SRC = '--your-smtp-user-name--' PWD = '--your-smtp-password--' PORT = 465 # usual # setup a default message TGT = '--your-email-address--' OBJ = 'Alert' MSG = 'Raspberry Pi rebooted' # Import smtplib for the actual sending function import smtplib, ssl # Import the email modules we'll need from email.mime.text import MIMEText # Allow for command line options to set the subject, target email and message import argparse parser = argparse.ArgumentParser(description='Send short email.') parser.add_argument('-s', '--subject') parser.add_argument('-t', '--to') parser.add_argument('-m', '--msg') args = parser.parse_args() if args.subject: OBJ = args.subject if args.to: TGT = args.to if args.msg: MSG = args.msg # debug arguments #print(args) #print('OBJ', OBJ) #print('TGT', TGT) #print('MSG', MSG) #exit # Create the message msg = MIMEText(MSG) msg['Subject'] = OBJ msg['From'] = SRC msg['To'] = TGT # Send it context = ssl.create_default_context() with smtplib.SMTP_SSL(SMPT, PORT, context=context) as server: server.login(SRC, PWD) server.sendmail(SRC, TGT, msg.as_string()) # ref: https://realpython.com/python-send-email/

Version téléchargeable : pymail.

Le script est enregistré en tant que fichier pymail dans le sous-répertoire pythons du répertoire personnel de pi. La dernière étape consiste à ajouter une tâche cron pour envoyer le courrier électronique au moment du redémarrage.

pi@raspberry:~ $ crontab -e
... @reboot sleep 60 && /usr/bin/python3 /home/pi/pythons/pymail @reboot /home/pi/.local/bin/webcam-streamer start && sleep 10 && /home/pi/.local/bin/webcam-streamer stop ...

Comme on peut le constater, une tâche était déjà effectuée au redémarrage, mais peu importe si une autre est ajoutée. J'ai imposé une minute d'attente avant d'envoyer le message. Cela peut être excessif, mais au début, l'envoi immédiat du courrier électronique posait des problèmes.