jeudi 23 décembre 2010

Installation de shinken et configuration de l'interface Thruk

J'utilise beaucoup nagios pour mon travail de tous les jours mais c'est un outil qui n'est pas parfait (loin de là! ). J'ai donc lu avec beaucoup d'intérêt le démarrage du projet shinken qui a comme gros avantage d'être beaucoup plus performant et d'être beaucoup plus modulable que son ainé.

Voulant m'en faire une idée pour de vrai, j'ai donc procédé à une installation from scratch. Comme la documentation ne parle pas du tout de l'ajout de l'interface, je laisse donc ici quelques mots à ce sujet.

Installation de shinken



Tout d'abord créer un utilisateur shinken. Très important, il faut un home qui soit valide (sinon, l'arbitrer ne démarre pas !).

Reste ensuite à procéder à l'installation. Ici, rien de plus simple, il faut simplement récupérer le package shinken-0.4.tar.gz puis de le décompresser. Se rendre dans le répertoire shinken-0.4 puis lancer la commande suivante :

sudo python setup.py install --install-scripts=/usr/bin


De là, shinken va créer pas mal de répertoire (notamment /var/lib/shinken et /etc/shinken). Par convenance, j'ai créé un fichier shinken.sh qui me lance tous les éléments dans le bon ordre :


patrice@Enclume:~/tmp/shinken-0.4$ cat /etc/init.d/shinken.sh
#!/bin/bash

cd /etc/init.d

for script in shinken-scheduler shinken-poller shinken-reactionner shinken-broker shinken-arbiter
do
./$script $1
done


De là, il suffit de faire un /etc/init.d/shinken.sh start et c'est parti ! Pour vérifier que tout va bien, il faut s'assurer que les process suivants sont bien présents :


patrice@Enclume:~/tmp/shinken-0.4$ ps -u shinken
PID TTY TIME CMD
4358 ? 00:00:09 shinken-schedul
4367 ? 00:00:10 shinken-poller
4372 ? 00:00:00 shinken-poller
4380 ? 00:00:09 shinken-reactio
4385 ? 00:00:00 shinken-reactio
4949 ? 00:00:13 shinken-broker
4989 ? 00:00:00 shinken-poller
4990 ? 00:00:00 shinken-poller
4993 ? 00:00:00 shinken-poller
4996 ? 00:00:18 shinken-broker
4997 ? 00:00:00 shinken-broker
5001 ? 00:00:00 shinken-reactio
5004 ? 00:00:00 shinken-poller
5018 ? 00:00:10 shinken-arbiter


Configuration de l'interface Thruk



Ici, il faut récupérer l'interface Thruk à l'emplacement suivant. On la décompresse puis nous nous rendons dedans afin d'y créer un fichier thruk_local.conf. En voici le contenu :


~/tmp/Thruk-0.74$ cat thruk_local.conf
######################################
# Backend Configuration, enter your backends here
<component Thruk::Backend>
<peer>
name = Shinken
type = livestatus
hidden = 0 # make this backend hidden by default
groups = admins # make this backend only visible to the admin group
<options>
peer = 127.0.0.1:50000
verbose = 0
</options>
</peer>
</component>


De là, il ne nous reste plus qu'à lancer le démon Thruk :


~/tmp/Thruk-0.74/script$ ./thruk_server.pl
You can connect to your server at http://enclume:3000


NB : Attention, il s'agit d'un test. Il est possible de lancer l'interface Thruk en utilisant un serveur apache mais ce n'est pas l'objet de cet article.

De là, il ne nous reste plus qu'à accéder à l'interface http://localhost:3000 au travers un navigateur :



Bon, il va maintenant falloir que je configure correctement ma map :D Mais bon, ça c'est une autre histoire ;).

mercredi 6 octobre 2010

Import des données de ndoutils dans pnp4nagios

Il y a de ça 5 ou 6 mois, j'ai procédé à un refresh à notre infrastructure de suivi nagios. A l'époque nous utilisions un nagios couplé avec NDOUtils pour faire notre suivi de tendance des machines. J'avais par ailleurs créé un plugin permettant de grapher tout ceci en me basant sur la bibliothéque JPGraph.

