Vous êtes ici:

Menu


Stacks Image 36912
Voici la présentation de mon projet Laptop en Lego pour présenter une démo de Centreon à l'Open Source Summit de Paris qui s'est déroulé le 6 et 7 décembre 2017. Ce projet a commencé fin août sur le papier pour se terminer la veille su salon avec les dernières mises au point.
Je voulais, avec ce projet, présenter un fonctionnement simple et ludique de la supervision Centreon. Tout en présentant ce matériel sous forme ludique, les briques Lego étant tout à fait adapté pour cela !

1 Le synoptique général du montage

Le but de ce montage était de présenter une architecture Centreon distribuée réalisée avec le socle Open-Source et l'intégration de Nagvis comme cartographie. Pour rendre la solution ludique, il a été ajouté des interfaces entrée-sortie grâce au port GPIO des raspberry.
Deux raspberry ont été requis pour ce montage : un PI 3 pour le Central équipé d'un disque dur PiDrive, un PI 1 pour le poller. Pour communiquer, le PI 3 étant équipé d'un émetteur Wifi, cette solution a été privilégié pour faire communiquer tout ce petit monde. Le Central a été configuré en point d'accès et un dongle wifi a été rajouté sur le PI 1 et pour communiquer vers l'extérieur le Central fait office de routeur et serveur dhcp pour le réseau interne. Cette configuration m'a permis de communiquer avec mon installation hors de toute connexion avec le monde extérieur.
Un équipement indispensable lorsque vous démarrez un raspberry en l'absence de tous réseaux, une carte horloge RTC équipe le raspberry PI 3. En effet, ces ordinateurs Low-cost n'ont pas de mémorisation de l'heure comme les grands. Il faut absolument une base de temps valide pour un fonctionnement optimal de Centreon et surtout en architecture distribuée.
En ce qui concerne les entrées-sorties et pour rendre le projet plus visuel, j'ai rajouté une visualisation du temps réel par l'intermédiaire de LEDs à trois couleurs à l'instar d'un feu tricolore. Ce montage ressemble beaucoup au précédent signal Centreon sauf qu'il n'utilise plus une bidouille d'interrogation de la base Centreon_storage mais une API Rest développé par l'équipe de Centreon pour interroger le temps réel de la supervision. Et pour finir, un écran Nokia servira pour les notifications comme si la supervision envoyait des emails.
Pour rester dans le mode ludique, il était indispensable de trouver une solution geek pour réaliser les démonstrations. Rien de tel que l'utilisation des Lego sous forme de Lego ! L'idée m'est venue d'une exposition Lego dans ma région. Ces boutons actionnent des interrupteurs miniatures connectés au GPIO. Il restait à trouver le programme idéal pour la simulation. N'ayant pas le temps adéquat pour développer une application graphique, Il fallait que je trouve un langage de programmation évolué et rapide à comprendre. Mon choix s'est arrêté sur Livecode version community et Gambas 3. J'ai vite abandonné Livecode car je n'ai pas réussi à le faire tourner sur Raspbian Jessie.
Voilà le projet au complet, reste à assembler tout ce petit monde ;)
Stacks Image 969841
Synoptique générale du projet

2 La construction du Laptop

La construction du Laptop s'est fait au fil de l'eau sans de véritable plan. Seul aide, les pages de ce site trouvé au hasard de mes recherches pour l'articulation de l'écran.
Stacks Image 969529
Création de la base
Stacks Image 969553
Positionnement des raspberry et du disque dur Pidrive. Vous distinguez sur le PI 3, la carte additionnelle pour l'horloge RTC.
Stacks Image 969646
Premier test d'installation du clavier sans fil
Stacks Image 969650
Premier test d'installation des boutons
Stacks Image 969674
Première version du Laptop, écran abaissé
Stacks Image 969678
Version à quatre boutons et test du logo Centreon
Stacks Image 969702
Test d'articulation avec d'anciens lego technique
Stacks Image 969706
Test d'articulation avec d'anciens lego technique
Stacks Image 969730
Création des boutons
Stacks Image 969734
Création des boutons
Stacks Image 969758
Deuxième version du laptop avec six boutons en façade
Stacks Image 969762
Les articulations précédentes sont installées, reste à mettre le logo Centreon.
Stacks Image 969786
Version finalisée avec les lego plats pour construire le logo
Stacks Image 969790
Ajout d'un système à Led pour les notifications
Stacks Image 969814
L'articulation avec les anciens technics n'étant pas fiable, achat d'une boîte Lego pour changer les articulations avec des pièces plus robustes.
Stacks Image 969818
Troisième et ultime version qui m'a pris une bonne partie d'une journée

