∴☆★ Ceci est ma page BROUILLON !! ★☆∴

NUT & upsmon & upssched

Monitorer les événements de l'UPS avec upsmon

Configuration par défaut

Par défaut, toutes les types d’événements sont associés aux directives SYSLOG (écriture dans /var/log/syslog) et WALL (notification aux utilisateurs par les terminaux).

FIXME Sous Ubuntu, la notification par la commande wall ne semble pas fonctionner !

Le fichier /etc/nut/upsmon contient donc les lignes suivantes :

NOTIFYFLAG ONLINE    SYSLOG+WALL
NOTIFYFLAG ONBATT    SYSLOG+WALL
NOTIFYFLAG LOWBATT   SYSLOG+WALL
NOTIFYFLAG FSD       SYSLOG+WALL
NOTIFYFLAG COMMOK    SYSLOG+WALL
NOTIFYFLAG COMMBAD   SYSLOG+WALL
NOTIFYFLAG SHUTDOWN  SYSLOG+WALL
NOTIFYFLAG REPLBATT  SYSLOG+WALL
NOTIFYFLAG NOCOMM    SYSLOG+WALL
NOTIFYFLAG NOPARENT  SYSLOG+WALL

Dans /var/log/syslog, on obtient un message préformaté. Exemple :

Aug 19 21:49:34 localhost upsmon[7784]: Startup successful
Aug 19 21:50:24 localhost upsmon[7786]: UPS localups@localhost on battery
Aug 19 21:50:34 localhost upsmon[7786]: Poll UPS [localups@localhost] failed - Data stale
Aug 19 21:50:34 localhost upsmon[7786]: Communications with UPS localups@localhost lost
Aug 19 21:50:39 localhost upsmon[7786]: Communications with UPS localups@localhost established
Aug 19 21:50:39 localhost upsmon[7786]: UPS localups@localhost on line power
Dans l'exemple ci-dessus localups est le libellé associé à l'onduleur dans le fichier /etc/nut/ups.conf

Utilisation d'un script via l'option NOTIFYCMD et la directive EXEC

Il est possible en plus ou la place des directives WALL et SYSLOG, d'utiliser la directive EXEC pour lancer un script définit par l'option NOTIFYCMD pour réaliser un traitement personnalisé.

Le fichier de configuration /etc/nut/upsmon.conf contiendra donc la ligne :

NOTIFYCMD /usr/local/bin/upsalert.sh
Le chemin /usr/local/bin/upsalert.sh est à remplacer par celui votre script !

Les options NOTIFYFAG concernée par ce traitement personnalisée doivent avoir la directive EXEC. Exemple pour ONLINE et ONBATT et LOWBATT :

NOTIFYFLAG ONLINE    SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT    SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT   SYSLOG+WALL+EXEC
NOTIFYFLAG FSD       SYSLOG+WALL
NOTIFYFLAG COMMOK    SYSLOG+WALL
NOTIFYFLAG COMMBAD   SYSLOG+WALL
NOTIFYFLAG SHUTDOWN  SYSLOG+WALL
NOTIFYFLAG REPLBATT  SYSLOG+WALL
NOTIFYFLAG NOCOMM    SYSLOG+WALL
NOTIFYFLAG NOPARENT  SYSLOG+WALL

FIXME Le script reçoit en argument le même libellé que ce qui est tracé dans /var/log/syslog.