Malheureusement, entre les problèmes sur la base de données, le fait que je sois sur Solaris (chouette encore un truc à compiler), les problèmes liés au broker nagios (pourquoi ce foutu machin ne veut pas se reconnecter à la base !!!), les problèmes de performance de la base (j'avais mis en place un système de rotation de la table nagios_servicechecks pour m'affranchir des problèmes de dégradation des performances avec le temps), la taille de tout ceci (200 Mo de place par jour pour 600 services !) et le plugin de graph à maintenir, j'ai fini par péter un cable !

Bref, à l'occasion d'un plan de refresh de ma machine, je suis tombé sur pnp4nagios et là, j'ai sérieusement réfléchi à me débarrasser de NDOUtils. En revanche, un point m'embêter : perdre mon historique de 100 jours de l'ancienne base MySQL. J'ai donc à ce moment pensé à utiliser les possibilités d'insertion en mode bulk de pnp4nagios afin de reconstituer mon historique.

Au démarrage, j'ai procédé par une extraction via un ensemble de scripts shells. J'ai ensuite procédé à un refactoring de ce script afin de le réécrire en perl que j'ai ensuite proposé à l'équipe de pnp4nagios. Ils m'ont simplement proposé de le déposer sur leur wiki à l'emplacement suivant.

Le script en question s'appelle ndo2pnp.pl et vous trouverez ci-dessous l'aide en ligne disponible sur l'outil :

$ ./ndo2pnp.pl --help
Usage :
-h --help Display this message.
--version Display version then exit.
-v --verbose Verbose run.
-u --user ndouser Log on to database with ndouser (default root).
-p --pass passwd Use passwd to logon (default gbu2kfe).
-t --type dbtype Change database type (default mysql).
--host dbhost Use dbhost (default localhost).
--dbname db Use db for ndo database name (default ndoutils).
--list-machine Display machine definition in ndo database.
--list-service Show services defined.
--export-as-pnp Export ndo content as a bulk file used by process_perfdata.pl.
>


Globalement, pour procéder à votre export/import, il faut suivre les étapes suivantes :
  • Extraction du contenu de la base : ./ndo2pnp.pl --user mysql_user -p mysql_pass --export-as-pnp > /tmp/perfdata.bulk

  • Import de l'extraction :/usr/share/pnp4nagios/libexec/process_perfdata.pl -b /tmp/perfdata.bulk --timeout 0

Quoi ? C'est tout ! Euh, juste une petite précision : l'import a duré 4 jours sur ma machine de production :). Un conseil : essayez de faire des extracts machine par machine (avec l'option --machines MAMACHINEAEXTRAIRE ou --services MESSERVICESAEXTRAIRE que j'ai oublié de documenté d'ailleurs ... Pas beau !). Les imports seront du coup moins long à faire (et éventuellement en parallèle) et peuvent vous donner une idée du résultat final sans avoir à vous coltiner l'intégralité de l'import de vos données.

Le résultat de tout ceci se trouve ci-dessous :


Toute la partie de décembre à février et le résultat de l'import (plus les quelques jours parasites d'octobre et novembre, date à laquelle nous avions eu des soucis avec la base MySQL). Vous remarquerez qu'entre temps, la base s'est alimentée avec de nouvelles valeurs.

dimanche 5 septembre 2010

Utilisation d'un robot avec Mediawiki

Il y a de ça quelques temps, j'ai eu l'occasion de travailler sur un robot de mise à jour automatique des populations sur les articles des communes de Charente-Maritime. Le principe est assez simple : les articles de commune utilisent tous un système de modèle afin de donner un aspect uniforme à tous les articles. Jetons un coup d'oeil au code source de l'article Wikipedia sur la ville de La Rochelle :


{{Infobox Communes de France
| nomcommune = La Rochelle
| image = La Rochelle Vieux-Port.JPG
| image-desc = Les tours du vieux-port de La Rochelle
[...]
| insee = 17300
| cp = 17000
| maire = [[Maxime Bono]]
[...]
| km² = 28.43
| sans = 76848
| date-sans = 2007
| aire-urbaine = 186271
| nomhab = Rochelaise, Rochelais
| siteweb = http://www.ville-larochelle.fr/
| géoloc-département = Charente-Maritime
}}