3 La gestion des boutons

J'ai donc utilisé un Visual Studio Like utilisant des instructions en basic pour réaliser ma gestion des boutons en Lego. Programme relativement simple utilisant deux fenêtres : la fenêtre principale et une fenêtre de dialogue adaptée à l'utilisation des boutons.
Stacks Image 969562
la fenêtre principale FMain
Et voici le code. Ne pas oublier de rajouter trois objet timer nommé respectivement timerTempo, timerHost et timerPoller. Avec le dernier bouton, nous allons pouvoir sélectionner trois choix de fonctions différents pour les cinq boutons restants. Nous augmentons la capacité des fonctions de notre Laptop : 3 choix * 5 boutons = 15 fonctions. Le dernier bouton servira aussi à valider nos choix de fonctions.
' Gambas class file

Library "/usr/local/lib/libpigpio"

Public Extern gpioInitialise() As Integer   'call at start of program to initialise
 
Public Extern gpioTerminate() As Integer    'call at end of program to release resources and terminate threads

Public Extern gpioVersion() As Integer
Public Extern gpioHardwareRevision() As Integer

Public Extern gpioSetMode(iPin As Integer, iMode As Integer) As Integer
Public Extern gpioRead(iPin As Integer) As Integer
Public Extern gpioWrite(iPin As Integer, iLevel As Integer) As Integer

Public Centreon_Start As Boolean = False
Public Nb_appuie_Button2 As Integer = 0
Public Create_poller As Boolean = False
Public Create_host As Boolean = False
Public ChoixBouton As Integer = 1
Public valider As Boolean = False

Public Lego_Button1 As Integer
Public Lego_Button2 As Integer
Public Lego_Button3 As Integer
Public Lego_Button4 As Integer
Public Lego_Button5 As Integer
Public Lego_Button6 As Integer

Const PI_INPUT As Integer = 0
Const PI_OUTPUT As Integer = 1


Public Sub LabelChoix_MouseDown()

  

End

Public Sub LblBouton1_MouseDown()

  

End

Public Sub Form_Open()

  Dim intReply As Integer

  intReply = gpioInitialise()
  If intReply < 0 Then
    LblInformation.Text = "Failed: must be run as root"
    'Button1.Enabled = False
  Else
    LblInformation.Text = "Initialised: pigpio version no: " & intReply
    LblInfo.Text = "Pi hardware rev: " & Hex$(gpioHardwareRevision())
    LblInfo.Text &= ",  pigpio vers: " & gpioVersion()
    Me.Tag = 0
  Endif
  gpioSetMode(21, PI_INPUT)
  gpioSetMode(20, PI_INPUT)
  gpioSetMode(18, PI_INPUT)
  gpioSetMode(25, PI_INPUT)
  gpioSetMode(24, PI_INPUT)
  gpioSetMode(23, PI_INPUT)

  gpioWrite(21, 1)
  gpioWrite(20, 1)
  gpioWrite(18, 1)
  gpioWrite(25, 1)
  gpioWrite(24, 1)
  gpioWrite(23, 1)
  
End

Public Sub Form_Close()

  gpioTerminate()

End

