Vous êtes ici:

Menu

La gestion des entrées/sorties en Python

Stacks Image 6091
L'intérêt du Raspberry est de nous fournir un bus d'entrées/sorties nommé GPIO. Pour le piloter, nous utiliserons le langage Python et sa librairie RPi.GPIO. Pour commencer, nous allons utiliser les leds RGB du Signal Centreon en Lego. Nous allons les interfacer avec le moteur de supervision Nagios.
Nous devrons trouver une solution satisfaisante pour faire fonctionner notre module. En effet, cette librairie exige les privilèges du super-utilisateur root. De plus, pour utiliser la fonctionnalité PWM ("Pulse With Modulation") permettant le clignotement des LED, notre programme doit être continuellement actif. Nous pourrions intégrer cette fonctionnalité dans le noyau, mais je préfère la solution du "deamon Unix" pour lancer notre script en tant que service.

Installation de la librairie RPi.GPIO

Toutes les commandes suivantes se feront en mode root. Pour commencer, il faudra installer les paquets prérequis pour Python et sa librairie :
apt-get install python-dev
Ensuite, récupérez les binaires sur le site python dédié au package. Copiez les binaires sur le raspberry. Exécutez les commandes suivantes :
tar xzf RPi.GPIO-0.5.4.tar.gz 
cd RPi.GPIO-0.5.4

Compilation

Compilez et installer la librairie.
python setup.py install

Principe de fonctionnement

Au démarrage du système, un script va être lancé et aura pour tâche la gestion de l'affichage des LED. Ce script appelé allume_led.py vérifiera, toutes les 10 secondes environ, un fichier de configuration et allumera les LED en fonctions de l'état de Nagios. Toutes les deux minutes, il vérifiera le fonctionnement de Nagios et alertera au besoin par un affichage spécifique des LED.
Pour modifier le fichier de configuration des LED, on utilisera la fonctionnalité event_handler de Nagios. Chaque événement sera pris en compte et le fichier de configuration sera modifié si besoin.
Tous les fichiers nécessaires à la gestion des LED seront stockés dans le dossier /usr/local/gestled. Créons ce dossier. Il faudra autoriser l'utilisateur nagios à ce dossier.
mkdir /usr/local/gestled
chown nagios:nagios /usr/local/gestled

Création du script allume_led.py

