mercredi 31 octobre 2012

Thruk une alternative à l'interface Web de Nagios

Il était une fois un moteur nagios ...

Si comme moi vous avez été amené a mettre en oeuvre plusieurs nagios, vous avez sûrement dû vous frotter a son interface Web a base de cgi et de fichier plat exporter toutes les 10 secondes.

Ne crachons pas dans la soupe, cette interface reste très bien pour une petite installation.

Malheureusement, avec l'évolution des besoins en supervision, il devient de plus en plus difficile de se contenter de cette interface. En vrac, on va donner les éléments suivants :
  • Interface vieillissante qui (en dehors des nouveaux CSS des dernières version de nagios) n'a plus évolué depuis de nombreuses années ;
  • Nécessité d'héberger les CGI sur la même machine que le moteur nagios ;
  • Overhead d'écriture du fichier status.dat ;
  • Désynchronisation de l'interface avec le moteur nagios (pour lancer un test immédiat - même dans le cas d'un test très court - l'interface vous rend la main tout de suite et vous devez attendre le lancement du test + le temps de rafraîchissement du fichier status.dat) ;
  • Explosion des temps de réponse dans le cas d'une grosse installation ;
  • Dans le cas où vous auriez plusieurs nœuds nagios, vous devez vous connecter sur la bonne interface pour consulter votre serveur.

Origine de Thruk

Thruk est donc un projet qui a démarré sur ce constat afin d'offrir une alternative sans pour autant dérouté complètement les utilisateurs en reprenant - dans les grandes lignes - l'aspect de l'ancienne interface. En réalité, cette interface apporte des améliorations très intéressantes par rapport à l'ancienne interface avec notamment les points suivants :
  • Possibilité de déporter l'interface de consultation sur un serveur distant ;
  • Possibilité de fédérer plusieurs noeuds nagios dans la même interface ;
  • Compatibilité avec n'importe quel moteur du moment que ce dernier supporte Livestatus (Shinken, Icinga, centreon engine, check_mk).

Quelques pré-requis de fonctionnement

L'installation de Livestatus se fait en rajoutant un broker à votre moteur nagios. Pour plus de détail, vous pouvez vous reporter à l'article suivant : setting up and using Livestatus. A noter que check_mk et Shinken viennent nativement avec ce support.

Autre point, dans le cas d'un accès déporter, il sera peut-être nécessaire de mettre en place un outil vous permettant d'exposer votre socket Unix sur le réseau. La documentation officiel fait appel à l'outil Unixcat (qui vient avec nagios). Pour ma part, j'ai préféré utiliser l'outil socat qui m'a donné des connexions plus stable et plus rapide. Ci-dessous un exemple de commande pour lancer socat :

socat TCP-LISTEN:1958,interface=lo,reuseaddr,keepalive,nodelay,fork,crnl \
      UNIX-CLIENT:/var/lib/nagios3/rw/live,keepalive

Installation de Thruk

Le gros défaut de Thruk est tout de même la ribambelle de plugin perl CPAN qu'il a comme dépendance. Heureusement, l'auteur du plugin propose un package tout prêt pour la plupart des plateformes disponibles (Debian, RedHat, Ubuntu, etc.). Pour se faire, il faut se rendre sur la page de téléchargement du projet, choisir le package qui vous convient et procéder à l'installation du package.

A noter que le produit a tout de même besoin de quelques dépendances au niveau système (plugin fastcgi pour apache notamment). Il faudra donc bien penser à installer ces dernières sous peine d'avoir des erreurs au moment de l'installation du package.

Une fois l'installation terminée, Thruk va créer un fichier htpasswd avec comme administrateur par défaut thrukadmin (mdp thrukadmin). Dans le cas où vous auriez déjà un fichier de mot de passe, bien penser à modifier le fichier /etc/apache2/conf.d/thruk.conf afin de pointer sur le bon. Bien penser également à modifier le fichier /etc/thruk/cgi.cfg dans ce cas là afin de définir les droits adéquates.

Enfin, il vous faudra  modifier le fichier /etc/thruk/thruk_local.conf afin de pointer sur votre noeud de supervision. Ci-dessous un exemple d'interfaçage avec un moteur Shinken :
######################################
# Backend Configuration, enter your backends here
<Component Thruk::Backend>
  <peer>
      name   = Shinken
      type   = livestatus
      <options>
          peer    = 127.0.0.1:50000
     </options>
  </peer>
</Component>
Un petit arrêt/relance du serveur apache et nous devrions être en mesure d'utiliser Thruk.

Tour du propriétaire

Connectez-vous sur l'interface Thruk (http://MONSERVEUR/thruk/). On devrait vous demander un mot de passe (thrukadmin/thrukadmin par défaut).