Public Sub TimerStart_Timer()  
  
  Lego_Button1 = gpioRead(21)
  Lego_Button2 = gpioRead(20)
  Lego_Button3 = gpioRead(18)
  Lego_Button4 = gpioRead(25)
  Lego_Button5 = gpioRead(24)
  Lego_Button6 = gpioRead(23)
  If Lego_Button1 = 0 Then
    ColorButton1.Value = Color.Orange
  Else
    ColorButton1.Value = Color.White
  Endif
   If Lego_Button2 = 0 Then
    ColorButton2.Value = Color.Orange
  Else
    ColorButton2.Value = Color.White
  Endif
   If Lego_Button3 = 0 Then
    ColorButton3.Value = Color.Orange
  Else
    ColorButton3.Value = Color.Green
  Endif
   If Lego_Button4 = 0 Then
    ColorButton4.Value = Color.Orange
  Else
    ColorButton4.Value = Color.Yellow
  Endif
   If Lego_Button5 = 0 Then
    ColorButton5.Value = Color.Orange
  Else
    ColorButton5.Value = Color.Red
  Endif
   If Lego_Button6 = 0 Then
    ColorButton6.Value = Color.Orange
  Else
    ColorButton6.Value = Color.White
  Endif
  
  If Lego_Button1 = 0 And ChoixBouton = 1 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Start Centreon ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      FQuestion.Text = "Information"
      FQuestion.Information = "Start Centreon !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
      Shell "sudo /home/pi/centreon/start_centreon.sh" 
    End If  
  End If
  
  If Lego_Button2 = 0 And ChoixBouton = 1 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Stop Centreon ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      FQuestion.Text = "Information"
      FQuestion.Information = "Centreon stop !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
      Shell "sudo /home/pi/centreon/stop_centreon.sh" 
    End If  
  Endif
  
  If Lego_Button1 = 0 And ChoixBouton = 2 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Create Poller ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      FQuestion.Text = "Information"
      FQuestion.Information = "Poller create !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
      Shell "sudo /home/pi/centreon/create_poller.sh" 
    End If
  End If
  
  If Lego_Button2 = 0 And ChoixBouton = 2 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Delete Poller ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      FQuestion.Text = "Information"
      FQuestion.Information = "Poller Deleted !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
      Shell "sudo /home/pi/centreon/delete_poller.sh" 
    End If
  End If

  If ChoixBouton = 3 And Lego_Button1 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Create Host ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/create_host.sh" 
      FQuestion.Text = "Information"
      FQuestion.Information = "Create Host OK !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
  End If
  
  If ChoixBouton = 3 And Lego_Button3 = 0 Then
    FQuestion.Information = "Etes-vous sur ?"
    FQuestion.ShowModal
    TimerStart.Enabled = False
    Timer1.Enabled = True
    If valider = True Then
      Message.Info("réussi !!!")
    End If
    
  End If
  
  If ChoixBouton = 3 And Lego_Button2 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Delete Host ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/delete_host.sh" 
      FQuestion.Text = "Information"
      FQuestion.Information = "Host Deleted !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
  End If

  If ChoixBouton = 1 And Lego_Button3 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Trap OK ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/script_ok.sh" 
      FQuestion.Text = "Information"
      FQuestion.Information = "Trap OK !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
 End If

  If ChoixBouton = 1 And Lego_Button4 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Trap warning ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/script_warning.sh"  
      FQuestion.Text = "Information"
      FQuestion.Information = "Trap Warning !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
 End If

  If ChoixBouton = 1 And Lego_Button5 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Trap Critical ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/script_critical.sh"  
      FQuestion.Text = "Information"
      FQuestion.Information = "Trap critical !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
  End If

If ChoixBouton = 3 And Lego_Button4 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Shutdown Poller ?"
    FQuestion.ShowModal
    'TimerStart.Enabled = False
    'Timer1.Enabled = True
    If valider = True Then
      Shell "sudo /home/pi/centreon/arretpi.sh" 
      FQuestion.Text = "Information"
      FQuestion.Information = "Command initiate !!!"
      FQuestion.ShowModal
      TimerStart.Enabled = False
      Timer1.Enabled = True
    End If
  End If

  If ChoixBouton = 3 And Lego_Button5 = 0 Then
    FQuestion.Text = "Question"
    FQuestion.Information = "Quit program ?"
    FQuestion.ShowModal
    TimerStart.Enabled = False
    Timer1.Enabled = True
    If valider = True Then
      FMain.Close
    End If
  End If

  
  If ChoixBouton = 1 And Lego_Button6 = 0 Then
    FMain.Activate
    LabelChoix.text = "Choix 2"
    LabelButton1.text = "add Poller"
    LabelButton2.text = "Delete Poller"
    LabelButton3.text = "Libre"
    LabelButton4.text = "Libre"
    LabelButton5.text = "Libre"
    TimerHost.Enabled = True
  End If

  If ChoixBouton = 2 And Lego_Button6 = 0 Then
    FMain.Activate
    LabelChoix.text = "Choix 3"
    LabelButton1.text = "add Host"
    LabelButton2.text = "Delete Host"
    LabelButton3.text = "Libre"
    LabelButton4.text = "Arret Poller"
    LabelButton5.text = "Quitter"
    TimerHost.Enabled = True
  Endif

  
  If ChoixBouton = 3 And Lego_Button6 = 0 Then
    FMain.Activate
    LabelChoix.text = "Choix 1"
    LabelButton1.text = "Start Centreon"
    LabelButton2.text = "Stop Centreon"
    LabelButton3.text = "Trap OK"
    LabelButton4.text = "Trap Warning"
    LabelButton5.text = "Trap Critical"
    TimerHost.Enabled = True
  Endif



End



Public Sub TimerTempo_Timer()
If Centreon_Start Then
  Centreon_Start = False
Else
  Centreon_Start = True
Endif
TimerTempo.Enabled = False  

End

Public Sub TimerPoller_Timer()
  Nb_appuie_Button2 = Nb_appuie_Button2 + 1
  If Nb_appuie_Button2 > 1 Then 
    Nb_appuie_Button2 = 0
  Endif
  TimerPoller.Enabled = False  
  