Utilisez le même montage de l'article sur le signal Centreon. Le but de ce script est de faire fonctionner les deux LEDs indépendamment l'une de l'autre. Comme nous utiliserons la fonctionnalité PWM dans une prochaine version, le script doit fonctionner en permanence en tant que service. Voici le script avec les explications.
Tout d'abord, nous devons charger les librairies nécessaires pour le Raspberry, la lecture du fichier de configuration, la mesure du temps et l'exécution de programme.
#!/usr/bin/env python# -*- coding:Utf-8 -*-#-----------------------------# allume_led.py# contrôle l'allumage ou non des LED# version 1.00 date 10/01/2014#-----------------------------# Chargement bibliothèqueimport ConfigParserimport timeimport commandsimport RPi.GPIO as GPIO
Nous initialisons les variables et les entrées-sorties du Raspberry
# initialisation constanteRGB_G_GREEN = 12RGB_G_BLUE = 11RGB_G_RED = 13RGB_D_BLUE = 15RGB_D_GREEN = 16RGB_D_RED = 18# Initialisation variableverif_nagios = 0led_gauche = 'blanc'led_droite = 'blanc'cfg = ConfigParser.ConfigParser()# Initialisation GPIOtry: # choix de la numérotation des I/O GPIO.setmode(GPIO.BOARD) #désactivation des alarmes GPIO.setwarnings(False) # initialisation des ports GPIO.setup(RGB_G_BLUE, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(RGB_G_GREEN, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(RGB_G_RED, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(RGB_D_BLUE, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(RGB_D_GREEN, GPIO.OUT, initial=GPIO.HIGH) GPIO.setup(RGB_D_RED, GPIO.OUT, initial=GPIO.HIGH)except RuntimeError: print("Error importing RPi.GPIO! This is probably because you need superuser privileges. You can achieve this by using 'sudo' to run your script")
Création des fonctions exécutant l'affichage des LED.
# Fonction gestion Led Gauchedef init_led_gauche (gauche): if gauche == 'vert': GPIO.output(RGB_G_BLUE, GPIO.HIGH) GPIO.output(RGB_G_RED, GPIO.HIGH) GPIO.output(RGB_G_GREEN, GPIO.LOW) elif gauche == 'rouge': GPIO.output(RGB_G_BLUE, GPIO.HIGH) GPIO.output(RGB_G_GREEN, GPIO.HIGH) GPIO.output(RGB_G_RED, GPIO.LOW) elif gauche == 'cyan': GPIO.output(RGB_G_BLUE, GPIO.LOW) GPIO.output(RGB_G_GREEN, GPIO.LOW) GPIO.output(RGB_G_RED, GPIO.HIGH) elif gauche == 'jaune': GPIO.output(RGB_G_BLUE, GPIO.HIGH) GPIO.output(RGB_G_GREEN, GPIO.LOW) GPIO.output(RGB_G_RED, GPIO.LOW) elif gauche == 'magenta': GPIO.output(RGB_G_BLUE, GPIO.LOW) GPIO.output(RGB_G_GREEN, GPIO.HIGH) GPIO.output(RGB_G_RED, GPIO.LOW) elif gauche == 'blanc': GPIO.output(RGB_G_BLUE, GPIO.LOW) GPIO.output(RGB_G_GREEN, GPIO.LOW) GPIO.output(RGB_G_RED, GPIO.LOW) elif gauche == 'bleu': GPIO.output(RGB_G_BLUE, GPIO.LOW) GPIO.output(RGB_G_GREEN, GPIO.HIGH) GPIO.output(RGB_G_RED, GPIO.HIGH)# Fonction gestion Led Droitedef init_led_droite (droite): if droite == 'rouge': GPIO.output(RGB_D_BLUE, GPIO.HIGH) GPIO.output(RGB_D_GREEN, GPIO.HIGH) GPIO.output(RGB_D_RED, GPIO.LOW) elif droite == 'vert': GPIO.output(RGB_D_BLUE, GPIO.HIGH) GPIO.output(RGB_D_GREEN, GPIO.LOW) GPIO.output(RGB_D_RED, GPIO.HIGH) elif droite == 'cyan': GPIO.output(RGB_D_BLUE, GPIO.LOW) GPIO.output(RGB_D_GREEN, GPIO.LOW) GPIO.output(RGB_D_RED, GPIO.HIGH) elif droite == 'magenta': GPIO.output(RGB_D_BLUE, GPIO.LOW) GPIO.output(RGB_D_GREEN, GPIO.HIGH) GPIO.output(RGB_D_RED, GPIO.LOW) elif droite == 'jaune': GPIO.output(RGB_D_BLUE, GPIO.HIGH) GPIO.output(RGB_D_GREEN, GPIO.LOW) GPIO.output(RGB_D_RED, GPIO.LOW) elif droite == 'blanc': GPIO.output(RGB_D_BLUE, GPIO.LOW) GPIO.output(RGB_D_GREEN, GPIO.LOW) GPIO.output(RGB_D_RED, GPIO.LOW) elif droite == 'bleu': GPIO.output(RGB_D_BLUE, GPIO.LOW) GPIO.output(RGB_D_GREEN, GPIO.HIGH) GPIO.output(RGB_D_RED, GPIO.HIGH)
Nous voici au coeur du programme. Il s'agit d'une boucle infinie. Le programme va lire un fichier de configuration de type ini à la "windows", situé dans le même dossier que le script, toutes les dix secondes. Ensuite, nous comparons les valeurs aux valeurs enregistrées dans le programme. Si celles-ci ont changées, on exécutera les fonctions correspondantes. Indépendamment de cette boucle, nous vérifierons, environ toutes les deux minutes, que notre moteur de supervision fonctionne sans problème.
# Programme principalwhile 1 : # lecture fichier configuration cfg.read('/usr/local/gestled/config_led.cfg') led_gauche_temp = cfg.get('General', 'led_gauche_couleur') if led_gauche_temp != led_gauche: led_gauche = led_gauche_temp init_led_gauche (led_gauche) led_droite_temp = cfg.get('General', 'led_droite_couleur') if led_droite_temp != led_droite: led_droite = led_droite_temp init_led_droite (led_droite) # tempo 10 secondes time.sleep(10) verif_nagios += 1 # toutes les deux minutes vérification Nagios if verif_nagios > 12 : verif_nagios = 0 resultat_nagios = commands.getoutput('nagios3stats -m -d NAGIOSPID -D :') resultat_splite = resultat_nagios.split(":") if int(resultat_splite[0]) != 0 : # Le serveur Nagios fonctionne, on affiche les informations du fichier de configuration init_led_droite (led_droite) init_led_gauche (led_gauche) else : # Le serveur Nagios est HS init_led_droite ('magenta') init_led_gauche ('magenta')