Notification par mail
Votre modem ainsi que vos équipements réseaux reliant ce dernier au PC hébergeant upsmon serveur (relié à l'onduleur) et upsmon client (celui exécutant le script) doivent aussi être alimentés pour pouvoir envoyer le mail au moment opportun. Dans le cas contraire, vous risquez de ne recevoir le mail que lorsque le courant revient, voir de ne pas recevoir le mail du tout !!

Choix d'un MTA accessible en console

Plusieurs MTA (mail transfert agent) accessible en console sont disponibles dans les dépôts. Parmi ceux-ci on notera :

Installation et configuration avec SSMTP

Exemple avec ssmtp :

Création du script de notification mail

A METTRE EN FORME — Brouillon

Créer un fichier pour l'entête avec une ligne From: ; To: ; Subject: : Ces données sont invariantes dans le message. Créer le script contenant les lignes :

#!/bin/bash
echo "$@" | cat </chemin/fichier/entête> - | ssmtp <mon-adresse-mail@mon-fai.fr>

FIXME : Non testé : à vérifier si ça marche bien :p

Vous pouvez modifier le libellé par défaut associé à chaque événement dans le fichier upsmon.conf :
NOTIFYMSG ONLINE	"UPS %s sur secteur."
NOTIFYMSG ONBATT	"UPS %s sur batterie."
NOTIFYMSG LOWBATT	"UPS %s batterie faible."
NOTIFYMSG FSD		"UPS %s: arrêt forcé en cours."
NOTIFYMSG COMMOK	"Communications avec l'UPS %s établie."
NOTIFYMSG COMMBAD	"Communications avec l'UPS %s perdue."
NOTIFYMSG SHUTDOWN	"Déconnexion et arrêt automatiques engagés."
NOTIFYMSG REPLBATT	"UPS %s La batterie doit être remplacée."
NOTIFYMSG NOCOMM	"UPS %s indisponible."
NOTIFYMSG NOPARENT	"mort du processus upsmon parent - arrêt impossible"

Utilisation de upssched

Si vous souhaitez effectuer des actions différentes selon le type d'événement, il est préférable d'utiliser upssched.

fichier upsmon.conf (exemple) :

NOTIFYCMD /sbin/upssched

NOTIFYFLAG ONLINE	SYSLOG+WALL+EXEC
NOTIFYFLAG ONBATT	SYSLOG+WALL+EXEC
NOTIFYFLAG LOWBATT	SYSLOG+WALL+EXEC
NOTIFYFLAG FSD	SYSLOG+WALL+EXEC
NOTIFYFLAG COMMOK	SYSLOG+EXEC
NOTIFYFLAG COMMBAD	SYSLOG+EXEC
NOTIFYFLAG SHUTDOWN	SYSLOG+WALL+EXEC
NOTIFYFLAG REPLBATT	SYSLOG+WALL+EXEC
NOTIFYFLAG NOCOMM	SYSLOG+WALL+EXEC
NOTIFYFLAG NOPARENT	SYSLOG+WALL+EXEC

Créer le fichier de config /etc/nut/upssched.conf

# the script to be executed
CMDSCRIPT /usr/local/bin/upsalert.sh

# mandatory fields that must be set before AT commands
PIPEFN /var/run/nut/upssched.pipe
LOCKFN /var/run/nut/upssched.lock

# the timers, here 30 sec after the ONBATT (ups on battery) event
AT ONBATT * START-TIMER onbatt-timer 120

# cancel the countdown is power is back
AT ONLINE * CANCEL-TIMER onbatt-timer

AT COMMBAD * EXECUTE commbad
AT COMMOK * EXECUTE commok
AT NOCOMM * EXECUTE nocomm
AT ONBATT * EXECUTE onbatt
AT LOWBATT * EXECUTE lowbatt
AT ONLINE * EXECUTE online
AT FSD	* EXECUTE fsd
AT SHUTDOWN * EXECUTE shutdown
AT REPLBATT * EXECUTE replbatt
AT NOPARENT * EXECUTE noparent

Créer le script /usr/local/bin/upsalert.sh (FIXME exemple à revoir)

#!/bin/bash
logfile=/var/log/ups.log
date=$(date +"%F %T")

case $1 in
    commbad)
        echo "$date : UPS communications failure." >> $logfile
        ;;
    commok)
        echo "$date : UPS communications restored." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.enable 2>> $logfile
        ;;
    nocomm)
        echo "$date : UPS communications cannot be established." >> $logfile
        ;;
    onbatt)
        echo "$date : UPS is on battery. Trying to suspend." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.mute 120 2>> $logfile
        sudo /usr/sbin/pm-suspend-hybrid --quirk-none 2>&1 >> $logfile
        ;;
    onbatt-timer)
        echo "$date : UPS is on battery for more than 2 min. Trying to hibernate." >> $logfile
       $echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.mute 300 2>> $logfile
        sudo /usr/sbin/pm-hibernate --quirk-none 2&>1 >>$logfile
        ;;
    lowbatt)
        echo "$date : UPS has a low battery. Current load=$(/bin/upsc localups ups.status)%. Trying forced-shutdown." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sleep 1
	sudo /bin/upscmd -u login -p pwd localups beeper.enable 2>> $logfile
        sudo /sbin/upsmon -c fsd 2>&1 >> $logfile
        ;;
    online)
        echo "$date : UPS on line. Shutdown aborted." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups shutdown.stop
        sleep 1
        sudo /sbin/upsmon -K && echo "$date : WARN : fsd flag is still on !" >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.enable 2>$logfile
        ;;
    fsd)
        echo "$date : UPS is being forced-shutdown by the master." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sleep 1
        sudo /bin/upscmd -u login -p pwd localups beeper.mute 300 2>> $logfile
        ;;
    shutdown)
        echo "$date : The system is being shutdown." >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.mute 300 2>> $logfile
        ;;
    replbatt)
        echo "$date : UPS battery is bad and needs to be replaced !!!" >> $logfile
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        sudo /bin/upscmd -u login -p pwd localups beeper.enable 2>> $logfile
        ;;
    noparent)
        echo "$date : The process that shuts down the system has died (shutdown impossible)." >> $logfile
        sudo /sbin/shutdown -h now 2>&1 >> $logfile
        ;;
    *)
        echo "$date : $0 > Unrecognized command: $1" | tee -a $logfile 1>&2
        echo "$date :     Current status=[$(/bin/upsc localups ups.status)], Charge=$(/bin/upsc localups battery.charge)%, Load=$(/bin/upsc localups ups.load)%." >> $logfile
        ;;