End

Public Sub TimerHost_Timer()
  ChoixBouton = ChoixBouton + 1
  If ChoixBouton > 3 Then
    ChoixBouton = 1
  Endif
  TimerHost.Enabled = False
  
End




Public Sub LabelButton2_MouseDown()

  

End

Public Sub Timer1_Timer()

  Timer1.Enabled = False
  TimerStart.Enabled = True

End
Comme je voulais avoir une fenêtre personnalisée avec validation avec les boutons Lego, j'ai créé un autre fenêtre appelé FQuestion
Stacks Image 969851
la fenêtre FQuestion
Et son code. Ne pas oublier d'ajouter l'objet timer dans cette fenêtre.
' Gambas class file


Public Information As String = ""

Public Sub Form_Activate()

  Timer1.Enabled = True
  LabelInformation.text = Information

End

Public Sub Form_Close()

  Timer1.Enabled = False

End

Public Sub Timer1_Timer()

  FMain.Lego_Button1 = FMain.gpioRead(21)
  FMain.Lego_Button2 = FMain.gpioRead(20)
  FMain.Lego_Button3 = FMain.gpioRead(18)
  FMain.Lego_Button4 = FMain.gpioRead(25)
  FMain.Lego_Button5 = FMain.gpioRead(24)
  FMain.Lego_Button6 = FMain.gpioRead(23)
  If FMain.Lego_Button6 = 0 Then
   FMain.valider = True
   FQuestion.Close
  Endif
  If FMain.Lego_Button1 = 0 Then
   FMain.valider = False
   FQuestion.Close
  End If
  If FMain.Lego_Button2 = 0 Then
   FMain.valider = False
   FQuestion.Close
  End If
  If FMain.Lego_Button3 = 0 Then
   FMain.valider = False
   FQuestion.Close
  End If
  If FMain.Lego_Button4 = 0 Then
   FMain.valider = False
   FQuestion.Close
  End If
  If FMain.Lego_Button5 = 0 Then
   FMain.valider = False
   FQuestion.Close
  End If

End

4 Les LED affichant le statut du temps réel

Les LEDs tricolores affichent en permanence l'état de la supervision (temps réel) grâce à l'API Rest. Nous utiliserons le raspberry faisant office de poller. Il faudra installer les librairies pour activer le GPIO du Raspberry. Celui-ci, grâce à un cron toutes les minutes, va scruter l'état du Central. Voici le script bash etat_monitoring.sh :
#!/bin/bash
CURL="/usr/bin/curl"
JQ="/usr/bin/jq"
SED="/bin/sed"

IP_CENTREON="192.168.5.1"
USER="admin"
PASSWORD="password"

setup ()
{
 echo Setup
 # vert
 gpio -g mode 17 out
 gpio -g write 17 0
 # jaune
 gpio -g mode 27 out
 gpio -g write 27 0
 # rouge
 gpio -g mode 22 out
 gpio -g write 22 0
}

requete ()
{
  TOKEN=`$CURL -s -d "username=$USER&password=$PASSWORD" -H "Content-Type: application/x-www-form-urlencoded" -X POST http://$IP_CENTREON/centreon/api/index.php?action=authenticate | $JQ '.["authToken"]'| $SED -e 's/^"//' -e 's/"$//'`

  NB_HOST_DOWN=`$CURL -s "http://$IP_CENTREON/centreon/api/index.php?object=centreon_realtime_hosts&action=list&viewType=unhandled&status=down" -H 'Content-Type: application/json' -H "centreon-auth-token: $TOKEN" | $JQ 'length'`

  NB_SERVICE_CRITICAL=`$CURL -s "http://$IP_CENTREON/centreon/api/index.php?object=centreon_realtime_services&action=list&viewType=unhandled&status=critical" -H 'Content-Type: application/json' -H "centreon-auth-token: $TOKEN" | $JQ 'length'`

  NB_SERVICE_WARNING=`$CURL -s "http://$IP_CENTREON/centreon/api/index.php?object=centreon_realtime_services&action=list&viewType=unhandled&status=warning" -H 'Content-Type: application/json' -H "centreon-auth-token: $TOKEN" | $JQ 'length'`

  if [[ "$NB_HOST_DOWN" != "0" ]] || [[ "$NB_SERVICE_CRITICAL" != "0" ]]; then
    gpio -g write 22 1
    gpio -g write 17 0
    gpio -g write 27 0
  else
    if [[ "$NB_SERVICE_WARNING" != "0" ]]; then
       gpio -g write 22 0
       gpio -g write 17 0
       gpio -g write 27 1
    else
       gpio -g write 22 0
       gpio -g write 17 1
       gpio -g write 27 0
    fi
  fi
  echo  "HOST DOWN        : $NB_HOST_DOWN"
  echo  "SERVICE CRITIQUE : $NB_SERVICE_CRITICAL"
  echo  "SERVICE WARNING  : $NB_SERVICE_WARNING"
  echo  "waiting..."
  sleep 30
}