Création du fichier de configuration

Le fichier de configuration que nous appellerons config_led.cfg est au format INI, organisé en section et clé, comme ci-dessous :
[General]led_gauche_couleur = vertled_gauche_etat = fixeled_droite_couleur = vertled_droite_etat = fixe
Les clés led_gauche_couleur et led_droite_couleur indiquent les valeurs à afficher sur nos LED du Raspberry. Ce fichier sera modifié par la commande submit_alerte que nous verrons plus bas. Les valeurs led_gauche_etat et led_droite_etat sont réservées à une future extension. Le fichier devra être modifiable par l'utilisateur Nagios, modifiez les droits UNIX de ce fichier.
chmod 644 /usr/local/gestled/config_led.cfg
chown nagios:nagios /usr/local/gestled/config_led.cfg

Création du script eteindre_led.py

Comme l'arrêt du script allume_led.py ne permet pas un arrêt propre du GPIO du Raspberry, nous allons écrire un script qui annulera la configuration du GPIO.
#!/usr/bin/env python# -*- coding:Utf-8 -*-#-----------------------------# eteindre_led.py# extension des LED# version 1.00 date 10/01/2014#-----------------------------# Chargement bibliothèqueimport RPi.GPIO as GPIOGPIO.setmode(GPIO.BOARD)GPIO.setwarnings(False)# initialisation constanteRGB_G_GREEN = 12RGB_G_BLUE = 11RGB_G_RED = 13RGB_D_BLUE = 15RGB_D_GREEN = 16RGB_D_RED = 18# initialisation des portsGPIO.setup(RGB_G_BLUE, GPIO.OUT, initial=GPIO.HIGH)GPIO.setup(RGB_G_GREEN, GPIO.OUT, initial=GPIO.HIGH)GPIO.setup(RGB_G_RED, GPIO.OUT, initial=GPIO.HIGH)GPIO.setup(RGB_D_BLUE, GPIO.OUT, initial=GPIO.HIGH)GPIO.setup(RGB_D_GREEN, GPIO.OUT, initial=GPIO.HIGH)GPIO.setup(RGB_D_RED, GPIO.OUT, initial=GPIO.HIGH)GPIO.cleanup()
Vous pouvez récupérez le script complet ici

Création du script gestled

Création de notre script de service dans le dossier /etc/init.d
vi /etc/init.d/gestled
#!/bin/sh### BEGIN INIT INFO# Provides: gestled# Required-Start: $remote_fs $syslog# Required-Stop: $remote_fs $syslog# Should-Start:# Should-Stop:# Default-Start: 2 3 4 5# Default-Stop: 0 1 6# Short-Description: led system# Description: led system### END INIT INFODAEMON="/usr/local/gestled/allume_led.py"DAEMONUSER="root"DEAMON_NAME="allume_led.py"PIDFILE=/var/run/allume_led.pid. /lib/lsb/init-functionscase "$1" in start) log_daemon_msg "Starting system $DEAMON_NAME Daemon" start-stop-daemon --background --pidfile $PIDFILE --make-pidfile --name $DEAMON_NAME --start --quiet --chuid $DAEMONUSER --exec $DAEMON log_end_msg $? ;; stop) log_daemon_msg "Stopping system $DEAMON_NAME Daemon" start-stop-daemon --stop --pidfile $PIDFILE --verbose /usr/local/gestled/eteindre_led.py log_end_msg $? ;; *) echo "Usage: /etc/init.d/$DEAMON_NAME {start|stop}" exit 1 ;;esacexit 0
Ajoutez les droits d'exécution et activez ce service.
chmod +x /etc/init.d/gestled
update-rc.d gestled defaults

Vérification du script

