Centreon Signal 2

Principe de fonctionnement
Pour cette nouvelle version, nous utiliserons le protocole UDP qui n'exige pas de contrôle de flux. Une trame est émise par un script lancé par un cron toutes les minutes. Le script effectuera une requête sur la base Centstatus ou Centstorage en fonction du type de broker défini par un paramètre.
Le script serveur UDP sera installé sur un ordinateur Raspberry. Grâce à la librairie GPIO, nous accèderons au module d'entrée/sortie logique pour commander des LED RGB. Dans ce premier montage, nous utiliserons des couleurs basiques : VERT, ROUGE, JAUNE, BLEU et BLANC.
La première LED affiche l'état des Hôtes et la deuxième l'état des Services, les services les plus critiques seront affichés en priorité.
Le script serveur UDP sera installé sur un ordinateur Raspberry. Grâce à la librairie GPIO, nous accèderons au module d'entrée/sortie logique pour commander des LED RGB. Dans ce premier montage, nous utiliserons des couleurs basiques : VERT, ROUGE, JAUNE, BLEU et BLANC.
La première LED affiche l'état des Hôtes et la deuxième l'état des Services, les services les plus critiques seront affichés en priorité.

Principe de fonctionnement

Schéma électrique réalisé avec Fritzing
Matériel requis
Pour la réalisation de ce montage, nous aurons besoin :
- de briques Lego que l'on peut acheter au détail sur le site Lego Pick A Brick,
- d'un ordinateur Raspberry,
- d'une platine d'essai (optionnelle) pour le montage électronique,
- de deux LED RGB de diamètre trois millimètres,
- d'une petite plaque de plastique pour fixer les LEDs,
- de six résistances de 330 ohms,
- des câbles nécessaires aux montages (les câbles de platine d'essai sont très bien).
Montage du signal
Les instructions de montage du signal en Lego se trouvent ici.

Schéma de cablage
L'image ci-contre représente le montage réel hors du coffret Lego. Les LEDs ont été fixés sur une plaque de Plexi. La plaque d'essai nous permet un montage plus souple et autorise les modifications qui seront apportées dans le futur.
L'utilisation d'adaptateur mâle/mâle permet la réutilisation de connecteur de lecteur CD/DVD.
On utilisera du matériel de récupération pour le montage des LEDs (plaque de plexi percée aux dimensions des LEDs, souplisseau pour protéger des courts-circuits et câble de récupération d'anciens ordinateurs).



Et voici le montage du circuit électrique dans le boîtier Lego

Positionnement du Raspberry, l'emplacement pour la platine d'essai étant enlevé. Avant de fermer le boîtier, penser à connecter le câble d'alimentation.

Repositionner l'emplacement de la platine d'essai et l'insérer doucement.

Ouvrir délicatement la boîte comme indiqué sur la photo.

C'est l'opération la plus délicate, il faut enlever les briques Lego par le bas et insérer la plaque de Plexi sans abimer les connexions au LEDs.

Remettre les briques Lego et repositionner délicatement le tout sur la plaque de fond.

Le montage est terminé, vous pouvez refermer la boîte.
Le progamme
Le programme python installé sur le serveur Centreon que l'on appellera sendcentreon.py
et le programme installé sur le raspberry que l'on nommera server_udp.py#!/usr/bin/env python # -*- coding:Utf-8 -*- #*********************************************************** #* sendcentreon.py * #* envoie les informations au signal centreon * #* version 1:00 date 08/01/2013 * #*********************************************************** from optparse import OptionParser # chargement des librairies import MySQLdb import sys import socket import time # initialisation des variables UDP_IP = '127.0.0.1' UDP_PORT = 20000 HOST_MYSQL = 'localhost' USER_MYSQL = 'centreon' PWD_MYSQL = 'passwd' # définitions des options options = {} options[('-b','--broker')] = {'dest':'broker', 'help':'nom du broker'} options[('-i','--ip')] = {'dest':'ip', 'help':'adresse destination'} # affichage des options def main(options, arguments): print('options %s' % options) print('arguments %s' % arguments) # récupérations des options if __name__ == '__main__': parser = OptionParser() for param, option in options.items(): parser.add_option(*param, **option) options, arguments = parser.parse_args() if options.ip != "": UDP_IP = options.ip ADRESSE=(UDP_IP,UDP_PORT) BUFFER_SIZE = 1024 MESSAGE="Host:unknown,Service:unknown" #connection à la base de données if options.broker == "broker": conn = MySQLdb.connect(HOST_MYSQL,USER_MYSQL,PWD_MYSQL, 'centstorage') elif options.broker == "ndo": conn = MySQLdb.connect(HOST_MYSQL,USER_MYSQL,PWD_MYSQL, 'centstatus') else: print "broker inconnu !" sys.exit(0) curs = conn.cursor() # vérification des hosts if options.broker == "broker": result=curs.execute("SELECT count(DISTINCT name), state FROM hosts WHERE name NOT LIKE '_Module_%' AND hosts.enabled = 1 group by state") elif options.broker == "ndo": result=curs.execute("SELECT count(DISTINCT nagios_objects.name1), nagios_hoststatus.current_state FROM nagios_hoststatus, nagios_objects WHERE nagios_objects.object_id = nagios_hoststatus.host_object_id AND nagios_objects.is_active = 1 AND nagios_objects.name1 NOT LIKE '_Module_%' GROUP BY nagios_hoststatus.current_state") # récupération du nombre d'enregistrement numrows = int(curs.rowcount) # initialisation host alarme host_alarme = 0 # lecture des enregistrements for x in range(0, numrows): result=curs.fetchone() if result[1] == 1: host_alarme = 1 break if result[1] == 4: host_alarme = 4 # affichage heure print "envoi le :",time.strftime('%d/%m/%y à %H:%M',time.localtime()) # résultat host if host_alarme == 1: print "host down" elif host_alarme == 4: print "host pending" else: print "Host OK" # vérification des services if options.broker == "broker": result = curs.execute("SELECT COUNT(DISTINCT CONCAT(s.service_id,';', s.host_id)) as number, s.state_type, s.acknowledged, s.scheduled_downtime_depth, s.state FROM services s, `hosts` h WHERE s.host_id IS NOT NULL AND s.host_id = h.host_id AND s.scheduled_downtime_depth = '0' AND s.acknowledged = '0' AND s.state <> '0' AND h.state = '0' AND s.enabled = 1 AND h.enabled = 1 GROUP BY s.state, s.acknowledged, s.scheduled_downtime_depth") elif options.broker == "ndo": result = curs.execute("SELECT COUNT(DISTINCT CONCAT(no.name1,';', no.name2)) as number, nss.state_type, nss.problem_has_been_acknowledged, nss.scheduled_downtime_depth, nss.current_state FROM nagios_servicestatus nss, nagios_objects no, nagios_hoststatus nhs, nagios_services ns WHERE no.object_id = nss.service_object_id AND no.name1 NOT LIKE '_Module_%' AND no.is_active = 1 AND nss.scheduled_downtime_depth = '0' AND nss.problem_has_been_acknowledged = '0' AND nss.current_state != '0' AND no.object_id = ns.service_object_id AND ns.host_object_id = nhs.host_object_id AND nhs.current_state = '0' GROUP BY nss.current_state, nss.problem_has_been_acknowledged, nss.scheduled_downtime_depth") # récupération du nombre d'enregistrement numrows = int(curs.rowcount) # inialisation service alarme service_alarme = 0 # lecture des enregistrement for x in range(0, numrows): result=curs.fetchone() if result[4] == 2: # Critical service_alarme = 2 break if result[4] ==1 and service_alarme==0: # Warning service_alarme = 1 if result[4] == 3 and service_alarme==0: # Unknow service_alarme = 3 if result[4] == 4 and service_alarme==0: # Pending service_alarme = 4 # resultat service if service_alarme == 0: print "Services OK" elif service_alarme == 1: print "Services Warning" elif service_alarme == 2: print "Services Critical" elif service_alarme == 3: print "Services Unknow" else: print "Services Pending" curs.close() conn.close() # préparation du message et envoi au signal MESSAGE = "Host:"+str(host_alarme)+", Service:" +str(service_alarme) print MESSAGE s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.sendto(MESSAGE,ADRESSE) s.close()
#!/usr/bin/env python # -*- coding:Utf-8 -*- # Serveur UDP utilisant le module socket # import nécessaire au fonctionnement du serveur import socket import time import RPi.GPIO as GPIO import os # imports seulement nécessaires à l'exemple (=calcul d'expression par eval()) import sys from math import * # initialisation des ports GPIO.setup(11, GPIO.OUT) GPIO.setup(12, GPIO.OUT) GPIO.setup(13, GPIO.OUT) GPIO.setup(15, GPIO.OUT) GPIO.setup(16, GPIO.OUT) GPIO.setup(18, GPIO.OUT) GPIO.output(11, True) GPIO.output(12, True) GPIO.output(13, True) GPIO.output(15, True) GPIO.output(16, True) GPIO.output(18, True) buf=1024 adresse=('',20000) socketserveur=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) socketserveur.bind(adresse) print "serveur actif" # boucle de service du serveur while True: # attente d'une nouvelle connexion # et enregistrement de la requete et de l'adresse du demandeur requete, adresseclient = socketserveur.recvfrom(buf) if not requete: break data=requete.strip() # Affichage des informations reçues print "received data:", data # traitement des information if data[5] == "1": print "affichage host down led rouge" # réglage led GPIO.output(11, True) GPIO.output(12, True) GPIO.output(13, False) elif data[5] == "4": print "affichage host pending led bleu" # réglage led GPIO.output(12, True) GPIO.output(13, True) GPIO.output(11, False) elif data[5] == "0": print "affichage host ok led verte" # réglage led GPIO.output(11, True) GPIO.output(13, True) GPIO.output(12, False) if data[16] == "1": print "affichage service warning led jaune" # réglage led GPIO.output(15, True) GPIO.output(16, False) GPIO.output(18, False) elif data[16] == "2": # réglage led GPIO.output(15, True) GPIO.output(16, True) GPIO.output(18, False) print "affichage service critical pending led rouge" elif data[16] == "3": # réglage led GPIO.output(15, False) GPIO.output(16, False) GPIO.output(18, False) print "affichage service Unknown pending led blanche" elif data[16] == "4": # réglage led GPIO.output(15, False) GPIO.output(16, True) GPIO.output(18, True) print "affichage service pending pending led bleu" elif data[16] == "0": GPIO.output(15, True) GPIO.output(16, False) GPIO.output(18, True) print "affichage service ok led verte" socketserveur.close()
Configuration des systèmes
Pour le serveur Centreon, vous aurez besoin de Python (normalement déjà installé) et de la librairie Mysql pour Python.
Copiez le script sendcentreon.py dans le dossier de votre choix, par exemple pour un utilisateur appelé vmdebian
Ajoutons une tâche cron exécutant le script toutes les minutes.
ajoutons la ligne suivante pour un broker ndo
pour un broker centreon-broker
Le premier paramètre i permet de renseigner l'adresse IP du signal Centreon et le deuxième le type de broker (ndo pour NDOutils, broker pour Centreon-Broker). La redirection des messages de sortie n'est pas indispensable, mais fortement conseillée pour d'éventuels débogages.
Pour le Signal, nous utiliserons une version debian pour Raspberry avec l'installation de la bibliothèque GPIO pour Python. Installez le script server_udp.py dans le dossier utilisateur pi. Lancez le serveur avec la commande ci-dessous.
Au bout d'environ une minute, les LEDs s'afficheront ainsi que les lignes suivantes sur le terminal
apt-get install python-mysqldb
Copiez le script sendcentreon.py dans le dossier de votre choix, par exemple pour un utilisateur appelé vmdebian
cp sendcentreon.py /home/vmdebian
chown vmdebian:vmdebian /home/vmdebian/sendcentreon.py
chmod +x /home/vmdebian/sendcentreon.py
Ajoutons une tâche cron exécutant le script toutes les minutes.
crontab -e
ajoutons la ligne suivante pour un broker ndo
* * * * * /home/vmdebian/sendcentreon.py -i [Adresse IP du signal] -b ndo >> /home/vmdebian/sendcentreon.log
pour un broker centreon-broker
* * * * * /home/vmdebian/sendcentreon.py -i [Adresse IP du signal] -b broker >> /home/vmdebian/sendcentreon.log
Le premier paramètre i permet de renseigner l'adresse IP du signal Centreon et le deuxième le type de broker (ndo pour NDOutils, broker pour Centreon-Broker). La redirection des messages de sortie n'est pas indispensable, mais fortement conseillée pour d'éventuels débogages.
Pour le Signal, nous utiliserons une version debian pour Raspberry avec l'installation de la bibliothèque GPIO pour Python. Installez le script server_udp.py dans le dossier utilisateur pi. Lancez le serveur avec la commande ci-dessous.
pi@raspberrypi:~$ sudo python server_udp.py
serveur actif
Au bout d'environ une minute, les LEDs s'afficheront ainsi que les lignes suivantes sur le terminal
serveur actif
received data: Host:1, Service:0
affichage host down led rouge
affichage service ok led verte
Fonctionnement
Voici quelques exemples du fonctionnement de Centreon Signal 2

Host : Critical, Service : Critical

Host : Critical, Service : Warning

Host : Critical, Service : OK

Host : OK, Service : Critical

Host : OK, Service : Warning

Host : OK, Service : Unknown

Host : OK, Service : Pending

Host : Pending, Service : OK

Host : OK, Service : OK
Prochain épisode, l'intégration d'une alarme sonore...