Au premier lancement, vous devriez avoir à attendre quelques secondes (ce comportement est normal puisque apache va devoir instancier les process fastcgi de Thruk à ce moment là). Ce délais d'attente passé, vous devriez arriver sur l'interface de Thruk. Par la suite, les process étant déjà là, vous n'aurez pas ce temps d'attente.

Comme indiqué un peu plus haut, l'interface est quasi la même que celle des CGIs si on exclue la map graphique (mais elle est avantageusement remplacé par une grille qui est plus fonctionnelle).

Du côté des améliorations, on peut noter les points suivants :
  • Champ de recherche plus efficace (utilisation d'ajax pour vous proposer des solutions lors de le champ de recherche avec proposition de choix de hostgroup, nom des services et bien sûr machine) ;
  • Lors du lancement d'un test, l'interface se bloque tant que le moteur nagios n'a pas récupéré le résultat du test (plus besoin de faire de rafraîchissement) ;
  • Intégration des graphiques de PNP ;
  • Présence de lien permettant des exports au format Excel (je sais, je suis pas forcément fan mais c'est quand même pratique).
Globalement, l'interface est plus jolie, plus réactive et vous avez également d'autres raffinements auxquels je ne pense pas forcément (générateur de rapport, gestion de la conf etc.).

Bref, comme dirait l'autre, l'essayer c'est l'adopter !

vendredi 26 octobre 2012

Plugin de suivi des PDUs

Il y a peu de temps de ça, j'ai eu à mettre en place un suivi des PDUs (Power Distribution Unit) pour un de mes clients. En faisant bien attention de ne pas réinventer la roue, je me suis donc appuyé sur le script développé par boreal labs (http://www.boreal-labs.com/joomla/index.php/en/downloads-menu/view.download/18-pdu/9-checkpwnetrpduload.html). Ci-dessous un petit exemple d'exécution de ce dernier :


./check_pwnet_rpdu_load.pl -H 192.168.0.1 -C public -b 1,2 -m A -w n,12 -c 16,o
PWNET_RPDU_LOAD OK - PDU 'PDU-IT-R5-A' bank #1 load = 3.3A; bank #2 load = 0.0A; | PDUBank1Load=3.3A;13.0;16.0;0;16 PDUBank2Load=0.0A;12.0;16.0;0;16


Une fois intégré dans nagios, mon ami PNP a commencé à produire le résultat suivant :

Seulement voilà, certains PDUs avaient un capteur de température/humidité et j'avais besoin de faire un suivi là dessus. C'est donc à cette occasion, j'ai écrit un script permettant de remonter ces informations. Ce script est disponible à l'adresse suivante : http://code.google.com/p/plugin-nagios-yannig/source/browse/trunk/pdu/check_pdu_sensors.pl

Il vous faudra récupérer la mib du constructeur (le fichier powernet405.mib) et le rendre disponible à snmpwalk (en renseignant son emplacement avec la variable d'environnement MIBDIRS par exemple). Ci-dessous un exemple de test de communication :


./check_pdu_sensors.pl -H 192.168.0.1 -C public 
Temperature/Humidity sensor status is OK - temperature = 22.4°C, humidity = 56%|temperature=22.4 humidity=56%


Ce dernier va vous renvoyer la température et/ou l'humidité (fonction du type de capteur sur votre matériel) à un instant T de votre PDU. Le résultat prend la forme suivante :

J'ai ensuite intégré tout ceci dans nagios et l'ami PNP a commencé à produire des graphiques assez sympas. En voici ci-dessous un petit exemple de suivi sur 2 semaines de l'humidité :


mercredi 3 octobre 2012

Mise en place selenium

Ces derniers temps, on m'a demandé de mettre en place de scénario de surveillance sur une application typiquement horrible : code HTML horrible, Internet Explorer only etc.

Bref, j'ai donc commencé à vouloir faire ça en cucumber mais je me suis rapidement frotté à des problèmes mon cher concombre masqué refusant catégoriquement mes noms de formulaires fantaisiste (il faut dire qu'on trouve des dollars ('$') dedans ...).

Bien triste, j'ai commencé à chercher quelque chose d'autre qui pourrait répondre à mon besoin et je suis tombé sur selenium (http://seleniumhq.org/) et son IDE (qui est une simple extension à installer dans firefox).

J'ai commencé à faire joujou avec l'IDE et - malgré un rendu HTML catastrophique - j'ai réussi à faire un scénario de test avec Firefox.

En trifouillant un peu, j'ai vu qu'il existait un serveur selenium (un process java) et qu'il pouvait tourner dans un serveur X virtuel. Devant tant de beauté, j'ai donc commencé à mettre ça en place :D.

Pré-requis python

Comme par la suite je vais générer des scripts au format python, nous allons devoir installer la librairie python permettant de communiquer avec selenium. Ici, rien de bien compliqué, un coup de apt-get pour installer le nécessaire :

apt-get install python-pip python-dev build-essential

Maintenant que nous avons pip, nous pouvons procéder à l'installation de la librairie selenium :

pip install -U selenium

Passons maintenant à la suite (et y'a du monde !)

X11 Virtual frame buffer (miam !)

Ce cher Xvfb ! Toujours un petit moment émouvant quand je le croise ! Pour le lancer, il faut simplement utiliser la ligne de commande suivante :

DISPLAY=:1 Xvfb :1 -screen 0 1024x768x24

Bien penser à le rendre utilisable depuis n'importe où avec la commande xhost :

DISPLAY=:1 xhost +

ATTENTION : L'utilisation de xhost + va rendre le serveur X visible depuis l'extérieur !!! Il est conseillé de mettre en place un parefeu pour bloquer les accès externes.

L'installation se fait avec un apt-get install xvfb (et x11-server-utils pour disposer de l'utilitaire xhost)

Installation de Firefox

Par la suite, nous utiliserons firefox pour faire nos tests. Donc rien de bien fameux si ce n'est un apt-get install firefox (à remplacer par iceweasel si vous êtes sur Debian).

Mise en place de Selenium

On arrive enfin au coeur du sujet. Selenium est un serveur qui s'appuie sur un jar java pour se lancer. Donc de manière logique, il va vous falloir un java fonctionnel. Je vous passe les détails, vous faîtes comme vous voulez.

Récupérer ensuite la dernière version de selenium serveur sous la forme d'un JAR. Vous pouvez ensuite le lancer avec la ligne de commande suivante :

export DISPLAY=:1
java -Djava.security.egd=file:/dev/./urandom \
     -jar /path/to/jar/selenium-server-standalone-2.25.0.jar \
     -browserSessionReuse

A noter la présence de l'option -browserSessionReuse qui permet d'éviter de relancer le navigateur à chaque lancement de scénario et l'option biscornu java.security.egd qui permet de passer du device aléatoire /dev/random (qui est lent) à /dev/urandom qui lui n'utilise pas l'entropie du système pour fonctionner mais un générateur de nombre aléatoire.

Test de notre premier scénario

À l'aide de l'IDE selenium, nous avons enregistré notre scénario. Nous allons maintenant exporter ce dernier au format Python 2 / unittest / Remote Control. Voici ce à quoi ça devrait ressembler :

from selenium import selenium
import unittest, time, re

class sites(unittest.TestCase):
    def setUp(self):
        self.verificationErrors = []
        self.selenium = selenium("localhost", 4444, "*chrome", "http://monsite/")
        self.selenium.start()
    
    def test_sites(self):
        sel = self.selenium
        sel.open("/ma_page")
        sel.type("id=un_champ", "une_valeur")
        sel.type("id=un_autre_champ", "une_autre_valeur")
        sel.click("id=id_d_un_lien")
        sel.wait_for_page_to_load("30000")
    
    def tearDown(self):
        self.selenium.stop()
        self.assertEqual([], self.verificationErrors)

if __name__ == "__main__":
    unittest.main()
Lançons maintenant ce beau script depuis la machine faisant tourner selenium :

python mon_scenario.py
.
----------------------------------------------------------------------
Ran 1 test in 4.051s
OK

Magnifique non ? Tout à fait mais ça ne vous dit pas ce que vous allez en faire dans votre nagios.

(Des)intégrations dans nagios/Shinken

Comment ça, vous voulez le script qui analyse la sortie de tout ça et l'insert directement dans nagios ? Je vous trouve un peu exigeant quand même !

Bon, si vous insistez ... Il faut récupérer le script check_selenium.pl et lancer ensuite la sonde de la manière suivante :

/emplacement/scripts/check_selenium.pl --script \
      /emplacement/de/mon/scenario.py  \
      --label "Le test de ma super application"

De là, vous devriez obtenir la sortie suivante :

Selenium test OK (Le test de ma super application)|time=3.180s test_count=1

Elle est pas belle la vie ?

mardi 2 octobre 2012

Suivi des interfaces d'un switch CISCO sous Nagios/Shinken

Depuis quelques jours, je travaille sur la mise en place d'un Shinken chez un client. A cette occasion, on m'a demandé de faire un suivi des switchs de la boîte et notamment le débit de chaque port.

Comme je suis quelqu'un de relativement paresseux (je n'avais pas trop envie de me déclarer les 48 ports des 200 switchs à la main). J'ai donc rapidement pensé à un script qui me permettrait de déclarer automatiquement ces surveillances. Et comme je suis un mec super sympas qui adore raconter sa vie, je vais vous en faire profiter bande de veinards !

Pour se faire, nous allons utiliser les MIBs SNMP des switchs CISCO qui ont la bonne idée de proposer tout un tas de chose vachement intéressante (oui, enfin ... pour un administrateur d'outils de surveillance). Nous allons voir notamment l'OID 1.3.6.1.2.1.2.2.1.2 qui va nous renvoyer la liste des interfaces du switch :

$ snmpwalk -c ecalyptus -v 2c 10.1.1.1 1.3.6.1.2.1.2.2.1.2
iso.3.6.1.2.1.2.2.1.2.1 = STRING: "FastEthernet1"
iso.3.6.1.2.1.2.2.1.2.2 = STRING: "TenGigabitEthernet1/1"
iso.3.6.1.2.1.2.2.1.2.3 = STRING: "TenGigabitEthernet1/2"
iso.3.6.1.2.1.2.2.1.2.4 = STRING: "TenGigabitEthernet1/3"
iso.3.6.1.2.1.2.2.1.2.5 = STRING: "TenGigabitEthernet1/4"
iso.3.6.1.2.1.2.2.1.2.6 = STRING: "GigabitEthernet3/1"
iso.3.6.1.2.1.2.2.1.2.7 = STRING: "GigabitEthernet3/2"
iso.3.6.1.2.1.2.2.1.2.8 = STRING: "GigabitEthernet3/3"
iso.3.6.1.2.1.2.2.1.2.9 = STRING: "GigabitEthernet3/4"
iso.3.6.1.2.1.2.2.1.2.10 = STRING: "GigabitEthernet3/5"
iso.3.6.1.2.1.2.2.1.2.11 = STRING: "GigabitEthernet3/6"
iso.3.6.1.2.1.2.2.1.2.12 = STRING: "GigabitEthernet3/7"
iso.3.6.1.2.1.2.2.1.2.13 = STRING: "GigabitEthernet3/8"
iso.3.6.1.2.1.2.2.1.2.14 = STRING: "GigabitEthernet3/9"
iso.3.6.1.2.1.2.2.1.2.15 = STRING: "GigabitEthernet3/10"
[...]

Nous allons nous servir de cette sortie pour générer notre surveillance. Pour cela, nous allons utiliser le script perl suivant :
#!/usr/bin/perl
use strict;

open(MODEL, "modele.txt");
mkdir("modeles") if(!-d("modeles"));
while() {
  chomp();
  my($modele, $ip) = split(/;/);
  my @interfaces = `snmpwalk -c ecalyptus -v 2c $ip 1.3.6.1.2.1.2.2.1.2`;
  open(MODEL_CFG, ">modeles/switch-$modele.cfg");
  foreach(@interfaces) {
    if(/iso.3.6.1.2.1.2.2.1.2.(\d+) = STRING: "(.*Ethernet.*)"/) {
      my ($id, $interface) = ($1, $2);
      print MODEL_CFG "define service {
  hostgroup_name       $modele
  use                  generic-service
  service_description  $interface
  check_command        check_port_usage!$id!6000!8000
}
\n";
    }
  }
  close(MODEL_CFG);
}
close(MODEL);
Ce script attend en entrée un fichier de paramètre (modele.txt) et nous donne en sortie des fichiers de configuration au format nagios dans le sous-répertoire modeles. Il nous reste maintenant à prendre ces fichiers et les intégrer dans la configuration de notre nagios/Shinken.

Ci-dessous un exemple de surveillance sur un switch CISCO (du type WS-C2960-24PC-L) :
define service {
  hostgroup_name       WS-C2960-24PC-L
  use                  generic-service
  service_description  FastEthernet0/1
  check_command        check_port_usage!10001!6000!8000
}
[...]
define service {
  hostgroup_name       WS-C2960-24PC-L
  use                  generic-service
  service_description  GigabitEthernet0/2
  check_command        check_port_usage!10102!6000!8000
}
Il reste ensuite à déclarer un hostgroup ad-hoc avec un template de serveur comme suit :

define hostgroup{
  hostgroup_name  WS-C2960-24PC-L
  alias           Switchs Cisco WS-C2960-24PC-L
}

define host {
  name            switch-WS-C2960-24PC-L
  use             generic-switch
  alias           Ensemble des switchs Cisco WS-C2960-24PC-L
  hostgroups      Switch,WS-C2960-24PC-L
  icon_image      vendors/cisco.png
  register        0
}
Et nous pouvons déclarer maintenant des switchs utilisant le template switch-WS-C2960-24PC-L. Ces derniers viendront directement avec la surveillance automatique de tous leurs ports.