Maintenant, il est temps d'essayer notre service gestled.
root@raspberrypi:~# service gestled start
[ ok ] Starting system allume_led.py Daemon:.
Les deux LED affichent la couleur verte.
Stacks Image 6249
Le cube fonctionnement correctement, aucune alerte.
Nous vérifions l'alerte si le moteur Nagios s'arrête. Stoppons le service
root@raspberrypi:~# service nagios3 stop
Après environ deux minutes d'attente, les deux LED s'affiche en couleur Magenta.
Stacks Image 6394
Le moteur de supervision ne fonctionne plus, les LEDs s'affichent en magenta
Pour arrêter le service gestled.
root@raspberrypi:~# service gestled stop
[....] Stopping system allume_led.py Daemon:Stopped process in pidfile '/var/run/allume_led.pid' (pid 23763).
. ok 
Les deux LED doivent s'éteindre. Nous allons voir la configuration de Nagios pour la prise en compte des événements.

Configuration Nagios

Nous devons activer les Event Handlers de Nagios au niveau global. Par conséquent, à chaque évènement de changement d'état d'hôtes et de services, nous lancerons une commande pour modifier la configuration de nos LED. Le programme allume_led.py tournant en deamon rechargera la nouvelle configuration si besoin est.

Activation globale des Events Handlers

Modifiez le fichier de configuration de nagios /etc/nagios3/nagios.cfg. Décommentez et modifiez les lignes suivantes :
global_host_event_handler=submit_alerte
global_service_event_handler=submit_alerte
Vérifiez la ligne suivante :
event_handler_enabled           1

Création du fichier de commande

Nous allons créer ensuite le fichier de commande pour la configuration globale des Events Handlers. Nous allons le nommer /etc/nagios3/conf.d/global_handlers.cfg
# 'submit_alerte' command definitiondefine command{ command_name submit_alerte command_line /usr/lib/nagios/plugins/submit_alerte "$HOSTNAME$" "$SERVICEDESC$" "$TOTALHOSTSDOWN$" "$TOTALHOSTSUNREACHABLE$" "$TOTALSERVICESCRITICAL$" "$TOTALSERVICESWARNING$" "$TOTALSERVICESUNKNOWN$" }

Script submit_alerte

Le script submit_alerte sera créé dans le dossier des plugins /usr/lib/nagios/plugins. Celui-ci aura pour tâche de récupérer les paramètres de Nagios afin de les envoyer à un script en python ecrit_config.py. Ce dernier se chargera de la gestion du fichier de configuration config_led.cfg. Le reste du programme submit_alerte sert à la création d'un fichier de log. J'aurais pu simplifier le fonctionnement en réalisant un seul fichier en python, mais en fait j'ai récupéré un script trouvé sur le très bon site Monitoring-fr.org.
#!/bin/bashHOSTNAME=$1SERVICEDESC=$2TOTALHOSTSDOWN=$3TOTALHOSTSUNREACHABLE=$4TOTALSERVICESCRITICAL=$5TOTALSERVICESWARNING=$6TOTALSERVICESUNKNOWN=$7YEAR=`date +%Y` # the current yearMONTH=`date +%m` # the current numeric monthDAY=`date +%d` # the current dayHOUR=`date +%H` # the current hourMINUTE=`date +%M` # the current minuteSECOND=`date +%S` # the current secondGESTLED_ROOT=/usr/local/gestled$GESTLED_ROOT/ecrit_config.py -D $TOTALHOSTSDOWN -U $TOTALHOSTSUNREACHABLE -C $TOTALSERVICESCRITICAL -W $TOTALSERVICESWARNING -u $TOTALSERVICESUNKNOWNif [ ! -f $GESTLED_ROOT/log.txt ]then echo "====== Incidents du $DAY/$MONTH/$YEAR ======" >> $GESTLED_ROOT/log.txt echo "^ Heure ^Host ^Service ^ Host Down ^ Host Unreachable ^ Service Critical ^ Service Warning ^ Service Unknown ^" >> $GESTLED_ROOT/log.txtfiecho "| $HOUR:$MINUTE:$SECOND | $HOSTNAME | $SERVICEDESC | $TOTALHOSTSDOWN | $TOTALHOSTSUNREACHABLE | $TOTALSERVICESCRITICAL | $TOTALSERVICESWARNING | $TOTALSERVICESUNKNOWN " >> $GESTLED_ROOT/log.txtexit 0
Pour la prise en compte de ces modifications, relancez Nagios
service nagios3 restart

Script ecrit_config.py