setup
while true; do
  requete
done

5 Les interfaces de notifications

Pour réaliser les notifications sur l'écran LCD, il faudra récupérer la bonne librairie pour l'écran LCD nokia. Ensuite, il faudra créer deux commandes de notifications et les scripts correspondants. Comme l'écran LCD se trouve sur le poller, nous allons créer une mini application client-server avec une connexion TCP entre les deux raspberry.
Stacks Image 969860
La commande de notification pour les hôtes
Stacks Image 969863
la commande de notification pour les services
Et voici les scripts pour la communication entre les deux raspberry.
Le programme serveur sur le Poller server_udp.py
#!/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
import subprocess

# imports seulement nécessaires à l'exemple (=calcul d'expression par eval())
import sys
from math import *


try:

    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)
        data=requete.strip()
        # Affichage des informations reçues
        print "received data:", data
        subprocess.call(['/home/pi/messagelcd/callmessage.sh',data])
        time.sleep(0.25)

except KeyboardInterrupt:
    pass

finally:
    socketserveur.close()
Le programme client sur le Central sendmessage.py
#!/usr/bin/env python
# -*- coding:Utf-8 -*-

from optparse import OptionParser

# chargement des librairies
#import MySQLdb
import sys
import socket
import time

# initialisation des variables
UDP_IP = '192.168.5.10'
UDP_PORT = 20000
HOST_MYSQL = 'localhost'
USER_MYSQL = 'centreon'
PWD_MYSQL = 'passwd'

# définitions des options
options = {}
options[('-m','--message')] = {'dest':'message',
                              'help':'notification Centreon'}
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 = options.message

# affichage heure
print "envoi le :",time.strftime('%d/%m/%y à %H:%M',time.localtime())

#curs.close()
#conn.close()

# préparation du message et envoi au signal
#MESSAGE = "test message"
print MESSAGE

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s.sendto(MESSAGE,ADRESSE)

s.close()
Et voici les scripts pour afficher le message sur l'écran LCD.
le script callmessage.sh
#!/bin/bash
sudo /home/pi/messagelcd/message.py --message="$1"
le script message.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from optparse import OptionParser

import pcd8544.lcd as lcd
import time, os, sys

if not os.geteuid() == 0:
    sys.exit('Script must be run as root')

# définitions des options
options = {}
options[('-m','--message')] = {'dest':'message',
                              'help':'message'}

# 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()



ON, OFF = [1, 0]

lcd.init()
lcd.cls()
lcd.backlight(ON)
for i in range(50,100,5):
    lcd.set_contrast(i)
    lcd.centre_text(0,"   Message :   ")
    lcd.centre_text(1,"               ")
    lcd.centre_text(2,options.message)
    time.sleep(2)
lcd.cls()
lcd.backlight(OFF)

6 les scripts associés aux boutons

Voici quelques scripts que j'ai réalisé pour cette démo. Le premier pour démarrer Centreon. Il sera nécessaire de mémoriser la date du jour pour éviter de démarrer les processus de purge, de reporting lors de plusieurs démarrage dans la même journée.
#!/bin/bash
# start_centreon.sh
# version 1.00
# date 10/10/2017
# version 1.01
# date 13/11/2017
# add date courante

#démarrage Serveur Mysql
sudo service mysql start
sudo service mysql status

#démarrage Serveur Web
sudo service apache2 start
sudo service apache2 status

#démarrage centreontrapd
sudo service centreontrapd start
sudo service centreontrapd status

#démarrage centcore
sudo service centcore start
sudo service centcore status

#démarrage cbd
sudo service cbd start
sudo service cbd status

#démarrage centengine
sudo service centengine start
sudo service centengine status

DATECOURANTE=`cat /home/pi/centreon/datecourante.txt`
DATEACTUEL=`date +%D`

if [ "$DATECOURANTE" != "$DATEACTUEL" ]; then
  echo "changement"
  #Purge databin
  sudo -u centreon /usr/bin/php /usr/share/centreon/cron/centstorage_purge.php

  #Gestion partitionning
  sudo -u centreon /usr/bin/php /usr/share/centreon/cron/centreon-partitioning.php

  #Reporting
  sudo -u centreon /usr/share/centreon/cron/eventReportBuilder --config=/etc/centreon/conf.pm
  sudo -u centreon /usr/share/centreon/cron/dashboardBuilder --config=/etc/centreon/conf.pm
  date +%D > /home/pi/centreon/datecourante.txt