esac
exit 0

Réduire le nombre d'écriture sur disque pour les log et sauver la vie du SSD Ryan

  1. Créer un dossier pour les log permanentes : sudo mkdir -p /var/log.hdd/
  2. Modifier le fichier de config de /etc/logrotate.conf et ajouter la ligne olddir /var/log.hdd/ :
# see "man logrotate" for details
# rotate log files weekly
weekly

# keep 4 weeks worth of backlogs
rotate 4

# create new (empty) log files after rotating old ones
create

# uncomment this if you want your log files compressed
#compress

olddir /var/log.hdd/

# packages drop log rotation information into this directory
include /etc/logrotate.d

# no packages own wtmp, or btmp -- we'll rotate them here
/var/log/wtmp {
    missingok
    monthly
    create 0664 root utmp
    rotate 1
}

/var/log/btmp {
    missingok
    monthly
    create 0660 root utmp
    rotate 1
}

# system-specific logs may be configured here
  1. Modifier /etc/fstab pour charge /var/log sur un tmpfs :
# dossier en RAM (volatile)
tmpfs						/tmp            	tmpfs   defaults           				0    	0
tmpfs     					/var/tmp      		tmpfs   defaults    					0      	0
tmpfs     					/var/lock      		tmpfs   defaults    					0      	0
tmpfs						/var/log		tmpfs	defaults					0	0
Il est possible de s'arrêter là, si le système est rarement rebooté, et que l'on accepte de perdre les logs depuis la dernière rotation

Mod easy

FIXME devrait bien marcher pour systèmes avec peu de reboot, et permet de ne perdre aucun log !!
  1. FIXME Créer un script dans /etc/init.d/ qui appele logrotate en mode forcé pour recopier les log dans /var/log.hdd si appelé avec stop
#!/bin/sh
case "$1" in
stop)
logrotate -f /etc/logrotate.conf
;;
*)
#no-op
;;
esac
exit 0
  1. Lier le script dans /etc/rc0.d/S39savelogs
Le mieux serait de faire un service qui écoute le bon événement et ferait la manip juste avant le démontage (S40umountfs).
Cela ne respecte pas les règles logrotate (daily, weekly …) donc risque de perdre rapidement des données si peu de génération sont conservées pour un fichier donné !

Mod avancé

  1. FIXME Créer un script dans /etc/init.d qui fait :
    • en stop : copie des fichiers de /var/log vers /var/log.hdd && umount de /var/log && création des liens symboliques avec le même nom que les fichiers copiés de /var/log vers /var/log.hdd (ou lien symbolique des dossiers directement) FIXME utiliser le contenu de /var/lib/logrotate/status ? (cf. /etc/cron.daily/logrotate )
    • en start (juste après mount), copier les log de /var/log/ à la suite des fichiers existant puis écrasement des fichiers de /var/log/ par ceux de /var/log.hdd
FIXME besoin de créer 2 liens symbolique différents : nécessité de tester le nom d'appel pour vérifier si Start ou Stop && avant/après mount/umount. start + après mount = OK ; stop + avant umount = OK ; sinon ne rien faire.