Pour pouvoir tracer des jolies courbes illustrant les services que me rend mon onduleur APC back-UPS pro 900, j’ai fait un petit script qui utilise le fantastique démon apcupsd (que j’ai installé depuis les dépôts debian) pour relever les différentes métriques fournies par l’onduleur et les remonter en utilisant snmp dans zabbix que j’utilise pour la supervision. Au delà des graphiques, ce qui est intéressant là-dedans est aussi de profiter des alertes que peut générer zabbix en cas de souci. Voici un exemple de supervision d’un onduleur APC avec apcupsd, snmp et zabbix.
apcupsd
Bien sûr, étant ultra-complet, apcupsd sait très bien faire tout ce qu’on pourrait imaginer avoir envie de faire en cas de coupure de courant à la prise électrique, y compris envoyer des alertes, ou exécuter toutes sortes de scripts. Cependant, comme j’utilise zabbix pour superviser un peu toute mon infra, il me paraissait logique d’y concentrer aussi la supervision de l’onduleur.
Par conséquent, je n’ai pas altéré beaucoup la configuration par défaut du démon, et me suis contenté simplement de paramétrer le type de mon onduleur et le type de liaison qu’il utilise, ainsi que la valeur de batterie restante (en pourcentage, et en minutes) avant de déclencher un arrêt propre de la machine. C’est ultra-minimaliste au regard de toutes les possibilités offertes par le démon, dont on peut avoir un aperçu en RTFM un petit peu, mais ça suffit pour ce que je veux faire.
On peut vérifier que la communication est fonctionnelle entre l’OS et l’onduleur avec la commande suivante, fournie par le paquet apcupsd:
root@xxx:~# apcaccess
APC : xxx,xxx,xxx
DATE : 2019-04-08 22:06:35 +0200
HOSTNAME : xxx
VERSION : 3.14.14 (31 May 2016) debian
UPSNAME : apc1
CABLE : USB Cable
DRIVER : USB UPS Driver
UPSMODE : Stand Alone
STARTTIME: 2019-03-16 19:34:47 +0100
MODEL : Back-UPS RS 900G
STATUS : ONLINE
LINEV : 235.0 Volts
LOADPCT : 26.0 Percent
BCHARGE : 100.0 Percent
TIMELEFT : 40.9 Minutes
MBATTCHG : 15 Percent
MINTIMEL : 8 Minutes
MAXTIME : 0 Seconds
SENSE : Medium
LOTRANS : 176.0 Volts
HITRANS : 294.0 Volts
ALARMDEL : No alarm
BATTV : 27.1 Volts
LASTXFER : Automatic or explicit self test
NUMXFERS : 2
XONBATT : 2019-04-07 09:47:54 +0200
TONBATT : 0 Seconds
CUMONBATT: 12 Seconds
XOFFBATT : 2019-04-07 09:48:04 +0200
LASTSTEST: 2019-04-07 09:47:54 +0200
SELFTEST : NO
STATFLAG : 0x05000008
SERIALNO : 3B1237X01578
BATTDATE : 2019-03-15
NOMINV : 230 Volts
NOMBATTV : 24.0 Volts
NOMPOWER : 540 Watts
FIRMWARE : 879.L4 .I USB FW:L4
END APC : 2019-04-08 22:06:36 +0200
Si ça retourne quelque chose qui ressemble à la sortie ci-dessus, c’est que la communication entre l’onduleur et le démon apcupsd fonctionne. On constate qu’une multitude d’informations remontent, et on voit par exemple que j’ai installé une batterie neuve le 19 mars 2019; la précédente ayant rendu l’âme après un peu plus de 5 années de service.
Le script qui va récupérer les données intéressantes est le suivant:
#!/bin/bash
#
RAWSTATUS=`apcaccess`
#echo "$RAWSTATUS"
# 1 input voltage
INPUTVOLTAGE=$(echo "$RAWSTATUS" | grep LINEV | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 2 low input voltage transfert
LOWINVOLTRANS=$(echo "$RAWSTATUS" | grep LOTRANS | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 3 high input voltage transfert
HIGHINVOLTRANS=$(echo "$RAWSTATUS" | grep HITRANS | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 4 battery voltage
BATTERYVOLTAGE=$(echo "$RAWSTATUS" | grep BATTV | grep -v NOM | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 5 nominal battery voltage
NOMBATTERYVOLTAGE=$(echo "$RAWSTATUS" | grep NOMBATTV | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 6 battery charge
BATTERYCHARGE=$(echo "$RAWSTATUS" | grep BCHARGE | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 7 time left
TIMELEFT=$(echo "$RAWSTATUS" | grep TIMELEFT | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 8 load percentage
LOADPERCENTAGE=$(echo "$RAWSTATUS" | grep LOADPCT | cut -d ':' -f 2 | cut -d ' ' -f 2 | cut -d '.' -f 1)
# 9 load power
NOMINALPOWER=$(echo "$RAWSTATUS" | grep NOMPOWER | cut -d ':' -f 2 | cut -d ' ' -f 2)
LOADPOWER=$(($LOADPERCENTAGE * $NOMINALPOWER / 100))
# 10 nominal power
# 11 UPS status
UPSSTATUSTEXT=$(echo "$RAWSTATUS" | grep STATUS | cut -d ':' -f 2 | cut -d ' ' -f 2)
if [ "$UPSSTATUSTEXT" == "ONLINE" ];
then
UPSTATUS=1
else
UPSTATUS=0
fi
# 12 Date de dernier transfert sur batterie
XONBATT=$(echo "$RAWSTATUS" | grep XONBATT | sed s/:/=/ | cut -d '=' -f 2)
# 13 duree du dernier transfert sur batterie
TONBATT=$(echo "$RAWSTATUS" | grep TONBATT | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 14 duree cumulee du temps sur batterie depuis le dernier restart de apcupsd
CUMONBATT=$(echo "$RAWSTATUS" | grep CUMONBATT | cut -d ':' -f 2 | cut -d ' ' -f 2)
# 15 cause du dernier passage sur batterie
LASTXFER=$(echo "$RAWSTATUS" | grep LASTXFER | cut -d ':' -f 2)
# afficher tout ca
echo $INPUTVOLTAGE
echo $LOWINVOLTRANS
echo $HIGHINVOLTRANS
echo $BATTERYVOLTAGE
echo $NOMBATTERYVOLTAGE
echo $BATTERYCHARGE
echo $TIMELEFT
echo $LOADPERCENTAGE
echo $LOADPOWER
echo $NOMINALPOWER
echo $UPSTATUS
echo $XONBATT
echo $TONBATT
echo $CUMONBATT
echo $LASTXFER
Il récupère une quinzaine de mesures, et les affiche. Il faut maintenant remonter ces informations par snmp.
snmpd
Ce qu’il y a de sympa avec le démon snmpd, c’est qu’on peut l’étendre pour lui faire exécuter un script de son choix, pour remonter toutes sortes de mesures; c’est ce que je vais utiliser ici. Voici la directive à ajouter au fichier de configuration du démon snmpd.
extend apcupsd /bin/bash /etc/apcupsd/apcups_snmp.sh
Le premier mot clé indique que nous voulons « étendre » l’agent snmp. Le deuxième mot clé nomme cette partie de l’extension, et la suite indique l’interpréteur et le script à exécuter lorsque l’agent est interrogé.
zabbix
Il ne reste plus qu’à créer un template pour zabbix qui va aller interroger cette extension de l’agent snmp et nous tracer les beaux graphiques dont nous rêvons.
Voici l’export d’un template zabbix v4 qui utilise snmp v1, qui nous donne quelques jolies données comme ci-dessous:
Le template contient également les déclencheurs d’alerte qui me conviennent, avec les seuils de durée restante de batterie pertinents pour moi.
o/