Le script python sera créé dans le dossier /usr/local/gestled. Il est utilisé pour modifier la configuration des LED.
#!/usr/bin/env python# -*- coding:Utf-8 -*-#-----------------------------# ecrit_config.py# ecriture fichier config# version 1.00 date 10/01/2014#-----------------------------# Chargement bibliothèqueimport ConfigParserimport optparseparseur = optparse.OptionParser()parseur.add_option('-D','--hostsdown',help='Total Hosts Down',dest='total_hosts_down')parseur.add_option('-U','--hostsunreachable',help='Total Hosts Unreachable',dest='total_hosts_unreachable')parseur.add_option('-C','--servicescritical',help='Total Services Critical',dest='total_services_critical')parseur.add_option('-W','--serviceswarning',help='Total Services Warning',dest='total_services_warning')parseur.add_option('-u','--servicesunknown',help='Total Services Unknown',dest='total_services_unknown')(options, args) =parseur.parse_args()cfg = ConfigParser.ConfigParser()# lecture du fichier de configurationcfg.read('/usr/local/gestled/config_led.cfg')S = 'General'# configuration des couleurs en fonction des états Nagiosif int(options.total_hosts_down) > 0: cfg.set(S, 'led_gauche_couleur', 'rouge')elif int(options.total_hosts_unreachable) > 0: cfg.set(S, 'led_gauche_couleur', 'blanc')else: cfg.set(S, 'led_gauche_couleur', 'vert')if int(options.total_services_critical) > 0: cfg.set(S, 'led_droite_couleur', 'rouge')elif int(options.total_services_warning) > 0: cfg.set(S, 'led_droite_couleur', 'jaune')elif int(options.total_services_unknown) > 0: cfg.set(S, 'led_droite_couleur', 'blanc')else: cfg.set(S, 'led_droite_couleur', 'vert')# écriture du fichier de configurationcfg.write(open('/usr/local/gestled/config_led.cfg','w'))

Vérification du fonctionnement

Vous allons vérifier le fonctionnement d'une alerte de service. Le service que nous utiliserons s'appelle HTTP. Il suffira d'arrêter le serveur Web de la machine hôte. Lorsque le moteur Nagios réalisera sa requête, le plugin retournera un état soft de type Critical. Ce qui provoquera l'exécution d'un Event Handler et par conséquent le script submit_alerte. Au bout de dix secondes maxi, le Signal Raspberry affichera une LED rouge (LED de droite).
Stacks Image 6399
Affichage d'une alarme de type service critique
Voici le log du fonctionnement. Nous remarquerons l'envoi de trois submit_alerte avec l'état SOFT et un submit_alerte avec l'état HARD.
Stacks Image 6404
Logs de Nagios
La remise en fonctionnement du service HTTP déclenchera un Event Handler avec l'Etat OK. La LED s'affichera à nouveau avec la couleur verte.

Vérification des logs

Pour chaque évènement, la commande submit_alerte va alimenter le fichier de log /usr/local/gestled/log.txt.
====== Incidents du 10/01/2014 ======^ Heure ^Host ^Service ^ Host Down ^ Host Unreachable ^ Service Critical ^ Service Warning ^ Service Unknown ^| 21:03:06 | test | $ | 1 | 0 | 0 | 0 || 21:04:16 | test | HTTP | 1 | 0 | 1 | 0 || 21:04:16 | test | $ | 1 | 0 | 1 | 0 || 21:05:26 | test | $ | 1 | 0 | 1 | 0 || 21:06:36 | test | $ | 1 | 0 | 1 | 0 || 21:07:26 | test | $ | 1 | 0 | 1 | 0 || 21:07:46 | test | $ | 1 | 0 | 1 | 0 || 21:08:36 | test | $ | 1 | 0 | 1 | 0 || 21:08:56 | test | $ | 1 | 0 | 1 | 0 || 21:09:16 | test | $ | 1 | 0 | 1 | 0 || 21:09:47 | test | $ | 1 | 0 | 1 | 0 || 21:44:09 | test | HTTP | 1 | 0 | 0 | 0 | 0| 21:44:22 | test | $ | 0 | 0 | 0 | 0 | 0| 21:54:19 | test | HTTP | 0 | 0 | 1 | 0 | 0
Nous pouvons améliorer notre système d'alerte en réalisant une distinction entre l'état SOFT et HARD, par exemple avec un clignotement des LED pour l'état SOFT. C'est ce que nous verrons lors d'un prochain article.

Références

comments powered by Disqus
 Vous êtes ici: