Manuel développeur¶
Chargement des fichiers XML¶
Les fichiers XML se situent dans le répertoire
/etc/vigilo/vigiconf/conf.d/
.
On y trouve notamment les répertoires principaux suivants :
- définition des hôtes
/etc/vigilo/vigiconf/conf.d/hosts
- definition des groupes d’hôtes
/etc/vigilo/vigiconf/conf.d/groups/
- définition des modèles d’équipements
/etc/vigilo/vigiconf/conf.d/templates/
La documentation sur la syntaxe des fichiers de configuration XML est disponible dans le manuel utilisateur de VigiConf. Le lecteur s’y référera au besoin.
Les fichiers XML sont parcourus par VigiConf. La structure d’exécution est la suivante :
- Analyse des fichier XML.
- Prise en compte des tests de supervision Python.
- Exécution des générateurs.
Création d’un nouveau test de supervision¶
Introduction¶
Les tests de supervision de VigiConf sont écrits en Python. Ils permettent de générer des fichiers de configuration concernant une ou plusieurs applications.
Organisation des tests de supervision¶
Principe des classes d’équipements¶
Les tests fournis par Vigilo sont regroupés dans le répertoire suivant :
/usr/lib/pythonx.y/site-packages/vigilo/vigiconf/tests/
On y trouve d’autres répertoires :
- all/
- linux/
- lmsensors/
- ucd/
Ces répertoires correspondent à des classes d’équipements et contiennent
des tests de supervision spécifiques à un type (famille/gamme/modèle)
d’équipement particulier. Par exemple, le dossier linux/
contient
des tests de supervision capables de fonctionner sur toutes les distributions
Linux.
Le dossier all/
est un cas particulier : les tests de supervision qu’il
contient peuvent être appliqués à n’importe quel type d’équipement (système
ou réseau).
Note
Par convention, les noms des classes d’équipements ne peuvent contenir que les caractères alphanumériques (a-z0-9) et l’underscore (_). De plus, nous recommandons d’inscrire les noms des classes en minuscules.
Avertissement
Pour des raisons historiques, certaines classes d’équipements actuellement fournies avec Vigilo contiennent des traits d’union (-) dans leur nom. Cet usage est cependant déconseillé et pourrait ne plus être supporté dans les futures versions de Vigilo. Utilisez le caractère underscore (_) à la place.
Les fichiers contenus dans ces répertoires portent des noms représentatifs
du test de supervision appliqué (par exemple, CPU.py
pour un test de
supervision portant sur l’état du processeur sur l’équipement).
Le même nom de fichier peut apparaître dans plusieurs classes d’équipements
différentes (par exemple, linux/CPU.py
et ucd/CPU.py
).
Ajout ou personnalisation d’un test¶
L’administrateur de la solution a la possibilité de définir ses propres tests
de supervision ou bien de redéfinir les tests fournis par défaut.
Les ajouts/surcharges de tests doivent se faire dans le dossier
/etc/vigilo/vigiconf/conf.d/tests
en respectant la même arborescence
classe/test.py
.
Ainsi, le test portant sur le processeur de la classe d’équipements “maclasse”
se trouvera dans le fichier
/etc/vigilo/vigiconf/conf.d/tests/maclasse/CPU.py
.
De même, on pourra redéfinir le comportement du test de supervision d’un
processeur sur une distribution Linux en créant un fichier
/etc/vigilo/vigiconf/conf.d/tests/linux/CPU.py
contenant le code
modifié.
Structure du code d’un test¶
Tous les tests de supervision héritent de la classe
vigilo.vigiconf.lib.confclasses.test.Test
et contiennent
une méthode add_test()
qui intègre la logique du test.
Exemple de test de supervision de la charge du processeur sur un nouveau modèle
d’équipements de la marque “exemple”. Le test sera placé dans
/etc/vigilo/vigiconf/conf.d/tests/exemple/CPU.py
.
# -*- coding: utf-8 -*-
from vigilo.vigiconf.lib.confclasses.test import Test
class CPU(Test):
"""
Description de ce que fait le test, par exemple :
Supervision de la charge du processeur sur un équipement
de marque exemple.
"""
def add_test(self, warn=60, crit=80):
"""
Description des arguments acceptés par ce test de supervision.
@param warn: Seuil de charge CPU en pourcentage
au-delà duquel un avertissement sera levé
par Vigilo dans le bac à événements.
@type warn: C{float}
@param crit: Seuil de charge CPU en pourcentage
au-delà duquel une alerte critique sera levée
par Vigilo dans le bac à événements.
@type crit: C{float}
"""
# Généralement le code commence par convertir les paramètres
# reçus vers les types attendus, comme ci-dessous.
warn = self.as_float(warn)
crit = self.as_float(crit)
# Code intégrant la logique de test de la charge CPU
# sur ce type d'équipements.
Note
Si vous souhaitez redistribuer votre test de supervision à l’équipe en charge du développement de Vigilo par la suite, nous vous recommandons d’adopter la syntaxe de documentation Epytext, comme dans l’exemple précédent. Il s’agit du format de documentation de l’API adopté par l’équipe pour le développement des nouveaux tests de supervision.
Note
Si vous créez un test de supervision similaire à un test déjà existant
(par exemple, un nouveau test portant sur le CPU), nous vous recommandons
de garder la même signature pour la fonction add_test()
,
afin de rendre homogène la configuration du test pour l’utilisateur,
quelle que soit la classe d’équipements sous-jacente.
La classe doit avoir exactement le même nom que le fichier dans lequel elle se trouve. Il s’agit également du nom qui devra être utilisé par l’administrateur dans les fichiers de configuration XML pour pouvoir appliquer ce test de supervision à un équipement.
Les arguments passés à la méthode add_test()
seront ceux indiqués
dans les fichiers XML de configuration qui utilisent ce test.
Avertissement
Les arguments passés à la fonction add_test()
seront
systématiquement des chaînes de caractères, y compris pour des valeurs
numériques (par exemple, des seuils d’alerte).
Le code de la méthode doit donc effectuer les conversions nécessaires
avant d’utiliser ces valeurs. Le chapitre Méthodes de l’instance de test
décrit les méthodes de la classe Test
pouvant être utilisées afin
de réaliser les conversions adéquates.
Méthodes de l’instance de test¶
Chaque instance de la classe Test
ou d’une classe dérivée possède
plusieurs méthodes outils.
Ces méthodes peuvent être regroupées en 2 catégories :
- Les méthodes permettant de convertir les paramètres passés à un test vers un type donné (entier, flottant, booléen).
- Les méthodes permettant d’ajouter les éléments de configuration nécessaires pour réaliser les tests à proprement parler, récupérer des informations sur les performances (métrologie), générer des graphiques à partir de ces informations, etc.
La liste suivante décrit les méthodes utilisables pour effectuer la conversion des paramètres d’un test.
as_bool()
Convertit la valeur passée en argument en booléen. Les valeurs
1
,true
,on
etyes
représentent la valeur PythonTrue
, tandis que les valeurs0
,false
,off
etno
représentent la valeur PythonFalse
. Toute autre valeur génèrera une erreur d’analyse.Note
L’analyse effectuée est insensible à la casse (ie.
yes
==Yes
).Note
Si la valeur donnée est déjà un booléen, elle est retournée sans qu’aucune conversion ne soit effectuée.
as_float()
Convertit la valeur passée en argument en nombre flottant. Si la valeur ne peut être convertie, une erreur d’analyse est levée.
Note
Si la valeur donnée est déjà un flottant, elle est retournée sans qu’aucune conversion ne soit effectuée.
as_int()
Convertit la valeur passée en argument en nombre entier. Si la valeur ne peut être convertie, une erreur d’analyse est levée.
Note
Si la valeur donnée est déjà un entier, elle est retournée sans qu’aucune conversion ne soit effectuée.
La liste suivante décrit les méthodes appartenant à la deuxième catégorie (manipulation des tests de supervision et de la métrologie).
add_collector_metro()
- Ajoute un service passif de métrologie à Nagios.
add_collector_service()
- Ajoute un service passif à Nagios et ajoute un test supplémentaire au collector (SNMP).
add_collector_service_and_metro()
Cette méthode est un raccourci qui correspond à une succession d’appels aux méthodes suivantes :
add_collector_service()
add_collector_metro()
add_collector_service_and_metro_and_graph()
Cette méthode est un raccourci qui correspond à une succession d’appels aux méthodes suivantes :
add_collector_service()
add_collector_metro()
add_graph()
add_external_sup_service()
- Ajoute un service actif à Nagios.
add_graph()
- Ajoute un graphique à Vigigraph.
add_metro_service()
- Ajoute un test Nagios sur les valeurs contenues dans les fichiers RRD.
add_perfdata()
- Déclare une donnée de performance reçu par le connecteur de métrologie, permettant ainsi de faire le lien entre les données de performance et les base RRDs de métrologie.
add_perfdata_handler()
- Déclare une donnée de performance générée par un module Nagios dans Vigilo, permettant ainsi de faire le lien entre les données de performance des modules Nagios et les bases RRDs de métrologie.
add_trap()
- Ajoute un service passif dans Nagios, dont l’état changera sur réception
d’un trap SNMP. Cette méthode ajoute également des éléments de configuration
dans le fichier
snmptt.conf
utilisé pour traiter les traps SNMP.
Note
Un service Nagios actif est un service pour lequel l’exécution du test de supervision associé est déclenchée par Nagios. Un service Nagios passif est un service dont le test de supervision n’est pas déclenché par Nagios. À la place, la valeur d’état du service est calculée indépendamment de Nagios, puis injectée dans celui-ci. Par exemple, les services dont l’état est déterminé grâce à SNMP sont déclarés comme des services passifs dans Nagios. Le collector SNMP de Vigilo (service actif) est appelé par Nagios, se charge de calculer les états de ces services, puis envoie ces états à Nagios.
Note
Toutes ces fonctions appellent la méthode add qui va ajouter/modifier la hash_map. La structure de la hash_map est disponible au début du fichier /lib/confclasses/host.py. La méthode add est également déclarée dans ce même fichier, elle va simplement ajouter un élément, dans l’une des clefs de la hash_map. En cas de non existence de la clef, elle l’ajoute. Le développeur peut appeler directement la méthode add dans son test Python, mais cela nécessite une connaissance de la structure de la hash_map. La hash_map est l’équivalent d’un dictionnaire Python, et est parcourue par les générateurs pour la génération de configuration. Avec un seul test Python, on peut, par exemple, ajouter des services passifs/actifs à Nagios, tout en plaçant des informations dans la hash_map, qui sera lu par notre générateur qui créera un fichier de configuration spécifique.
Générateurs de fichiers de configuration¶
Un certain nombre de générateurs de fichiers de configuration sont fournis par défaut avec VigiConf. Ces générateurs vont créer des fichiers de configuration pour les applications et composants qui interagissent avec Vigilo (collecteur, connecteur de métrologie, Nagios, etc.).
Pour créer un nouveau générateur de fichiers de configuration, vous devez créer
un nouveau point d’entrée sous la section vigilo.vigiconf.generators
.
Pour l’heure, le nom de la clé associée au point d’entrée n’a pas d’importance.
Les générateurs doivent hériter de la classe
vigilo.vigiconf.lib.generators.Generator
ou d’une sous-classe
(par exemple, vigilo.vigiconf.lib.generators.file.FileGenerator
).
À minima, le générateur doit surcharger la méthode generate()
de la classe Generator
afin d’effectuer les traitements
nécessaires à la création d’une nouvelle configuration.
La méthode generate_host()
est également utilisable.
Cette méthode génère la configuration pour un hôte et le serveur de supervision
qui lui est associé.
Les générateurs de fichiers de configuration sont regroupés dans le répertoire
/usr/lib/pythonx.y/site-packages/vigilo/vigiconf/applications/
,
où x.y représente la version de Python utilisée (par exemple, 2.5 ou 2.6).
Architecture d’un générateur¶
L’ajout d’un générateur se fait par la création d’un nouveau répertoire
dans applications/
. Le dossier est organisé selon l’arborescence
suivante :
./applications/premier_generateur/
|- __init__.py
|- generator.py
|- templates/
| |- template_un.tpl
| `- template_deux.tpl
`- validate.sh
Le fichier __init__.py
¶
Ce fichier est quasiment identique entre les différents générateurs et décrit l’application pour laquelle des fichiers de configuration peuvent être générés.
Le fichier doit contenir une classe Python héritant de la classe
vigilo.vigiconf.lib.application.Application
.
Cette classe ne contient aucune méthode, mais simplement des attributs
permettant de décrire l’application.
Par exemple, pour une application nommée Foobar
effectuant une collecte
d’états, le fichier __init__.py
pourrait contenir un code semblable
à l’extrait suivant :
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from vigilo.vigiconf.lib.application import Application
from . import generator
class Foobar(Application):
name = "foobar"
priority = -1
validation = "validate.sh"
start_command = "start.sh"
stop_command = "stop.sh"
generator = generator.FoobarGenerator
group = "collect"
Le rôle des différents attributs de cette classe est décrit dans le tableau ci-dessous.
Attribut | Rôle |
---|---|
dbonly |
Drapeau indiquant si l’application manipule des données externes à la base de données Vigilo. Ce drapeau permet de paralléliser l’exécution des applications qui ne travaillent que sur la base de données Vigilo et de désactiver leur exécution lorsqu’une bascule de serveur est nécessaire (haute disponibilité). |
defaults |
Paramêtres de configuration par défaut de l’application et indépendants de la configuration du parc. |
generator |
La classe Python correspondant au générateur de configuration à proprement parler pour cette application. |
group |
Le groupe fonctionnel auquel l’application appartient. Les groupes actuellement définis par Vigilo sont :
|
name |
Un nom unique pour faire référence à cette application. Le nom ne doit contenir que des caractères en minuscules. |
priority |
Priorité pour l’ordonnancement du redémarrage. L’application avec la priorité la plus élevée sera qualifiée et déployée en premier. |
start_command |
Une commande qui sera exécutée sur les serveurs
de supervision où l’application est installée
afin de relancer l’application. Cet attribut peut
valoir None si l’application n’a pas besoin
d’être arrêtée puis relancée pour prendre en
compte une nouvelle configuration. |
stop_command |
Une commande qui sera exécutée sur les serveurs
de supervision où l’application est installée
afin d’arrêter l’application. Cet attribut peut
valoir None si l’application n’a pas besoin
d’être arrêtée puis relancée pour prendre en
compte une nouvelle configuration. |
validation |
Une commande qui sera exécutée sur la machine où VigiConf est installé et sur les serveurs de supervision où l’application est installée afin de vérifier la validité des fichiers de configuration générés. |
Avertissement
Le nom de la classe (Foobar
dans notre exemple) doit commencer
par une majuscule.
Note
Les groupes fonctionnels sont utilisés pour répartir la supervision
du parc entre différents serveurs de supervision.
Cette répartition est effectuée grâce à la configuration située dans
le fichier /etc/vigilo/vigiconf/conf.d/general/appgroups-server.py
.
Le dossier templates/
¶
Le dossier templates/
contient un ensemble de fichiers de « modèles »
portant l’extension .tpl
(pour « template »).
Reportez-vous à la section sur l’Utilisation des modèles dans un générateur pour plus d’information sur le mécanisme des modèles.
Le fichier generator.py
¶
Ce fichier contient le générateur à proprement parler. C’est lui qui va générer le(s) fichier(s) de configuration de l’application.
Imports utiles¶
Le fichier generator.py
importe généralement plusieurs objets
et modules de Vigilo, comme indiqué dans l’extrait de code suivant :
# Si l'application utilise des données provenant du fichier
# de configuration de VigiConf (/etc/vigilo/vigiconf/settings.ini).
from vigilo.common.conf import settings
# Cet import donne accès à la hashmap utilisée pour transmettre
# la configuration des différents hôtes.
from vigilo.vigiconf import conf
# Import de la classe permettant de générer des fichiers de configuration.
from vigilo.vigiconf.lib.generators import FileGenerator
# Pour des besoins plus spécifiques, on peut également importer
# directement la classe de base des générateurs
#from vigilo.vigiconf.lib.generators import Generator
Classe du générateur¶
Le fichier du générateur doit contenir une classe qui hérite de la classe
vigilo.vigiconf.lib.generators.Generator
ou de l’une de ses sous-classes (par exemple
vigilo.vigiconf.lib.generators.FileGenerator
).
Note
Par convention, la classe correspondant au générateur pour une application
nommée Foobar
dans Vigilo s’appelle FoobarGen
.
Cette classe doit définir au minimum deux méthodes :
generate()
generate_host()
La méthode generate()
est appelée exactement une fois pour chaque
serveur de supervision vers laquelle une nouvelle configuration doit être
déployée, au début de la génération. La plupart du temps, cette méthode
se contente de réinitialiser la liste des fichiers de configuration à générer
(attribut _files
), puis appelle la méthode generate()
de
la classe parente.
Par exemple, le générateur de configuration pour Nagios contient :
def generate(self):
# pylint: disable-msg=W0201
self._files = {}
self._graph = None
super(NagiosGen, self).generate()
La méthode generate_host()
est appelée pour chaque hôte pour lequel
une configuration doit être générée. La méthode reçoit en argument le nom
du serveur pour lequel une configuration doit être générée, ainsi que le nom
du serveur de supervision vers lequel cette configuration sera déployée :
def generate_host(self, hostname, vserver):
# Le code permettant de générer la configuration pour l'hôte
# "hostname" sur le serveur de supervision "vserver" se trouve ici.
pass
Les méthodes du générateur seront donc appelées successivement selon le motif suivant :
# Début de la nouvelle configuration pour un serveur de supervision.
generator.generate()
# Génération de la configuration pour les différents équipements
# supervisés par le serveur "sup1.example.com"
generator.generate_host("serveur1.example.com", "sup1.example.com")
generator.generate_host("serveur2.example.com", "sup1.example.com")
generator.generate_host("serveur3.example.com", "sup1.example.com")
# Début de la nouvelle configuration pour un serveur de supervision.
generator.generate()
# Génération de la configuration pour les différents équipements
# supervisés par le serveur "sup2.example.com"
generator.generate_host("serveur4.example.com", "sup2.example.com")
generator.generate_host("serveur5.example.com", "sup2.example.com")
generator.generate_host("serveur6.example.com", "sup2.example.com")
# etc.
Utilisation des modèles¶
Pour générer le ou les fichiers de configuration dont il est responsable,
un générateur peut utiliser le mécanisme des modèles de documents proposé
par Vigilo. Les modèles de documents sont des fichiers portant l’extension
« .tpl » et placés dans le répertoire templates/
à côté du générateur.
Un modèle de document peut représenter la totalité d’un fichier de configuration ou bien simplement un fragment de ce fichier. Dans le second cas, cela signifie que plusieurs modèles de documents devront être utilisés successivement afin de générer un fichier de configuration complet.
Un modèle de document est similaire à « un texte à trous », au sens où il
s’agit d’un exemple du contenu d’un fichier de configuration dans lequel
certains champs dont le contenu est variable (par exemple, un nom de machine)
sont remplacés par des champs de formatage Python (%(foo)s
).
Le contenu des champs de formatage Python sera substitué par les valeurs
adéquates lors de l’utilisation du modèle par le générateur.
Exemple de modèle (ici, le modèle host.tpl
responsable de la création
de la configuration d’un hôte dans Nagios) :
define host{
use %(hostTPL)s
host_name %(name)s
alias %(name)s
address %(address)s
%(hostGroups)s
%(parents)s
%(generic_hdirectives)s
}
Dans cet exemple, on peut voir que le modèle attend plusieurs variables :
- Le nom du modèle Nagios à utiliser :
hostTPL
. - Le nom de l’équipement en cours de configuration :
name
. - L’adresse de l’équipement :
address
. - D’autres variables :
hostGroups
,parents
, etc.
L’utilisation d’un modèle de documents dans un générateur est plutôt simple. L’extrait de code (simplifié) suivant donne un exemple d’utilisation de plusieurs modèles par le générateur Nagios :
def generate_host(self, hostname, vserver):
# Détermination du chemin jusqu'au fichier de configuration à générer.
# - self.baseDir correspond à la racine du dossier de génération
# des configurations.
# - vserver contient le nom du serveur de supervision vers lequel
# ce fichier de configuration sera déployé.
# L'affectation du chemin dans un attribut de la classe (self.fileName)
# est facultative : on aurait pu utiliser une variable locale.
self.fileName = os.path.join(self.baseDir, vserver, "nagios",
"nagios.cfg")
if self.fileName not in self._files:
self._files[self.fileName] = {}
# Récupération de la configuration relative à l'hôte
# pour lequel on est en train de générer une configuration.
h = conf.hostsConf[hostname]
# Si le fichier de configuration n'existe pas encore
# (ie. on commence la création de la configuration).
if not os.path.exists(self.fileName):
# Alors, on utilise la méthode templateCreate() pour créer
# le fichier de configuration à partir du modèle contenu
# dans "templates/header.tpl".
self.templateCreate(self.fileName, self.templates["header"] {,
"confid": conf.confid,
})
# Préparation des variables qui seront passées
# au modèle "templates/host.tpl".
newhash = self._prepare_template_variables(h.copy())
# Ajout de la configuration de l'hôte au fichier de configuration,
# en utilisant le modèle "templates/host.tpl".
self.templateAppend(self.fileName, self.templates['host'], newhash)
En somme, la signature des méthodes templateCreate()
et
templateAppend()
est identique, les 2 méthodes acceptant
les arguments suivants (dans cet ordre) :
- Le nom du fichier de configuration qui sera créé (
templateCreate()
) ou complété (templateAppend()
). - Le nom du modèle de document à utiliser, sans extension.
- Un dictionnaire dont les clés sont les champs de substitution définis dans le modèle de document et les valeurs sont celles que doivent prendre les champs de substitution.
Le fichier de validation¶
Ce fichier correspond à la valeur de l’attribut validation
dans la classe qui décrit l’application
et son nom doit donc être adapté en conséquence.
En général, il s’agit d’un simple script shell appelé validate.sh
.
Le but de ce fichier est d’effectuer des vérifications permettant de s’assurer que la nouvelle configuration est valide (bon format, bonnes options, etc.).
Ce fichier sera exécuté une première fois sur la machine qui héberge VigiConf (phase de validation), puis une seconde fois sur la machine de supervision finale (phase de qualification) afin d’être absolument certain que la nouvelle configuration pourra être appliquée.
Une rapide lecture du contenu des scripts des autres générateurs facilite la création d’un nouveau script de validation.
Générateur de cartes automatiques¶
VigiConf fournit un mécanisme permettant de générer automatiquement des cartes, construites à partir des données présentes dans la configuration (groupes, hôtes, services ou toute autre donnée).
Un générateur de cartes automatiques est une classe contenue dans le paquet
automaps
et dérivant de la classe de base AutoMap
.