fi
le script d'arrêt de Centreon.
#!/bin/bash
# stop_centreon.sh
# version 1.00
# date 10/10/2017

#arrêt centengine
sudo service centengine stop
sudo service centengine status

#arrêt cbd
sudo service cbd stop
sudo service cbd status

#arrêt centcore
sudo service centcore stop
sudo service centcore status

#arrêt centreontrapd
sudo service centreontrapd stop
sudo service centreontrapd status

#arrêt Serveur Web
sudo service apache2 stop
sudo service apache2 status

#arrêt Serveur Mysql
sudo service mysql stop
sudo service mysql status
Les scripts pour créer un poller et le supprimer. Pour éviter des erreurs en base, je n'utilise jamais le même nom du poller en mémorisant le nombre de poller créé.
script create_poller.sh
#!/bin/bash
# create_poller.sh
# version 1.00
# date 22/11/2017

CLAPI_DIR=/usr/bin
USER_CENTREON=admin
PWD_CENTREON=password
# lecture fichier
NUM=`cat /home/pi/centreon/numpoller.txt`
(( NUM++ ))
echo $NUM
NAME_POLLER=Poller$NUM
IP_POLLER=192.168.5.10
IP_CENTRAL=192.168.5.1
MIN_NAME_POLLER="$(echo $NAME_POLLER | tr 'A-Z' 'a-z')"

#set date poller
DATE_CENTRAL=`date +"%m/%d/%Y %H:%M:%S"`
echo $DATE_CENTRAL
/usr/bin/ssh pi@192.168.5.10 "sudo date -s '"$DATE_CENTRAL"'"

# create instance poller
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a show -v $NAME_POLLER | grep $NAME_POLLER | cut -d";" -f2`
if [ "$RESULT" != "$NAME_POLLER" ]
then
    echo create instance poller
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a ADD -v "$NAME_POLLER;$IP_POLLER;22;CENGINE"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;localhost;0"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;is_default;0"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;ns_activate;1"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;init_script;centengine"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;init_script_centreontrapd;centreontrapd"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;nagios_bin;/usr/sbin/centengine"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;nagios_perfdata;/var/log/centreon-engine/service-perfdata"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;nagiostats_bin;/usr/sbin/centenginestats"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;centreonbroker_logs_path;/var/log/centreon-broker/watchdog.log"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;centreonbroker_cfg_path;/etc/centreon-broker"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;centreonbroker_module_path;/usr/share/centreon/lib/centreon-broker"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;centreonconnector_path;/usr/lib/centreon-connector"
    $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a setparam -v "$NAME_POLLER;snmp_trapd_path_conf;/etc/snmp/centreon_traps/"
else
   echo instance $NAME_POLLER  already exist !
fi


#create module broker for poller
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a show -v $MIN_NAME_POLLER-module | grep $MIN_NAME_POLLER-module | cut -d";" -f2`
if [ "$RESULT" != "$MIN_NAME_POLLER-module" ]
then
   echo create module broker for poller
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a ADD -v "$MIN_NAME_POLLER-module;$NAME_POLLER"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setparam -v "$MIN_NAME_POLLER-module;filename;$MIN_NAME_POLLER-module.xml"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setparam -v "$MIN_NAME_POLLER-module;cache_directory;/var/lib/centreon-broker"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setparam -v "$MIN_NAME_POLLER-module;stats_activate;1"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a ADDLOGGER -v "$MIN_NAME_POLLER-module;/var/log/centreon-engine/$MIN_NAME_POLLER-module.log;file"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setlogger -v "$MIN_NAME_POLLER-module;1;config;yes"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setlogger -v "$MIN_NAME_POLLER-module;1;debug;no"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setlogger -v "$MIN_NAME_POLLER-module;1;info;no"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setlogger -v "$MIN_NAME_POLLER-module;1;level;low"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a ADDOUTPUT -v "$MIN_NAME_POLLER-module;$MIN_NAME_POLLER-module-output;ipv4"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;protocol;bbdo"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;tls;no"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;compression;no"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;port;5669"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;retry_interval;"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;buffering_timeout;"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a setoutput -v "$MIN_NAME_POLLER-module;1;host;$IP_CENTRAL"
else
   echo module broker for poller $MIN_NAME_POLLER  already exist !
fi

#create engine poller
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a show -v $NAME_POLLER-cfg | grep $NAME_POLLER-cfg | cut -d";" -f2`
if [ "$RESULT" != "$NAME_POLLER-cfg" ]
then
   echo create engine poller
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a add -v "$NAME_POLLER-cfg;$NAME_POLLER;Poller Engine"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;status_file;/var/log/centreon-engine/status.dat"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;cfg_dir;/etc/centreon-engine"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;log_file;/var/log/centreon-engine/centengine.log"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;temp_file;/var/log/centreon-engine/centengine.tmp"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;lock_file;/var/lock/subsys/centengine.lock"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;command_file;/var/lib/centreon-engine/rw/centengine.cmd"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;log_archive_path;/var/log/centreon-engine/archives/"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;state_retention_file;/var/log/centreon-engine/retention.dat"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;broker_module;/usr/lib/centreon-engine/externalcmd.so|/usr/lib/centreon-broker/cbmod.so /etc/centreon-broker/$MIN_NAME_POLLER-module.xml"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;nagios_user;centreon-engine"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o enginecfg -a setparam -v "$NAME_POLLER-cfg;nagios_group;centreon-engine"
else
   echo engine poller $NAME_POLLER-cfg  already exist !
fi

#apply poller to resourcecfg
echo apply poller to resourcecfg
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o resourcecfg -a show |
while read line
do
   NAME=$(echo $line | cut -d";" -f2 )
   ID=$(echo $line | cut -d";" -f1 )
   CHAINE=$(echo $line | cut -d";" -f6 )
   if [ "\$USER1\$" == "$NAME" ]
   then
     CONCACT=$CHAINE\|$NAME_POLLER
     $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o resourcecfg -a setparam -v "$ID;instance;$CONCACT"
   fi
   if [ "\$CENTREONPLUGINS\$" == "$NAME" ]
   then
     CONCACT=$CHAINE\|$NAME_POLLER
     $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o resourcecfg -a setparam -v "$ID;instance;$CONCACT"
   fi
done

# generate conf
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERGENERATE -v "$NAME_POLLER"`

# control result
if [ $? -ne 0 ]
then

        echo "Erreur generation: "$RESULT
else

	# test monitoring
	RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERTEST -v "$NAME_POLLER"`
	if [ $? -ne 0 ]
	then

       		 echo "Erreur test: "$RESULT
	else

	        # move config
       		 RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a CFGMOVE -v "$NAME_POLLER"`
        	if [ $? -ne 0 ]
       		then

                	echo "Erreur Move config: "$RESULT
       		else

                	# reload config
                	RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERRESTART -v "$NAME_POLLER"`
                	if [ $? -ne 0 ]
                	then

                       		echo "Erreur reload config: "$RESULT
                	else
				echo "reload config OK"
			fi
		fi
	fi
fi
#sleep 10
# delete error instances
#RESULT=`/usr/bin/ssh pi@192.168.5.10 "/bin/ps aux | grep /usr/sbin/centengine | /bin/grep 'centengine' | /usr/bin/head -n 1 "`
# delete poller1 centreon_storage
#ID_PID=`echo $RESULT | /usr/bin/awk '{ print $2}'`
#echo "Delete from instances where name='Poller1' and pid!=${ID_PID};" | mysql -u centreon -pcentreon centreon_storage
script delete_poller.sh
#!/bin/bash
# delete_poller.sh
# version 1.00
# date 22/11/2017

CLAPI_DIR=/usr/bin
USER_CENTREON=admin
PWD_CENTREON=password
# lecture fichier
NUM=`cat /home/pi/centreon/numpoller.txt`
(( NUM++ ))
echo $NUM
echo $NUM > /home/pi/centreon/numpoller.txt
NAME_POLLER=Poller$NUM
IP_POLLER=192.168.5.10
IP_CENTRAL=192.168.5.1
MIN_NAME_POLLER="$(echo $NAME_POLLER | tr 'A-Z' 'a-z')"

# stop poller
/usr/bin/ssh pi@192.168.5.10 'sudo service centengine stop'
# delete poller
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o CENTBROKERCFG -a del -v "$MIN_NAME_POLLER-module"
# delete engine
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o ENGINECFG -a DEL -v "$NAME_POLLER-cfg"
# delete poller
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o INSTANCE -a DEL -v "$NAME_POLLER"
# delete poller1 centreon_storage
#echo "Delete from instances where name='Poller1';" | mysql -u centreon -pcentreon centreon_storage
Les scripts pour ajouter un hôte et le supprimer.
script create_host.sh
#!/bin/bash
# create_host.sh
# version 1.00
# date 22/11/2017

CLAPI_DIR=/usr/bin
USER_CENTREON=admin
PWD_CENTREON=password
# lecture fichier
NUM=`cat /home/pi/centreon/numpoller.txt`
(( NUM++ ))
echo $NUM
NAME_POLLER=Poller$NUM
IP_POLLER=192.168.5.10
IP_CENTRAL=192.168.5.1
MIN_NAME_POLLER="$(echo $NAME_POLLER | tr 'A-Z' 'a-z')"

#create host Group
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o hg -a show -v $NAME_HG | grep Linux-Servers | cut -d";" -f2`
if [ "$RESULT" != "$NAME_POLLER" ]
then
  echo create Hostgroup Linux-Servers
  $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o hg -a add -v "Linux-Servers;Linux-Servers"