Comme vous pouvez le constater, l'article utilise un modèle Mediawiki (ici le modèle Infobox Communes de France) et utilise des paramètres nommés (aire-urbaine=186271 par exemple). L'idée de l'automate est donc de venir modifier les paramètres sans et date-sans (respectivement la population et la date de ce recensement) à partir de fichier plat. Ceci bien sûr afin d'éviter de faire le travail de mise à jour des centaines de communes de France à la main.

Pour les plus curieux, le code source du robot se trouve à l'adresse suivante : DroopigBot sur google code

Bref, le robot a fonctionné sur les communes de Charente-Maritime (ainsi que sur une partie de la Vendée) et m'a donné une idée lumineuse : alimenter automatiquement notre wiki de documentation interne. En effet, nous avions tout un tas de site différent dispersé avec des fonctionnalités différentes :

  • Un inventaire de machine

  • Un spip de documentation (avec une version complètement obsolète)

  • Un inventaire par mail de nos instances de serveurs Java

  • Mais également plein de chose avec des fichiers plats dans plein d'endroit différent



J'ai donc récupéré le code que j'avais utilisé pour mes communes afin d'en faire quelque chose de plus simple sous la forme d'un script d'extraction et de mise à jour de contenu d'article.

Je ne vais pas tout vous présenter mais juste l'utilitaire en ligne de commande qui me permet de faire cette mise à jour : update_article.sh. Vous pouvez le récupérer à l'adresse suivante : http://code.google.com/p/droopigbot/source/browse/#svn/trunk/public_html.

Pour le configurer, c'est assez simple : créer un utilisateur avec droit d'écriture sur votre mediawiki, créer un fichier robot_config.inc.php avec les informations de connexion. Ci-dessous un exemple pour ce fichier :
$robot = new DroopigBot("Nomdubot", "passdubot", "http://addresse-du-serveur/wiki");
?>


Une fois enregistré, votre robot est prêt à fonctionner. Faisons un test simple d'extraction :

drayan@robert:~/dev/droopigbot/public_html$ ./update_article.sh --name 'Page de test' --dump
Un article de test.


Alimentons maintenant un fichier pour mettre à jour cet article :
drayan@robert:~/dev/droopigbot/public_html$ cat > essai.txt
Mon article a été mise à jour.

Et j'en suis très content.


Lançons la mise à jour :
drayan@robert:~/dev/droopigbot/public_html$ ./update_article.sh --name 'Page de test' --update ./essai.txt --no-simulation --message 'Mise à jour par un robot'
Updating 'Page de test' with './essai.txt' content


Si on jette un coup d'oeil à l'article, nous voyons qu'il a été mis à jour :



Allons maintenant voir l'historique :


Reste maintenant plus qu'à faire vos scripts de mise à jour de votre wiki :)

dimanche 11 juillet 2010

Sortie de pnp4nagios 0.6.5

Juste un petit billet pour signaler la sortie de pnp4nagios en version 0.6.5. Un rapide coup d'oeil sur le changelog nous donne les nouveautés suivantes (par rapport à la version 0.4.x) :
  • Interface Web se basant sur le moteur Kohana, thème jQuery et utilisation de plugin jQuery
  • process_perfdata.pl peut utiliser plusieurs bases RRD par source nagios
  • Nouvelle fonctionnalitée d'installation : possibilité de spécifier l'emplacement des fichiers layout (-–with-layout)
  • Lors d'une erreur de rendu, les erreurs sont affichées sous la forme d'image.
  • Les templates d'affichage ne peuvent plus changer la valeur des variables internes.
  • Possibilité d'utiliser les templates des versions 0.4.x.
  • Refonte du code PDF ainsi que pour les pages.
  • Optimisation du Template par défaut (default.php)
  • Export des bases RRD au format XML, CSV et JSON en utilisation la fonction RRDtool "xport"
  • Les erreurs font pointer sur la FAQ en ligne.
  • Plugin permettant d'afficher les graphiques dans un popup.
  • Support du rrdcached
Une fonctionnalité que je n'ai pas encore eu le loisir de tester est la partie "special template" qui permet apparemment de récupérer des informations sur plusieurs machines en même temps pour les afficher sur un même graphique. Une application de cette nouvelle fonction pourrait être de disposer d'un graphique indiquant le trafic en temps réel de 4 machines frontales Web.

Autre fonctionnalité nouvelle sur la version 0.6.5, la présence de fonction d'aide à la création de template (voir la page suivante : http://docs.pnp4nagios.org/pnp-0.6/tpl_helper). Ces fonctions vous permettront de simplifier la prise en main des outils RRD. Quelques exemples d'utilisation :
  • Définir une nouvelle source de données RRD : $def = rrd::def('var1', $RRDFILE[0], $DS[0], 'MAX');
  • Définir un gradient : $def .= rrd::gradient('var1', '#ff0000', '#ffff00' );
  • Afficher une ligne : $def .= rrd::line1('var1', #ff00ff );
Autre point qui pourrait vous intéresser, j'ai reversé une traduction française de l'interface.

vendredi 25 juin 2010

Compilation NRPE sous AIX 5.3 avec support du SSL

J'ai eu dernièrement besoin de compiler un agent nagios NRPE pour AIX 5.3. Malheureusement pour moi, cet OS est livré sans librairie dynamique openssl (ie libssl.so). J'ai donc du compiler nrpe en static.

N'ayant pas trouver d'information intéressante sur le net (en dehors de désactiver le ssl), je me suis dit que ce genre d'information pourrait être utile à d'autre.

Tout d'abord, modifier le fichier configure de la manière suivante (sur une version 2.12 de nrpe) :


$ diff configure.orig configure
6673c6673
< if test -f "$dir/libssl.so"; then
---
> if test -f "$dir/libssl.a"; then
6687c6687
< LIBS="$LIBS -lssl -lcrypto";
---
> LIBS="$LIBS $ssllibdir/libssl.a $ssllibdir/libcrypto.a";


Le patch consiste à changer la nature du fichier recherché (libssl.a à la place de libssl.so) et remplacer les flags de compilation -lssl et -lcrypto par les fichiers des bibliothèques que l'on vient de trouver.

Il ne reste plus qu'à lancer configure avec les options suivantes :
./configure --with-ssl=/opt/freeware --with-ssl-lib=/opt/freeware/lib --prefix=/opt/nagios


Un coup de make ; make install et vous disposez maintenant des binaires nrpe et check_nrpe à la mode AIX et surtout avec le support du SSL.

jeudi 24 juin 2010

Problème de performance avec pnp4nagios sous Solaris

Depuis quelques temps déjà, je devais mettre en place pnp4nagios combiné à un nagios 3.2 sur une nouvelle machine. Auparavant, je passais par une machine un peu vieillotte (un sunfire V210 avec 2 Go de mémoire) que je devais remplacer par une plus récente (à base de M5000 Sun). L'ancienne plateforme passait par un nagios combiné avec ndoutils (un backend de stockage des données de performance sous MySQL). Cette plateforme était très contraignante pour plusieurs raisons :
  • Plugin de génération de graphique maison (c'est votre serviteur qui avait écrit ça)
  • Scripts de gestion du contenu de la table nagios_servicechecks : je découpais cette table en journée pour pouvoir supporté le volume de données (environ 200 Mo/jour et 17 Go d'historique)
  • Lenteur de la solution : nagios et le module de base de données (ndo2db) n'était pas très consommateur mais en revanche, la base MySQL était très consommatrice de ressource disque et CPU.
Bref, pour toutes ces raisons et après un rapide tour des solutions existantes, nous avions décidé de partir sur l'excellent plugin pnp4nagios pour l'historisation. Avec ce plugin, plus de serveur MySQL, moins d'IO, plus de script de maintenance. Bref, que du bonheur.

C'est donc assez confiant qu'il y a quelques jours que nous avons procédé à la mise en production. Mais comme toujours, j'ai eu une mauvaise surprise lors de la migration. Lors de la fin de la bascule de tous nos anciens services sur la nouvelle (environ 900 services), j'ai commencé à voir des messages d'erreurs m'indiquant un time out lors du lancement du script process_perfdata.pl au bout de 5 secondes. En y regardant de plus près, j'ai constaté que le timeout était fixé par la directive perfdata_timeout=5 et en urgence, j'ai donc fixé le timeout à 30 s.

Une fois ce contournement mis en place, j'ai pu regarder en détail le problème. J'ai notamment constaté que la machine passait énormément de temps à faire ses mises à jour. En rajoutant quelques traces, je me suis rendu compte que le script process_perfdata.pl n'utilisait pas la bibliothéque native perl RRD mais le binaire rrd ! Suite à quelques tests que j'avais pu faire il y a quelques temps sur les deux modes de fonctionnement, j'ai essayé de voir si le problème ne pouvait pas venir de là.

Après un coup d'oeil à la configuration de nagios et je suis tombé sur cette partie :
define command {
command_name process-service-perfdata-file
command_line /bin/perl /usr/share/pnp4nagios/libexec/process_perfdata.pl --bulk=/var/nagios/service-perfdata
}

define command {
command_name process-host-perfdata-file
command_line /bin/perl /usr/share/pnp4nagios/libexec/process_perfdata.pl -d HOSTPERFDATA --bulk=/var/nagios/host-perfdata
}
Rien de bien choquant mais le problème est que sous Solaris la version de RRD venant de sunfreeware s'installe dans /usr/local. Problème, ce dernier est livré avec un binding perl prévu pour la version 5.8.8. Malheureusement, la version installée par défaut (ie dans le répertoire /usr/bin) est une version 5.8.4 et n'est pas en mesure d'utiliser la bibliothéque native perl de RRD.

Bref, j'ai donc changé la version de perl par celle se trouvant dans /usr/local/bin :
define command {
command_name process-service-perfdata-file
command_line /usr/local/bin/perl /usr/share/pnp4nagios/libexec/process_perfdata.pl --bulk=/var/nagios/service-perfdata
}

define command {
command_name process-host-perfdata-file
command_line /usr/local/bin/perl /usr/share/pnp4nagios/libexec/process_perfdata.pl -d HOSTPERFDATA --bulk=/var/nagios/host-perfdata
}
Un coup d'arrêt relance et après quelques temps, j'ai obtenu une nette diminution au niveau des temps de traitement de perfdata :

Zoom sur la partie basse :

C'est ici qu'on constate tout l'intérêt de l'utilisation de la bibliothéque native RRD : on est passé à des temps de traitement d'environ 30s à des temps de traitement de l'ordre de la seconde.

mercredi 23 juin 2010

Supervision de WebLogic à l'aide de nagios

Afin de surveiller la consommation mémoire de nos instances WebLogic, j'ai commencé à écrire un plugin se basant sur le protocole SNMP.

Pour ceux qui ne le saurait pas, WebLogic est un serveur d'application Java propriétaire.

Ce besoin de surveillance vient du fait que les serveurs les hébergeants (des Sun V890 avec 40 Go de mémoire) sont sur le point d'arriver à saturation mémoire. Pour cette raison, nous avons donc essayé de savoir quelles instances consommées et à quelle hauteur.

Il faut dire que nous avons constaté que la mémoire allouée aux JVMs étaient le double de la mémoire physique ! Pour info, la machine héberge une centaine d'instance WebLogic en version 8.1 et Java 1.4. Comme vous vous en doutez, nous avons prévu de faire le ménage dans nos instances. Mais pour ça, il nous faudrait un petit état des lieux, d'où l'écriture d'un script.

Passons maintenant à l'écriture du script.

Premier point, il faut se débrouiller pour activer l'agent SNMP au niveau du domaine WebLogic. Nous pourrons ainsi interroger le serveur sans avoir à faire de couteuses interrogations à base de programme en java. Nous allons ensuite nous baser sur l'outil snmpwalk.

Pour mémoire, une page de référence de la MIB de ce serveur d'application est disponible à l'adresse suivante : http://download.oracle.com/docs/cd/E13222_01/wls/docs90/snmp/index.html

Commençons tout d'abord par interroger l'agent SNMP WebLogic en ligne de commande :
drayan@robinet:~$ snmpwalk -m ./BEA-WEBLOGIC-MIB.mib -c public -v 1 192.168.0.10:7061 .1.3.6.1.4.1.140.625.180
La branche .1.3.6.1.4.1.140.625.180 correspond aux informations sur les threads Java actifs. Nous pouvons également interroger la branche .1.3.6.1.4.1.140.625.340.1 pour récupérer la quantité de mémoire consommée (jvmRuntimeHeapSizeCurrent). A noter que pour connaître les instances présentes dans le domaine WebLogic, je fais appel à la branche 1.3.6.1.4.1.140.625.361.1.

Une fois enrobé tout ceci j'obtiens le script suivant :
#!/usr/bin/perl
use strict;
use File::Basename;
use Sys::Hostname;
use Getopt::Long;

my $verbose = 0;
my $show_help = 0;
my $show_version = 0;
my $snmp_address = 0;
my $instance = 0;
my $snmp_cmd = "snmpwalk -m ".dirname($0)."/../share/BEA-WEBLOGIC-MIB.mib";
my $show_only = ".*";

sub usage {
my ($msg) = @_;
$msg = "" if(!$msg);
my $name = basename($0);
print "Usage :
\$ $name [OPTION]

Get runtime information about WebLogic instance
-h --help display this help and exit.
--intance <SRVNAME>[,<>] name of the instances to check.
--only <REGEXP> show only instance corresponding to regexp.
--snmp <HOST[:PORT]> address (and port) of the snmp server.
-v --verbose verbose.

Examples:
\$ $name --port 10861 --instance srvback11,srvback12,srvback13,srvback14
".($msg ? "\n".$msg."\n" : "")
}

GetOptions(
"V" => \$show_version,
"version" => \$show_version,
"h" => \$show_help,
"help" => \$show_help,
"v" => \$verbose,
"verbose" => \$verbose,
"snmp=s" => \$snmp_address,
"instance=s" => \$instance,
"only=s" => \$show_only,
);

if($show_help) { usage(); exit(0); }
die("Please specify snmp address (--snmp host:port)") if(!$snmp_address);

if(!$instance) {
my(%instance_name, %instance_state) = ((), ());
my @tmp = ();
my ($i, $j) = (0, 0);
foreach(`$snmp_cmd -c public -v 1 $snmp_address 1.3.6.1.4.1.140.625.361.1 2> /dev/null`) {
if(/BEA-WEBLOGIC-MIB::serverLifeCycleRuntimeName.*STRING: "(\w+)"/) {
$instance_name{$i++} = $1;
} elsif(/BEA-WEBLOGIC-MIB::serverLifeCycleRuntimeState.*STRING: "(\w+)"/) {
my $label = $instance_name{$j++};
$instance_state{$label} = $1;
if($1 =~ /RUNNING/) {
print "$label is RUNNING\n" if($verbose);
push(@tmp, $label);
} else {
print "Ignoring $label\n" if($verbose);
}
}
}
$instance = join(",", @tmp);
}

my $perfdata = "";
foreach my $srv(sort(split(/,/, $instance))) {
next if(!($srv =~ /$show_only/));
my @result = `$snmp_cmd -c public\@$srv -v 1 $snmp_address .1.3.6.1.4.1.140.625.340.1 2> /dev/null`;
my($label, $current_max_heap, $free_heap);
foreach(@result) {
if(/BEA-WEBLOGIC-MIB::jvmRuntimeName.*STRING:\s+"(\w+)"/) { $label = $1; }
elsif(/BEA-WEBLOGIC-MIB::jvmRuntimeHeapFreeCurrent.*INTEGER:\s+(\d+)/) { $free_heap = $1; }
elsif(/BEA-WEBLOGIC-MIB::jvmRuntimeHeapSizeCurrent.*INTEGER:\s+(\d+)/) {
$current_max_heap = $1;
$current_max_heap = int($current_max_heap / 1048576 + .5);
$free_heap = int($free_heap / 1048576 + .5);
my $used = $current_max_heap - $free_heap;
$perfdata .= " $label=$used;$current_max_heap;$current_max_heap;0;$current_max_heap";
}
}
}

print "WebLogic memory OK|$perfdata\n";
On configure notre agent pour accepter un nouveau type de commande :
command[check_weblogic_memory]=/usr/lib/nagios/plugins/check_weblogic --snmp localhost:7061
On configure un nouveau service sous Nagios :
define service {
host_name machine-weblogic
use generic-service
service_description Suivi memoire WebLogic
check_command check_nrpe!check_weblogic_memory
}
Et hop ! Au bout de quelques jours, vous obtenez le résultat suivant (en combinaison avec pnp4nagios) :