fi

#create poller host
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o host -a show -v $NAME_POLLER | grep $NAME_POLLER | cut -d";" -f2`
if [ "$RESULT" != "$NAME_POLLER" ]
then
   echo create poller host
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o host -a add -v "$NAME_POLLER;poller $NAME_POLLER;$IP_POLLER;generic-host|OS-Linux-SNMPV2|HWD_raspberry;$NAME_POLLER;Linux-Servers"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o host -a setparam -v "$NAME_POLLER;host_snmp_community;public"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o host -a setparam -v "$NAME_POLLER;host_snmp_version;2c"
   $CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o host -a applytpl -v "$NAME_POLLER"
else
   echo poller host $NAME_POLLER  already exist !
fi


# generate conf
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERGENERATE -v "$NAME_POLLER"`

# control result
if [ $? -ne 0 ]
then

        echo "Erreur generation: "$RESULT
else

        # test monitoring
        RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERTEST -v "$NAME_POLLER"`
        if [ $? -ne 0 ]
        then

                 echo "Erreur test: "$RESULT
        else

                # move config
                 RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a CFGMOVE -v "$NAME_POLLER"`
                if [ $? -ne 0 ]
                then

                        echo "Erreur Move config: "$RESULT
                else

                        # reload config
                        RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERRELOAD -v "$NAME_POLLER"`
                        if [ $? -ne 0 ]
                        then

                                echo "Erreur reload config: "$RESULT
                        else
                                echo "reload config OK"
                        fi
                fi
        fi
fi

script delete_poller.sh
#!/bin/bash
# delete_host.sh
# version 1.00
# date 22/11/2017

CLAPI_DIR=/usr/bin
USER_CENTREON=admin
PWD_CENTREON=password
# lecture fichier
NUM=`cat /home/pi/centreon/numpoller.txt`
(( NUM++ ))
echo $NUM
NAME_POLLER=Poller$NUM
IP_POLLER=192.168.5.10
IP_CENTRAL=192.168.5.1
MIN_NAME_POLLER="$(echo $NAME_POLLER | tr 'A-Z' 'a-z')"


# delete host
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o HOST -a DEL -v "$NAME_POLLER"
# delete host Group
$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -o HG -a DEL -v "Linux-Servers"

# generate conf
RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERGENERATE -v "$NAME_POLLER"`

# control result
if [ $? -ne 0 ]
then

        echo "Erreur generation: "$RESULT
else

        # test monitoring
        RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERTEST -v "$NAME_POLLER"`
        if [ $? -ne 0 ]
        then

                 echo "Erreur test: "$RESULT
        else

                # move config
                 RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a CFGMOVE -v "$NAME_POLLER"`
                if [ $? -ne 0 ]
                then

                        echo "Erreur Move config: "$RESULT
                else

                        # reload config
                        RESULT=`$CLAPI_DIR/centreon -u $USER_CENTREON -p $PWD_CENTREON -a POLLERRELOAD -v "$NAME_POLLER"`
                        if [ $? -ne 0 ]
                        then

                                echo "Erreur reload config: "$RESULT
                        else
                                echo "reload config OK"
                        fi
                fi
        fi
fi

Les scripts pour réaliser les états critiques, warning et OK.
script OK script_ok.sh
#!/bin/bash
/usr/bin/snmptrap -v2c -c public localhost '' .1.3.6.1.6.3.1.1.5.4 .1.3.6.1.2.1.2.2.1.1 i 1 .1.3.6.1.2.1.2.2.1.7 i 1 .1.3.6.1.2.1.2.2.1.8 i 1
script WARNING script_warning.sh
#!/bin/bash
sudo service snmpd restart
script CRITICAL script_warning.sh
#!/bin/bash
/usr/bin/snmptrap -v2c -c public localhost '' .1.3.6.1.6.3.1.1.5.3 .1.3.6.1.2.1.2.2.1.1 i 2 .1.3.6.1.2.1.2.2.1.7 i 1 .1.3.6.1.2.1.2.2.1.8 i 1
comments powered by Disqus
 Vous êtes ici: