This is a machine translation based on the English version of the article. It might or might not have already been subject to text preparation. If you find errors, please file a GitHub issue that states the paragraph that has to be improved. |
1. Introduction
Les plugins de check sont des modules logiciels écrits en Python qui sont exécutés sur une instance de Checkmk et qui créent et évaluent les services sur un hôte.
Checkmk comprend plus de 2000 plugins de check prêts à l'emploi pour tous les matériels et logiciels imaginables. Ces plugins sont maintenus par l'équipe Checkmk et de nouveaux sont ajoutés chaque semaine. En outre, il existe d'autres plugins sur le Checkmk Exchange qui sont fournis par nos utilisateurs.
Pourtant, il peut toujours arriver qu'un appareil, une application ou simplement une certaine métrique, qui est importante pour vous, ne soit pas encore couverte par l'un de ces plugins existants - peut-être simplement parce que c'est quelque chose qui a été développé dans votre organisation et que personne d'autre ne peut donc l'avoir. Dans l'article sur l'introduction au développement d'extensions pour Checkmk, vous pouvez découvrir quelles sont les options qui s'offrent à vous.
Cet article vous montre comment développer de véritables plugins de surveillance pour l'agent Checkmk - y compris tout ce qui va avec. Il existe un article séparé pour les plugins de surveillance basés sur SNMP.
1.1. La documentation de l'API Check
Depuis la version 2.0.0 de Checkmk, une nouvelle API a été développée pour la programmation des plugins de check. Nous allons vous montrer comment utiliser cette API de check pour la programmation des plugins.
Vous pouvez accéder à la documentation de l'API de contrôle à tout moment via l'interface utilisateur de Checkmk : Help > Developer resources > Check plugin API reference. Dans la nouvelle fenêtre du navigateur, sélectionnez BASE > Agent based API ("Check API") dans la barre de navigation de gauche :
Note pour les utilisateurs de l'API de contrôle valable jusqu'à la version 1.6.0: Si vous avez encore des plugins de contrôle qui ont été développés avec l'ancienne API, vous devriez les migrer rapidement vers la nouvelle API de contrôle. Même si l'ancienne API de contrôle continuera à être prise en charge pendant une période transitoire, cette période prendra également fin. Les avantages de la nouvelle API de contrôle compensent l'effort de migration unique, car elle est plus cohérente, plus logique, mieux documentée et à l'épreuve du temps. Dans l'article de blog sur la migration des plugins de contrôle, nous vous fournissons des informations détaillées sur les étapes nécessaires pour une migration. |
1.2. Conditions préalables
Si vous souhaitez programmer des plugins de surveillance check, vous aurez besoin des éléments suivants :
Une connaissance du langage de programmation Python.
Une expérience avec Checkmk, en particulier en ce qui concerne les agents et les checks.
Une pratique de l'utilisation de Linux à partir de la ligne d'instruction.
1.3. Termes et définitions
On parle toujours ici d'un "plugin de check" et de son écriture. Mais à proprement parler, vous avez toujours besoin de deux plugins, l'agent plugin sur l'hôte surveillé et le plugin de check sur le serveur Checkmk. Ces deux plugins doivent être écrits et compatibles l'un avec l'autre - ce n'est qu'à ce moment-là qu'ils peuvent fonctionner sans problème dans une opération de surveillance.
2. Écrire un plugin d'agent
Si vous souhaitez programmer des plugins pour Checkmk, il est très probable que vous ayez déjà configuré un serveur Checkmk et que vous ayez également surveillé votre serveur Checkmk en tant qu'hôte.
Dans ce qui suit, nous allons supposer un scénario exemplaire dans lequel le serveur Checkmk et l'hôte surveillé sont identiques, ce qui nous permet d'utiliser les requêtes Livestatus de l'hôte pour obtenir des informations sur les groupes d'hôtes fournis par le serveur Checkmk.
Dans l'exemple décrit, nous supposerons une organisation avec plusieurs sites :
Chacun de ces sites est représenté dans Checkmk par un groupe d'hôtes.
Chaque site dispose de sa propre équipe de service.
Pour que la bonne équipe de service puisse être avertie en cas de problème, chaque hôte doit être affecté à un site, c'est-à-dire également à un groupe d'hôtes. L'objectif de cet exemple est de mettre en place un check pour s'assurer qu'aucun hôte n'a oublié d'affecter un groupe d'hôtes.
L'ensemble du processus comprend deux étapes :
Lire les informations pour la surveillance à partir de l'hôte, c'est l'objet de ce chapitre.
Écrire un plugin de surveillance dans l'instance Checkmk qui évalue ces données, ce que nous montrerons dans le chapitre suivant.
Alors, allons-y ...
2.1. Récupérer et filtrer les informations
La première étape avant d'écrire un programme de plugin est la recherche ! Cela signifie qu'il faut trouver comment obtenir les informations dont vous avez besoin pour la surveillance.
Pour l'exemple choisi, nous utilisons le fait que le serveur Checkmk est également l'hôte. Cela signifie que dans un premier temps, il suffit de récupérer les données de statut via Livestatus, c'est-à-dire les données organisées dans des tables que Checkmk conserve en mémoire volatile à propos des hôtes et des services surveillés.
Connectez-vous en tant qu'utilisateur de l'instance et interrogez les informations sur les groupes d'hôtes à l'aide de l'instruction suivante :
OMD[mysite]:~$ lq "GET hostgroups"
action_url;alias;members;members_with_state;name;notes;notes_url;num_hosts;num_hosts_down;num_hosts_handled_problems;num_hosts_pending;num_hosts_unhandled_problems;num_hosts_unreach;num_hosts_up;num_services;num_services_crit;num_services_handled_problems;num_services_hard_crit;num_services_hard_ok;num_services_hard_unknown;num_services_hard_warn;num_services_ok;num_services_pending;num_services_unhandled_problems;num_services_unknown;num_services_warn;worst_host_state;worst_service_hard_state;worst_service_state
;Hamburg;myhost11,myhost22,myhost33;myhost11|0|1,myhost22|0|1,myhost33|0|1;Hamburg;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;Munich;myhost1,myhost2,myhost3;myhost1|0|1,myhost2|0|1,myhost3|0|1;Munich;;;3;0;0;0;0;0;3;123;10;0;10;99;0;14;99;0;24;0;14;0;2;2
;check_mk;localhost;localhost|0|1;check_mk;;;1;0;0;0;0;0;1;66;0;0;0;4;0;1;4;61;1;0;1;0;1;1
La première ligne de la sortie contient les noms des colonnes du tableau hostgroups
interrogé. Le point-virgule sert de séparateur. Les lignes suivantes contiennent ensuite le contenu de toutes les colonnes, également séparées par des points-virgules.
La sortie est déjà relativement confuse dans ce petit exemple et contient des informations qui ne sont pas pertinentes pour notre exemple. En général, vous devriez laisser l'interprétation des données à Checkmk. Cependant, le filtrage préalable sur l'hôte peut réduire le volume de données à transférer si elles ne sont pas toutes nécessaires. Donc, dans ce cas, limitez la requête aux colonnes pertinentes (Columns
), aux noms des groupes d'hôtes (name
) et aux hôtes dans ces groupes (members
) :
OMD[mysite]:~$ lq "GET hostgroups\nColumns: name members"
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
L'interface Livestatus s'attend à recevoir toutes les instructions et tous les en-têtes dans leur propre ligne séparée. Les sauts de ligne nécessaires sont indiqués par \n
.
Dans cet exemple, il y a actuellement trois groupes d'hôtes : deux groupes pour les sites et un pour le groupe check_mk
. Ce dernier contient un hôte appelé localhost
.
Le groupe d'hôtes check_mk
est une caractéristique spéciale au sein des groupes d'hôtes. Vous ne l'avez pas créé vous-même et vous ne pouvez pas ajouter activement un hôte à ce groupe. D'où vient donc ce groupe d'hôtes ? Comme, par définition, chaque hôte dans Checkmk doit appartenir à un groupe, Checkmk assigne par défaut au groupe "spécial" check_mk
tous les hôtes que vous n'avez pas spécifiquement assignés à un groupe.
Dès que vous avez assigné un hôte à l'un de vos propres groupes d'hôtes, Checkmk le retire du groupe check_mk
. Il n'y a pas non plus de moyen de réassigner un hôte au groupe d'hôtes check_mk
.
Ce sont exactement les propriétés du groupe check_mk
qui sont utilisées dans notre exemple : puisque chaque hôte doit être assigné à un emplacement, le groupe d'hôtes check_mk
doit être vide. S'il n'est pas vide, il faut agir, c'est-à-dire que les hôtes qu'il contient doivent être assignés aux groupes d'hôtes et donc à leurs emplacements appropriés.
2.2. Incorporer l'instruction dans l'agent
Jusqu'à présent, en tant qu'utilisateur de l'instance, vous avez utilisé l'instruction lq
pour afficher les informations, ce qui est utile pour comprendre les données.
Toutefois, pour pouvoir récupérer ces données sur le serveur Checkmk, la nouvelle commande doit être intégrée à l'agent Checkmk sur l'hôte surveillé. Théoriquement, vous pourriez éditer directement l'agent Checkmk dans le fichier /usr/bin/check_mk_agent
et y intégrer cette partie. Cette méthode présenterait toutefois l'inconvénient de faire disparaître votre nouvelle commande lors de la mise à jour du logiciel de l'agent, car ce fichier serait écrasé lors de la mise à jour.
Il est donc préférable de créer un plugin d'agent, pour lequel vous n'avez besoin que d'un fichier exécutable contenant l'instruction et se trouvant dans le répertoire /usr/lib/check_mk_agent/plugins/
.
Une dernière chose est importante : les données ne peuvent pas être simplement sorties. Vous aurez encore besoin d'un en-tête de section. Il s'agit d'une ligne spécialement formatée qui contient le nom du nouveau plugin d'agent. Cet en-tête de section permet à Checkmk de reconnaître ultérieurement où commencent les données du nouveau plugin d'agent et où se terminent les données du plugin précédent. Il est plus facile de savoir quand l'en-tête de section et le plugin de check ont le même nom - même si ce n'est pas une obligation.
cmk -L
Il vous faut donc tout d'abord un nom significatif pour votre nouveau plugin de contrôle. Ce nom ne peut contenir que des lettres minuscules (uniquement a-z, pas de trémas, pas d'accents), des traits de soulignement et des chiffres, et doit être unique. Évitez les conflits de noms avec les plugins de contrôle existants. Si vous souhaitez savoir quels noms existent déjà, vous pouvez en dresser la liste dans une instance Checkmk, sur la ligne d'instruction, à l'aide de surveillance, check plugin :
OMD[mysite]:~$ cmk -L
3par_capacity agent HPE 3PAR: Capacity
3par_cpgs agent HPE 3PAR: CPGs
3par_cpgs_usage agent HPE 3PAR: CPGs Usage
3par_hosts agent HPE 3PAR: Hosts
3par_ports agent HPE 3PAR: Ports
3par_remotecopy agent HPE 3PAR: Remote Copy
3par_system agent HPE 3PAR: System
3par_volumes agent HPE 3PAR: Volumes
3ware_disks agent 3ware ATA RAID Controller: State of Disks
3ware_info agent 3ware ATA RAID Controller: General Information
3ware_units agent 3ware ATA RAID Controller: State of Units
acme_agent_sessions snmp ACME Devices: Agent Sessions
acme_certificates snmp ACME Devices: Certificates
La sortie ici ne montre que les premières lignes de la très longue liste. L'utilisation de préfixes permet déjà de reconnaître facilement l'affectation de nombreux plugins de surveillance. L'utilisation de préfixes est donc également recommandée pour vos propres plugins de surveillance. Par ailleurs, la deuxième colonne indique comment le plugin de surveillance respectif obtient ses données.
Un nom approprié pour le nouveau plugin de surveillance, check plugin de notre exemple est myhostgroups
.
Vous disposez à présent de toutes les informations nécessaires pour créer le script du plugin d'agent. Créez un nouveau fichier myhostgroups
en tant qu'utilisateur root
dans le répertoire /usr/lib/check_mk_agent/plugins/
:
#!/bin/bash
columns="name members"
site="mysite"
echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"
Qu'est-ce que cela signifie en détail ?
La première ligne contient le "shebang" (abréviation de sharp et bang, ce dernier étant l'abréviation du point d'exclamation), par lequel Linux reconnaît qu'il doit exécuter le script avec le shell spécifié.
Pour que le script reste adaptable, deux variables sont introduites ensuite :
la variable
columns
, qui contient actuellement les noms de groupes et les membres associés,la variable
site
, qui contient le nom de l'instance Checkmk.
Utilisez l'instruction echo
pour produire l'en-tête de section. Comme les colonnes du tableau sont séparées par un point-virgule, utilisez l'ajout sep(59)
pour spécifier que le point-virgule est utilisé comme séparateur pour les données dans la sortie de l'agent. Le 59 représente le code de caractère ASCII 59, le point-virgule. Sans cet ajout, le caractère espace (caractère ASCII 32) serait utilisé comme séparateur par défaut.
Pour pouvoir utiliser l'instruction lq
, dont vous disposez en tant qu'utilisateur de l'instance, dans un script qui est exécuté par l'utilisateur root
, faites-la précéder de su
.
Il est possible que l'accès à |
Une fois le fichier créé, il est très important de le rendre exécutable :
root@linux# chmod +x /usr/lib/check_mk_agent/plugins/myhostgroups
Vous pouvez essayer le plugin d'agent directement à la main en entrant le chemin d'accès complet sous forme d'instruction :
root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Les groupes d'hôtes qui ne contiennent aucun hôte ne sont pas listés ici.
2.3. Test de l'agent
Les tests et le dépannage sont les tâches les plus importantes lors de la création d'un plugin d'agent fonctionnel. Il est préférable de procéder en trois étapes :
Testez le plugin d'agent 'autonome', ce que vous venez de faire dans la section précédente.
Testez l'agent dans son ensemble localement.
Récupérez l'agent sur le serveur Checkmk.
Tester l'agent localement est très simple. Comme root
, appelez l'instruction check_mk_agent
:
root@linux# check_mk_agent
La nouvelle section doit apparaître quelque part dans la très longue sortie. Les plugins d'agents sont édités par l'agent à la fin du processus.
Vous pouvez faire défiler la sortie en ajoutant less
(appuyez sur la barre d'espacement pour faire défiler, /
pour rechercher et q
pour quitter) :
root@linux# check_mk_agent | less
Vous pouvez également rechercher les lignes intéressantes dans la sortie. Par exemple, grep
avec -A
dispose d'une option permettant d'afficher quelques lignes supplémentaires après chaque résultat, ce qui vous permet de rechercher et d'afficher la section de manière pratique :
root@linux# check_mk_agent | grep -A3 '^<<<myhostgroups'
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Le troisième et dernier test est alors directement à partir du site Checkmk. Incluez l'hôte dans la surveillance (par exemple en tant que localhost
), connectez-vous en tant qu'utilisateur de l'instance et récupérez ensuite les données de l'agent avec cmk -d
:
OMD[mysite]:~$ cmk -d localhost | grep -A3 '^<<<myhostgroups'
Cela devrait produire le même résultat que l'instruction précédente.
Si cela fonctionne, votre agent est prêt. Et qu'avez-vous fait pour cela ? Vous avez créé un petit script sous le chemin d'accès /usr/lib/check_mk_agent/plugins/myhostgroups
et l'avez rendu exécutable.
Tout ce qui suit ne se passe plus que sur le serveur Checkmk : c'est là que vous écrivez le plugin de surveillance, check plugin.
3. Écrire un plugin de surveillance, check plugin simple
Préparer l'agent n'est que la moitié du plaisir. Vous devez maintenant apprendre à Checkmk comment gérer les informations de la nouvelle section de l'agent, quels services il doit générer, quand ils doivent passer en WARN ou CRIT, etc. Vous pouvez faire tout cela en programmant un plugin de check à l'aide de Python.
3.1. Préparation du fichier
Vous trouverez un répertoire préparé pour vos propres plugins de vérification dans la hiérarchie local
du répertoire du site. Il s'agit de ~/local/lib/check_mk/base/plugins/agent_based/
. Ici, dans le chemin, base
signifie la partie de Checkmk qui est responsable de la surveillance et des notifications proprement dites. Le dossier agent_based
contient tous les plugins associés à l'agent Checkmk (c'est-à-dire pas les plugins de notification, par exemple). Il est préférable de basculer vers le répertoire de surveillance, les plugins de surveillance, les plugins de notification, par exemple) :
OMD[mysite]:~$ cd local/lib/check_mk/base/plugins/agent_based
Le répertoire appartient à l'utilisateur de l'instance et vous pouvez donc le modifier. Vous pouvez éditer votre plugin de surveillance, check plugin avec n'importe quel éditeur de texte installé sur le système Linux.
Créez donc ici le fichier myhostgroups.py
pour le plugin de surveillance. La convention veut que le nom du fichier reflète le nom de la section de l'agent. Il est obligatoire que le fichier se termine par .py
, car à partir de la version 2.0.0 de Checkmk, les plugins de surveillance sont toujours de véritables modules Python.
Un cadre de base exécutable(Télécharger sur GitHub), que vous développerez étape par étape dans la suite, ressemble à ceci :
#!/usr/bin/env python3
from .agent_based_api.v1 import check_levels, Metric, register, Result, Service, State
def parse_myhostgroups(string_table):
parsed = {}
return parsed
def discover_myhostgroups(section):
yield Service()
def check_myhostgroups(section):
yield Result(state=State.OK, summary="Everything is fine")
register.agent_section(
name = "myhostgroups",
parse_function = parse_myhostgroups,
)
register.check_plugin(
name = "myhostgroups",
service_name = "Host group check_mk",
discovery_function = discover_myhostgroups,
check_function = check_myhostgroups,
)
Vous devez d'abord importer les fonctions et les classes requises pour les plugins de check à partir des modules Python. La méthode la plus simple est import *
, mais vous devriez l'éviter, car elle ne permet pas de savoir quels espaces nommage ont été mis à disposition.
Pour notre exemple, seuls les éléments utilisés dans le reste de cet article seront importés :
from .agent_based_api.v1 import check_levels, Metric, register, Result, Service, State
3.2. Ecrire la fonction parse
La fonction parse a pour tâche d'"analyser" les données "brutes" de l'agent, c'est-à-dire de les analyser et de les diviser, et de mettre ces données dans un formulaire logiquement structuré qui est facile à traiter pour toutes les étapes suivantes.
Comme indiqué dans la section consacrée au test de l'agent, la section fournie par le plugin d'agent présente la structure suivante :
<<<myhostgroups:sep(59)>>>
Hamburg;myhost11,myhost22,myhost33
Munich;myhost1,myhost2,myhost3
check_mk;localhost
Checkmk divise déjà les lignes de la section fournie par le plugin d'agent en une liste de lignes sur la base du séparateur figurant dans l'en-tête de la section (dans l'exemple ;
), ces lignes étant à leur tour des listes de mots. La structure de données suivante est donc disponible dans Checkmk à la place des données brutes fournies par le plugin d'agent :
[
['Hamburg', 'myhost11,myhost22,myhost33'],
['Munich', 'myhost1,myhost2,myhost3'],
['check_mk', 'localhost']
]
Dans la liste intérieure, le premier élément contient le nom du groupe d'hôtes et le second les noms des hôtes appartenant au groupe.
Vous pouvez adresser toutes ces informations, mais uniquement via leur position dans l'ensemble de données. Vous devrez donc toujours spécifier le nombre de crochets et le numéro de "séquence" du ou des contenu(s) souhaité(s) à l'intérieur de chaque crochet. Avec des volumes de données plus importants, cela devient de plus en plus complexe et il devient de plus en plus difficile d'en conserver un aperçu.
À ce stade, la fonction parse offre des avantages évidents grâce à la structure qu'elle crée. Elle rend le code plus facile à lire, les accès sont plus performants et il est beaucoup plus facile de conserver un aperçu. Elle transforme la structure de données fournie par Checkmk de manière à ce que vous puissiez adresser chacune des valeurs individuelles par nom (ou clé) à volonté, sans être obligé de parcourir plusieurs fois le champ(tableau) pour trouver ce que vous cherchez :
{
'Hamburg': {'members': 'myhost11,myhost22,myhost33'},
'Munich': {'members': 'myhost1,myhost2,myhost3'},
'check_mk': {'members': 'localhost'}
}
La convention veut que la fonction d'analyse soit nommée d'après la section de l'agent et commence par parse_
. Elle reçoit string_table
comme seul argument. Notez que vous n'êtes pas libre de choisir l'argument ici - il doit vraiment être nommé comme ceci.
def parse_myhostgroups(string_table):
# print(string_table)
parsed = {}
for line in string_table:
parsed[line[0]] = {"members": line[1]}
# print(parsed)
return parsed
Avec def
, vous spécifiez en Python qu'une fonction doit être définie ci-dessous.parsed = {}
crée le dictionnaire avec la structure de données améliorée. Dans notre exemple, nous allons parcourir chaque ligne, élément par élément. Le groupe d'hôtes suivi des membres du groupe d'hôtes est extrait de chaque ligne et assemblé en une entrée pour le dictionnaire.
Le dictionnaire est ensuite renvoyé à l'adresse return parsed
.
Dans l'exemple ci-dessus, vous trouverez deux lignes commentées. Si vous les commentez ultérieurement lorsque vous testez le plugin de surveillance, les données avant et après l'exécution de la fonction parse seront affichées sur la ligne d'instruction. Cela vous permet de vérifier si la fonction fait vraiment ce qu'elle est censée faire. |
3.3. Enregistrement de la section de l'agent
Pour que tout cela prenne effet, vous devez faire en sorte que la fonction parse, et la nouvelle section agent en général, soient connues de Checkmk. Pour ce faire, appelez une fonction d'enregistrement :
register.agent_section(
name = "myhostgroups",
parse_function = parse_myhostgroups,
)
Il est important que le nom de la section corresponde exactement à l'en-tête de la section dans la sortie de l'agent. À partir de ce moment, chaque plugin de surveillance qui utilise la section myhostgroups
reçoit la valeur de retour de la fonction parse. En règle générale, il s'agira du plugin de surveillance du même nom. Mais d'autres plugins de surveillance peuvent également souscrire à cette section, comme nous le montrerons dans l'extension du plugin de surveillance.
À propos : Si vous voulez savoir exactement comment cela fonctionne, vous pouvez jeter un coup d'œil à la documentation de l'API Check à cet endroit : vous y trouverez une description détaillée de cette fonction d'enregistrement - ainsi que des fonctions et objets qui seront utilisés plus loin dans cet article.
3.4. Enregistrement du plugin de surveillance, check plugin
Pour que Checkmk sache qu'il existe un nouveau plugin de check, il faut l'enregistrer. Cela se fait en appelant la fonction register.check_plugin
. Vous devez toujours spécifier au moins quatre éléments :
name
: Le nom du plugin de surveillance. Le plus simple est d'utiliser le même nom que votre nouvelle section d'agent. De cette manière, le check défini plus loin dans la fonction de check sait automatiquement quelle section il doit évaluer.service_name
Le nom du service tel qu'il doit alors apparaître dans la surveillance : Le nom du service tel qu'il doit alors apparaître dans la surveillance.discovery_function
Le nom du service tel qu'il doit apparaître dans la surveillance : la fonction de découverte des services de ce type (nous y reviendrons).check_function
La fonction permettant d'effectuer le check proprement dit (nous y reviendrons).
Pour le plugin de surveillance, check, check plugin ressemblera à ceci :
register.check_plugin(
name = "myhostgroups",
service_name = "Host group check_mk",
discovery_function = discover_myhostgroups,
check_function = check_myhostgroups,
)
Il est préférable de ne pas l'essayer tout de suite, car vous devez d'abord écrire les fonctions discover_myhostgroups
et check_myhostgroups
, qui doivent apparaître dans le code source avant l' enregistrement ci-dessus.
3.5. Écrire la fonction d'identification
Une caractéristique spéciale de Checkmk est la reconnaissance automatique des services à surveiller. Pour que cela fonctionne, chaque plugin de check doit définir une fonction qui utilise la sortie de l'agent pour reconnaître si un service de ce type ou quels services de ce type doivent être créés pour l'hôte en question.
La fonction de découverte est toujours appelée lorsqu'une reconnaissance du service est effectuée pour un hôte. Elle décide alors si des services doivent être créés ou lesquels. Dans le cas standard, elle reçoit exactement un argument portant le nom section
. Celui-ci contient les données de la section de l'agent dans un format préparé par la fonction parse.
Mettez donc en œuvre la logique simple suivante :si la section d'agent myhostgroups
existe, créez également un service approprié. Celui-ci apparaîtra alors automatiquement sur tous les hôtes sur lesquels le plugin d'agent est déployé.
Pour les plugins de surveillance check qui ne créent qu'un service par hôte, aucune autre information n'est nécessaire :
def discover_myhostgroups(section):
yield Service()
La fonction d'identification doit renvoyer un objet du type service
pour chaque service à créer à l'aide de yield
(pas avec return
). En Python, yield
a la même fonction que return
- tous deux renvoient une valeur à la fonction appelante. La différence décisive est que yield
se souvient de l'état d'avancement du traitement des données par la fonction.
L'appel suivant se poursuit après la dernière déclaration de yield
- et ne recommence pas au début. Cela signifie que ce n'est pas seulement le premier résultat qui est lu (comme ce serait le cas avec return
), mais tous les résultats dans l'ordre (cet avantage deviendra pertinent plus tard dans notre exemple avec la reconnaissance du service).
3.6. Écriture de la fonction de check
Vous pouvez maintenant passer à la fonction de check proprement dite, qui utilise la sortie actuelle de l'agent pour décider de l'état que le service doit prendre et peut fournir d'autres informations.
L'objectif de la fonction de contrôle est de mettre en place un contrôle qui peut être utilisé pour vérifier si un groupe d'hôtes a été assigné à un hôte quelconque. Pour ce faire, elle vérifie si le groupe d'hôtes check_mk
contient des hôtes. Si c'est le cas, le service doit recevoir le statut CRIT. Si ce n'est pas le cas, tout est OK et il en va de même pour l'état du service.
Voici l'implémentation :
def check_myhostgroups(section):
attr = section.get("check_mk")
hosts = attr["members"] if attr else ""
if hosts:
yield Result(state=State.CRIT, summary=f"Default group is not empty; Current member list: {hosts}")
else:
yield Result(state=State.OK, summary="Everything is fine")
Et maintenant l'explication : La fonction check_myhostgroups()
récupère d'abord la valeur appartenant à la clé check_mk
dans la variable attr
. Ensuite, la variable hosts
est liée à la valeur members
si elle existe. S'il n'y a pas de members
, hosts
reste vide.
Cette étape est suivie d'une requête if
pour l'évaluation proprement dite :
Si la variable
hosts
a un contenu, c'est-à-dire que le groupe d'hôtescheck_mk
n'est pas vide, le statut du service passe à CRIT et un texte d'avis est édité. Ce texte contient également une liste des noms d'hôtes de tous les hôtes qui se trouvent dans le groupe d'hôtescheck_mk
. La chaîne de caractères F de Python est utilisée avec des expressions, qui est ainsi nommée parce que la chaîne est précédée de la lettref
.Si la variable
hosts
est vide, c'est-à-dire s'il n'y a pas d'hôtes dans le groupe d'hôtescheck_mk
, le statut du service devient OK. Dans ce cas, un message approprié est également affiché.
Une fois la fonction de check créée, le plugin de surveillance est prêt.
Le plugin de surveillance, check plugin, ainsi que le plugin d'agentont été mis à disposition sur GitHub.
3.7. Test et activation du plugin de surveillance, check plugin
Le test et l'activation s'effectuent en ligne de commande avec l'instruction cmk
.
Essayez d'abord l'identification du service avec l'option -I
. En ajoutant l'option v
(pour verbose), une sortie détaillée est demandée. L'option --detect-plugins
restreint l'exécution de l'instruction à ce plugin de check et, par l'intermédiaire de localhost
, à cet hôte :
OMD[mysite]:~$ cmk -vI --detect-plugins=myhostgroups localhost
Discovering services and host labels on: localhost
localhost:
+ FETCHING DATA
[TCPFetcher] Execute data source
[PiggybackFetcher] Execute data source
No piggyback files for 'localhost'. Skip processing.
No piggyback files for '127.0.0.1'. Skip processing.
+ ANALYSE DISCOVERED HOST LABELS
SUCCESS - Found no new host labels
+ ANALYSE DISCOVERED SERVICES
+ EXECUTING DISCOVERY PLUGINS (1)
1 myhostgroups
SUCCESS - Found 1 services
Comme prévu, l'identification de service reconnaît un nouveau service dans le plugin de surveillance check myhostgroups
.
Vous pouvez maintenant essayer le plugin de surveillance, check, check, check :
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups -v localhost
+ FETCHING DATA
[TCPFetcher] Execute data source
[PiggybackFetcher] Execute data source
No piggyback files for 'localhost'. Skip processing.
No piggyback files for '127.0.0.1'. Skip processing.
Host group check_mk Default group is not empty; Current member list: localhost
[agent] Success, [piggyback] Success (but no data found for this host), execution time 1.3 sec | execution_time=1.330 user_time=0.010 system_time=0.000 children_user_time=0.000 children_system_time=0.000 cmk_time_agent=1.330
En exécutant le check, le statut du service trouvé précédemment sera déterminé.
Si tout s'est passé comme prévu, vous pouvez activer les modifications ; dans le cas contraire, vous trouverez des informations utiles dans le chapitre consacré au dépannage.
Enfin, activez les modifications en redémarrant la noyau de surveillance:
OMD[mysite]:~$ cmk -R
Generating configuration for core (type nagios)...
Precompiling host checks...OK
Validating Nagios configuration...OK
Restarting monitoring core...OK
Dans la surveillance Checkmk, vous trouverez maintenant le nouveau service Host group check_mk sur l'hôte localhost
:
check_mk
n'est pas vide, le service est CRIT.Félicitations pour la création réussie de votre premier plugin de surveillance, check plugin !
4. Extension du plugin de check, surveillance, check plugin
4.1. Travaux préparatoires
Le premier plugin de check, récemment achevé, doit maintenant être étendu pas à pas. Jusqu'à présent, le plugin d'agent n'a fourni que des informations sur les noms et les membres des groupes d'hôtes. Pour pouvoir évaluer le statut des hôtes et des services qui y sont exécutés, par exemple, il faut davantage de données.
Extension du plugin d'agent
Vous allez d'abord étendre le plugin d'agent une fois pour collecter toutes les informations qui seront nécessaires pour étendre le plugin de surveillance, check plugin dans les sections suivantes.
Pour connaître les informations que Checkmk fournit sur les groupes d'hôtes, vous pouvez interroger toutes les colonnes disponibles de la table des groupes d'hôtes à l'aide de l'instruction suivante, en tant qu'utilisateur de l'instance :
OMD[mysite]:~$ lq "GET columns\nFilter: table = hostgroups\nColumns: name"
action_url
alias
members
members_with_state
name
notes
notes_url
num_hosts
...
La sortie va encore plus loin. La table comporte près de 30 colonnes - et la plupart d'entre elles ont même des noms significatifs. Les colonnes suivantes sont intéressantes : nombre d'hôtes par groupe (colonne num_hosts
), nombre d'hôtes dans l'état UP (num_hosts_up
), nombre de services de tous les hôtes du groupe (num_services
) et nombre de services dans l'état OK (num_services_ok
).
Ces nouvelles colonnes ne doivent plus être fournies que par l'agent, ce que vous pouvez faire en étendant le plugin d'agent créé dans le chapitre précédent.
En tant qu'utilisateur root, éditez le script du plugin d'agent. Comme le script a déjà placé les valeurs configurables dans des variables, il suffit de modifier la ligne commençant par columns
et d'y introduire les quatre colonnes supplémentaires récupérées :
#!/bin/bash
columns="name members num_hosts num_hosts_up num_services num_services_ok"
site="mysite"
echo '<<<myhostgroups:sep(59)>>>'
su - ${site} lq "GET hostgroups\nColumns: ${columns}"
Exécutez le script pour le vérifier :
root@linux# /usr/lib/check_mk_agent/plugins/myhostgroups
<<<myhostgroups:sep(59)>>>
Munich;myhost3,myhost2,myhost1;3;3;180;144
Hamburg;myhost22,myhost33,myhost11;3;2;132;105
check_mk;SQL-Server,localhost;2;2;95;83
Les quatre nouvelles valeurs - séparées par un point-virgule - apparaissent désormais à la fin de chaque ligne.
Avec cette modification, le plugin d'agent fournit maintenant des données différentes de celles qu'il fournissait auparavant. À ce stade, il est important de s'assurer qu'avec les données modifiées, le plugin de check fait toujours ce qu'il est censé faire.
Extension de la fonction parse
Dans un plugin de check, la fonction parse est chargée de convertir les données fournies par le plugin d'agent. Lors de l'écriture de la fonction parse, vous n'avez pris en compte que deux colonnes du tableau des groupes d'hôtes. À présent, six colonnes sont fournies au lieu de deux. La fonction parse doit donc être personnalisée pour traiter les quatre colonnes supplémentaires.
En tant qu'utilisateur de l'instance, modifiez la fonction parse dans le fichier myhostgroups.py
, qui contient le plugin check :
def parse_myhostgroups(string_table):
parsed = {}
column_names = [
"name",
"members",
"num_hosts",
"num_hosts_up",
"num_services",
"num_services_ok",
]
for line in string_table:
parsed[line[0]] = {}
for n in range(1, len(column_names)):
parsed[line[0]][column_names[n]] = line[n]
return parsed
Tout ce qui se trouve entre parsed = {}
et return parsed
a été modifié ici. Tout d'abord, les colonnes à traiter sont définies sous leur nom en tant que liste column_names
. Un dictionnaire est ensuite créé dans la boucle for
en générant les paires clé-valeur dans chaque ligne à partir du nom de la colonne et de la valeur lue.
Cette extension n'est pas critique pour la fonction de contrôle existante, car la structure des données dans les deux premières colonnes reste inchangée. Seules des colonnes supplémentaires sont fournies, qui ne sont pas (encore) évaluées dans la fonction de contrôle.
Maintenant que les nouvelles données peuvent être traitées, vous les utiliserez également.
4.2. Reconnaissance du service
Dans l'exemple, vous avez intégré un contrôle très simple qui crée un service sur un hôte. Cependant, il est également très fréquent que plusieurs services soient créés à partir d'un seul contrôle sur un hôte.
L'exemple le plus courant est un service pour un système de fichiers sur un hôte. Le plugin de contrôle portant le nom df
crée un service par système de fichiers sur l'hôte. Afin de distinguer ces services, le point de montage du système de fichiers (par exemple /var
) ou la lettre du lecteur (par exemple C:
) est incorporé dans le nom du service. Il en résulte un nom de service tel que Filesystem /var
ou Filesystem C:
. Le mot /var
ou C:
est désigné ici comme un élément. Nous parlons donc également d'un contrôle avec des éléments.
Si vous voulez construire un check avec des éléments, vous devez implémenter les fonctions suivantes :
La fonction d'identification doit générer un service pour chacun des éléments qui doivent être surveillés sur l'hôte.
Vous devez inclure l'élément dans le nom du service en utilisant le caractère générique
%s
(par exemple"Filesystem %s"
).La fonction de check est appelée une fois, séparément pour chaque élément, et reçoit ce service comme argument. Elle doit ensuite extraire les données pertinentes pour cet élément à partir des données de l'agent.
Pour tester cela en pratique, vous allez créer un service distinct pour chaque groupe d'hôtes existant.
Étant donné que le plugin de surveillance check myhostgroups
créé dans le chapitre précédent pour vérifier le groupe standard check_mk
doit continuer à fonctionner, ce plugin de surveillance reste tel quel. Pour l'extension, créez un nouveau plugin de surveillance check dans le fichier myhostgroups.py
- dans un premier temps, de la même manière que précédemment, en enregistrant le plugin.
Le nouvel enregistrement est effectué en plus de l'enregistrement existant, l'enregistrement présenté dans le chapitre précédent reste inchangé. |
Voici le nouveau code :
...
register.check_plugin(
name = "myhostgroups_advanced",
sections = ["myhostgroups"],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
)
Pour que le nouveau plugin de contrôle puisse être distingué de l'ancien, un nom unique lui est attribué avec myhostgroups_advanced
. Le paramètre sections
détermine les sections de la sortie de l'agent auxquelles le plugin de contrôle s'abonne. Ici, myhostgroups
est utilisé pour spécifier que le nouveau plugin de contrôle utilise les mêmes données que l'ancien : la section du plugin de l'agent préparée par la fonction parse.
Le nom du service contient maintenant l'espace réservé %s
. Le nom de l'élément est inséré plus tard à cet endroit par Checkmk. Les deux dernières lignes définissent les noms de la nouvelle fonction d'identification et de la nouvelle fonction de check, qui doivent encore être écrites.
Commençons par la fonction d'identification, qui a désormais pour tâche de déterminer les éléments à surveiller - elle est également saisie en plus de la fonction existante :
def discover_myhostgroups_advanced(section):
for group in section:
if group != "check_mk":
yield Service(item=group)
Comme précédemment, la fonction de découverte reçoit l'argument section
. Les différents groupes d'hôtes sont parcourus en boucle. Tous les groupes d'hôtes sont intéressants ici - à l'exception de check_mk
, car ce groupe d'hôtes spécial a déjà été pris en charge par le plugin de check myhostgroups
existant. Chaque fois qu'un élément est trouvé, il est renvoyé avec yield
, qui crée un objet du type Service
, qui reçoit à son tour le nom du groupe d'hôtes en tant qu'élément.
Si l'hôte est surveillé ultérieurement, la fonction de contrôle est appelée séparément pour chaque service - et donc pour chaque élément. Cela vous amène à la définition de la fonction de contrôle pour le nouveau plugin de contrôle myhostgroups_advanced
. La fonction de contrôle reçoit l'argument item
en plus de la section. La première ligne de la fonction ressemble alors à ceci :
def check_myhostgroups_advanced(item, section):
L'algorithme de la fonction check est simple : si le groupe d'hôtes existe, le service est mis à OK et le nombre et les noms des hôtes du groupe sont listés. La fonction complète pour ceci :
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if attr:
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Le résultat du check est livré en retournant un objet de la classe Result
via yield
. Cela nécessite les paramètres state
et summary
. Ici, state
définit l'état du service (dans l'exemple OK
) et summary
le texte qui est affiché dans Summary du service. Ceci est purement informatif et n'est pas évalué plus avant par Checkmk. Vous pouvez en savoir plus à ce sujet dans la section suivante.
Jusqu'ici, tout va bien. Mais que se passe-t-il si l'élément que vous recherchez n'est pas trouvé ? Cela peut arriver si un service a déjà été créé pour un groupe d'hôtes dans le passé, mais que ce groupe d'hôtes a maintenant disparu - soit parce que le groupe d'hôtes existe toujours dans Checkmk mais ne contient plus d'hôtes, soit parce qu'il a été complètement supprimé. Dans les deux cas, ce groupe d'hôtes n'est plus présent dans l'output de l'agent.
La bonne nouvelle : Checkmk s'en occupe ! Si un élément recherché n'est pas trouvé, Checkmk génère automatiquement le résultat UNKNOWN - Item not found in monitoring data
pour le service. C'est intentionnel et c'est une bonne chose. Si un élément recherché n'est pas trouvé, vous pouvez simplement exécuter Python hors de la fonction et laisser Checkmk faire son travail.
Checkmk sait seulement que l'élément qui était là auparavant a maintenant disparu. Checkmk n'en connaît pas la raison - mais vous, si. Il est donc approprié de ne pas garder cette connaissance pour vous, d'intercepter cette condition dans la fonction de check et d'afficher un message utile.
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if not attr:
yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
return
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Qu'est-ce qui a changé ? La condition d'erreur est maintenant traitée en premier. Par conséquent, vérifiez dans la branche if
si l'élément n' existe vraiment pas, mettez le statut à CRIT et quittez la fonction avec return
. Dans tous les autres cas, retournez OK comme auparavant.
Cela signifie que vous avez adopté la situation des groupes d'hôtes disparus dans la fonction de check. Au lieu de UNKNOWN, le service associé sera désormais CRIT et contiendra des informations sur la cause du statut critique.
Ceci complète le nouveau plugin de contrôle en tant qu'extension de l'ancien. Le plugin d'agentétendu et le fichier étendu pour les plugins de contrôlese trouvent à nouveau sur GitHub. Ce dernier contient le plugin de contrôle simple myhostgroups
du chapitre précédent, la fonction d'analyse étendue et les composants du nouveau plugin de contrôle myhostgroups_advanced
avec son enregistrement, sa fonction de découverte et sa fonction de contrôle. Notez que les fonctions doivent toujours être définies avant l'enregistrement afin qu'il n'y ait pas d'erreurs causées par des noms de fonctions indéfinis.
Comme le nouveau plugin de contrôle myhostgroups_advanced
fournit de nouveaux services, vous devez effectuer une identification des services pour ce plugin de contrôle et activer les modifications afin de voir ces services dans la surveillance :
Procédez comme décrit dans le chapitre sur le plugin de surveillance simple.
4.3. Résumé et détails
Dans la surveillance de Checkmk, chaque service a un statut -OK, WARN, etc. - ainsi qu'une ligne de texte. Ce texte se trouve dans la colonne Summary - comme on peut le voir dans la capture d'écran précédente - et a donc pour tâche de fournir un bref résumé du statut du service. Le concept est que ce texte ne doit pas dépasser une longueur de 60 caractères, ce qui garantit un affichage concis du tableau sans sauts de ligne gênants.
Il y a également le champ Details, dans lequel sont affichés tous les détails sur le statut du service, qui comprend également toutes les informations sommaires. En cliquant sur le service, vous ouvrez la page du service, dans laquelle les deux champs Summary et Details sont visibles, parmi beaucoup d'autres.
En appelant yield Result(...)
, vous pouvez déterminer quelles informations sont si importantes qu'elles doivent être affichées dans le résumé, et pour lesquelles il est suffisant qu'elles apparaissent dans les détails.
Dans notre exemple, vous avez toujours utilisé un appel du type suivant :
yield Result(state=State.OK, summary=f"{attr['num_hosts']} hosts in this group: {attr['members']}")
Cela signifie que le texte défini comme summary
apparaît toujours dans le Summary- et également dans le Details. Vous ne devriez donc utiliser cette méthode que pour les informations importantes. Si un groupe d'hôtes contient de nombreux hôtes, la liste récapitulative peut devenir très longue - plus longue que les 60 caractères recommandés. Si une information est d'importance secondaire, vous pouvez utiliser details
pour spécifier que son texte n' apparaisse que dans les détails :
yield Result(
state = State.OK,
summary = f"{attr['num_hosts']} hosts in this group",
details = f"{attr['num_hosts']} hosts in this group: {attr['members']}",
)
Dans l'exemple ci-dessus, la liste des hôtes n'est donc affichée que dans le Details. Le Summary n'indique alors que le nombre d'hôtes dans le groupe :
Outre summary
et details
, il existe un troisième paramètre. Avec notice
, vous spécifiez qu'un texte pour un service dans l'état OK n' est affiché que dans les détails - mais aussi dans le résumé pour tous les autres états. Cela permet de voir immédiatement dans le résumé pourquoi le service n'est pas OK. Le paramètre notice
n'est pas particulièrement utile si les textes sont liés de manière permanente aux états, comme dans notre exemple jusqu'à présent.
En résumé, cela signifie que
Le texte total du résumé ne doit pas dépasser 60 caractères pour les services qui sont OK.
Utilisez toujours
summary
ounotice
- au moins l'un ou l'autre, mais pas les deux.Si nécessaire, ajoutez
details
si le texte des détails doit être une alternative.
4.4. Plusieurs résultats partiels par service
Pour éviter que le nombre de services sur un hôte n'augmente de manière excessive, plusieurs résultats partiels sont souvent combinés en un seul service. Par exemple, le service Memory sous Linux vérifie non seulement la charge de travail de la RAM et du swap, mais aussi la mémoire partagée, les tables de pages et toutes sortes d'autres choses.
L'API Check fournit une interface très pratique pour cela. Une fonction de check peut simplement générer un résultat avec yield
aussi souvent que nécessaire. Le statut global du service est alors basé sur le plus mauvais résultat partiel dans l'ordre OK → WARN → UNKNOWN → CRIT.
Dans notre exemple, utilisez cette option pour définir deux résultats supplémentaires pour chaque service des groupes d'hôtes en plus du résultat existant. Ceux-ci évaluent le pourcentage d'hôtes dans l'état UP et les services dans l'état OK. Vous utilisez les colonnes supplémentaires du tableau des groupes d'hôtes définies précédemment dans la sortie de l'agent et la fonction d'analyse syntaxique.
Développez maintenant la fonction check par étapes, de haut en bas :
def check_myhostgroups_advanced(item, section):
attr = section.get(item)
if not attr:
yield Result(state=State.CRIT, summary="Group is empty or has been deleted")
return
members = attr["members"]
num_hosts = int(attr["num_hosts"])
num_hosts_up = int(attr["num_hosts_up"])
num_services = int(attr["num_services"])
num_services_ok = int(attr["num_services_ok"])
La branche if
reste inchangée, c'est-à-dire que les nouveaux résultats partiels ne s'appliquent qu'aux groupes d'hôtes qui existent également. Vous définissez ensuite cinq variables pour les colonnes du tableau des groupes d'hôtes contenu dans la section. D'une part, cela augmente la lisibilité et, d'autre part, vous pouvez convertir les chaînes lues en nombres avec int()
pour les quatre colonnes qui doivent encore être utilisées pour le calcul.
Le seul résultat existant reste (presque) inchangé :
yield Result(
state = State.OK,
summary = f"{num_hosts} hosts in this group",
details = f"{num_hosts} hosts in this group: {members}",
)
Seul l'accès dans la 'F-String' Python à l'expression qui renvoie la valeur est désormais plus facile qu'auparavant, puisque le attr
se trouve déjà dans les définitions de variables.
Passons maintenant au coeur de l'extension, la définition d'un résultat qui met en oeuvre l'énoncé suivant : "Le service du groupe d'hôtes est WARN lorsque 90 % des hôtes sont UP, et CRIT lorsque 80 % des hôtes sont UP". La convention ici est que le check passe en WARN ou CRIT dès que le seuil est atteint - et pas seulement lorsqu'il est dépassé. L'API Check fournit la fonction auxiliaire check_levels
pour comparer une valeur déterminée avec des valeurs seuils.
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
label = "UP hosts",
notice_only = True,
)
Dans la première ligne, le pourcentage est calculé à partir du nombre total et du nombre d'hôtes dans l'état UP et stocké dans la variable hosts_up_perc
. La barre oblique (/
) exécute une division en virgule flottante, ce qui garantit que le résultat est une valeur flottante. C'est utile parce que certaines des fonctions utilisées plus tard attendent des valeurs flottantes en entrée.
Dans la deuxième ligne, le résultat de la fonction check_levels
est renvoyé sous la forme d'un objet de type result
. Cette fonction est alimentée par le pourcentage qui vient d'être calculé en tant que valeur (hosts_up_perc
), par les deux valeurs seuils inférieures (levels_lower
), par une étiquette qui précède la sortie (label
) et enfin par notice_only=True
.
Ce dernier paramètre utilise le paramètre notice
déjà introduit dans la section précédente pour l'objet Result()
. Avec notice_only=True
, vous spécifiez que le texte du service n'est affiché dans Summary que si le statut n'est pas OK. Toutefois, les résultats partiels qui conduisent à un WARN ou à un CRIT seront toujours visibles dans le résumé - quelle que soit la valeur de notice_only
.
Enfin, vous définissez le troisième résultat de la même manière que le deuxième, qui évalue le pourcentage de services dans l'état OK:
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (90.0, 80.0),
label = "OK services",
notice_only = True,
)
Ceci complète la fonction de check.
Le service d'un groupe d'hôtes évalue maintenant trois résultats et affiche le plus mauvais état de ceux-ci dans la surveillance, comme dans l'exemple suivant :
4.5. Métriques
Pas toujours, mais souvent, les contrôles portent sur des nombres - et ces nombres sont très souvent des valeurs mesurées ou calculées. Dans notre exemple, le nombre d'hôtes dans le groupe d'hôtes (num_hosts
) et le nombre d'hôtes dans l'état UP (num_hosts_up
) sont les valeurs mesurées. Le pourcentage d'hôtes dans l'état UP (hosts_up_perc
) est une valeur calculée à partir de ces valeurs. Si une telle valeur peut ensuite être affichée sur une période de temps, elle est également appelée métrique.
Avec son système de graphiques intégré, Checkmk dispose d'un composant permettant de stocker, d'évaluer et d'afficher de telles valeurs, indépendamment du calcul des états OK, WARN et CRIT.
Dans cet exemple, vous définirez les deux valeurs calculées, hosts_up_perc
et services_ok_perc
, comme des métriques. Les métriques seront immédiatement visibles dans l'interface utilisateur graphique de Checkmk sans que vous ayez à faire quoi que ce soit. Un graphique est automatiquement généré pour chaque métrique.
Les métriques sont déterminées par la fonction check et renvoyées en tant que résultat supplémentaire. Le plus simple est d'ajouter les informations relatives aux métriques à la fonction check_levels()
dans l'appel.
Pour rappel, la ligne avec l'appel de la fonction check_levels()
de la section précédente suit ici :
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
label = "UP hosts",
notice_only = True,
)
Les deux nouveaux arguments de la métrique sont metric_name
et boundaries
:
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
Pour que cela reste simple et significatif, utilisez le nom de la variable dans laquelle le pourcentage est stocké en tant que valeur pour le nom de la métrique.
Vous pouvez utiliser boundaries
pour fournir au système graphique des informations sur la plage de valeurs possibles. Il s'agit de la plus petite et de la plus grande valeur possible. Dans le cas d'un pourcentage, les limites de 0.0
et 100.0
ne sont pas trop difficiles à déterminer. Les nombres à virgule flottante et les nombres entiers (qui sont convertis en interne en nombres à virgule flottante) sont autorisés, mais pas les chaînes de caractères. Si une seule limite de la plage de valeurs est définie, il suffit d'entrer None
pour l'autre limite, par exemple boundaries=(0.0, None)
.
Avec cette extension, la fonction check_levels
renvoie également un objet du type Metric
via yield
en plus de Result
.
Vous pouvez maintenant définir la métrique services_ok_perc
de la même manière. Les dernières lignes de la fonction check ressembleront alors à ceci :
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (90.0, 80.0),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)
Avec la fonction de check étendue, les deux graphiques sont visibles dans la surveillance. Dans la liste des services, l'icône indique maintenant qu'il y a des graphiques pour le service. Si vous pointez l'icône avec la souris, les graphiques seront affichés en aperçu.
Vous trouverez un aperçu de tous les graphiques, y compris leurs légendes, dans les détails du service.
Mais que faire si la valeur de la métrique souhaitée n'a pas été définie avec la fonction check_levels()
? Vous pouvez bien entendu définir une métrique indépendamment d'un appel de fonction. L'objet Metric()
, que vous pouvez également créer directement via son constructeur, est utilisé à cette fin. La définition alternative d'une métrique pour la valeur hosts_up_perc
se présente comme suit :
yield Metric(
name = "hosts_up_perc",
value = hosts_up_perc,
levels = (80.0, 90.0),
boundaries = (0.0, 100.0),
)
Les arguments de Metric()
sont très similaires à ceux de l'appel de fonction illustré ci-dessus : sont obligatoires les deux premiers arguments pour le nom de la métrique et la valeur. En outre, il y a deux arguments facultatifs : levels
pour les valeurs seuils WARN et CRIT et boundaries
pour la plage de valeurs.
La spécification de |
Utilisez maintenant la possibilité de définir non seulement les deux valeurs calculées, mais aussi toutes les valeurs mesurées en tant que métriques à l'aide de Metric()
- dans notre exemple, les quatre valeurs mesurées du tableau des groupes d'hôtes. Limitez-vous aux deux spécifications obligatoires du nom et de la valeur de la métrique. Les quatre nouvelles lignes complètent l'extension de la fonction de contrôle pour les métriques :
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (90.0, 80.0),
metric_name = "hosts_up_perc",
label = "UP hosts",
boundaries = (0.0, 100.0),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (90.0, 80.0),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)
yield Metric(name="num_hosts", value=num_hosts)
yield Metric(name="num_hosts_up", value=num_hosts_up)
yield Metric(name="num_services", value=num_services)
yield Metric(name="num_services_ok", value=num_services_ok)
Cela augmente le nombre de graphiques par service, mais vous donne également la possibilité de combiner plusieurs métriques dans un seul graphique, par exemple. Nous montrons ces options et d'autres dans la section Personnaliser l'affichage des métriques ci-dessous.
Dans le fichier d'exemple surGitHub, vous pouvez retrouver l'ensemble de la fonction de check.
4.6. Paramètres de contrôle pour les jeux de règles
Dans le plugin de contrôle avancé myhostgroups_advanced
, vous avez créé l'état WARN si seulement 90 % des hôtes sont UP, et l'état CRIT si seulement 80 % des hôtes sont UP. Les nombres 90
et 80
sont programmés directement dans la fonction de check ou, comme le diraient les programmeurs, codés en dur. Cependant, les utilisateurs sont habitués à pouvoir configurer de telles valeurs seuils et d'autres paramètres de contrôle via des règles.
Par exemple, si un groupe d'hôtes ne compte que quatre membres, les deux valeurs seuils de 90 % et 80 % ne sont pas vraiment adaptées, car le pourcentage tombe à 75 % dès que le premier hôte tombe en panne et le statut passe directement à CRIT- sans niveau WARN intermédiaire.
Par conséquent, le plugin de surveillance devrait maintenant être amélioré pour pouvoir être configuré via l'interface Setup. Pour ce faire, vous aurez besoin d'un jeu de règles. S'il existe déjà un jeu de règles approprié dans Checkmk, vous pouvez l'utiliser. Comme la fonction de surveillance et le jeu de règles doivent être saisis, ce ne sera généralement pas le cas. Vous pouvez trouver plus d'informations sur les jeux de règles existants ci-dessous.
Sachez que les exemples présentés dans cette section ne sont pas couverts par l'API Check. |
Définition d'un nouveau jeu de règles
Pour créer un nouveau jeu de règles, créez un nouveau fichier dans le répertoire ~/local/share/check_mk/web/plugins/wato
. Le nom du fichier doit être basé sur celui du plugin de surveillance et, comme tous les fichiers de plugin, doit porter l'extension .py
. Pour notre exemple, le nom du fichier myhostgroups_advanced_parameters.py
convient.
Examinons pas à pas la structure d'un tel fichier, en commençant par quelques instructions d'importation.
Si les textes de votre fichier, qui sont affichés dans l'interface graphique de Checkmk, doivent pouvoir être traduits dans d'autres langues, importez _
(trait de soulignement) :
from cmk.gui.i18n import _
Il s'agit d'une fonction qui sert de marqueur pour tous les textes traduisibles. Par exemple, au lieu de "Threshold for Warning"
, écrivez _("Threshold for Warning")
pour l'appel de fonction. Le système de traduction de Checkmk, qui est basé sur gettext, trouve de tels textes et les ajoute à la liste des textes à traduire. Si vous ne construisez la vérification que pour vous-même, vous pouvez vous en passer et, par conséquent, de la ligne import
.
Importez ensuite ce que l'on appelle les ValueSpecs. Un ValueSpec est un outil très pratique et universel qui permet d'utiliser Checkmk dans de nombreuses situations. Il sert à générer des formulaires de saisie personnalisés, à afficher et à valider les valeurs saisies et à convertir ces dernières en structures de données Python.
from cmk.gui.valuespec import (
Dictionary,
Percentage,
TextInput,
Tuple,
)
Vous aurez de toute façon besoin de Dictionary
, car à partir de la version de Checkmk 2.0.0, les paramètres de contrôle sont stockés dans des dictionnaires Python.Percentage
est responsable de la saisie de valeurs en pourcentage, TextInput
d'un texte Unicode et Tuple
d'un ensemble d'objets ordonné et unidimensionnel. Vous utiliserez également Float
et Integer
plus fréquemment.
L'étape suivante consiste à importer les classes et les fonctions nécessaires à l'enregistrement :
from cmk.gui.plugins.wato.utils import (
CheckParameterRulespecWithItem,
rulespec_registry,
RulespecGroupCheckParametersApplications,
)
Si votre plugin de surveillance myhostgroups_advanced
génère plusieurs services, importez CheckParameterRulespecWithItem
. Si votre check ne génère pas de service, en d'autres termes s'il n'a pas d'élément, importez CheckParameterRulespecWithoutItem
à la place. Vous trouverez plus d'informations sur RulespecGroup
à la fin de cette section.
Viennent ensuite les définitions proprement dites. Tout d'abord, vous définissez un champ de saisie permettant à l'utilisateur de spécifier l'élément du check. Ce champ est affiché dans la condition de la règle et permet aux utilisateurs de limiter la règle à des services spécifiques. Il est également nécessaire pour la création manuelle de checks qui doivent fonctionner sans qu'une reconnaissance soit nécessaire.
Vous créez ce champ à l'aide de TextInput
. Un titre lui est attribué à l'aide de title
, qui est ensuite généralement affiché en tant qu'intitulé du champ de saisie. Si vous avez de la sympathie pour vos utilisateurs, incluez un commentaire utile pour l'aide en ligne :
def _item_valuespec_myhostgroups_advanced():
return TextInput(
title = "Host group name",
help = "You can restrict this rule to certain services of the specified hosts.",
)
Vous êtes libre de choisir le nom de la fonction qui renvoie cette ValueSpec ; il n'est requis que pour l'enregistrement ci-dessous. Le nom doit commencer par un trait de soulignement afin que la fonction ne soit pas visible au-delà de la limite du module.
Vient ensuite la ValueSpec pour la saisie des paramètres de contrôle proprement dits. Vous créez également une fonction qui génère la ValueSpec à cet effet. L'utilisateur doit pouvoir définir les deux valeurs seuils pour WARN et CRIT séparément pour le nombre d'hôtes dans l'état UP et les services dans l'état OK:
def _parameter_valuespec_myhostgroups_advanced():
return Dictionary(
elements = [
("hosts_up_lower",
Tuple(
title = _("Lower percentage threshold for host in UP status"),
elements = [
Percentage(title=_("Warning")),
Percentage(title=_("Critical")),
],
)
),
("services_ok_lower",
Tuple(
title = _("Lower percentage threshold for services in OK status"),
elements = [
Percentage(title=_("Warning")),
Percentage(title=_("Critical")),
],
)
),
],
)
L'adresse return Dictionary()
est obligatoire. À l'intérieur de celle-ci, utilisez elements=[]
pour créer la liste des paramètres, dans notre exemple hosts_up_lower
et services_ok_lower
. Ces deux paramètres sont chacun définis par un tuple de deux valeurs pour les valeurs seuils CRIT et WARN. Toutes les valeurs seuils doivent être des pourcentages, utilisez donc Percentage
ici.
Si vous souhaitez donner aux utilisateurs du jeu de règles des valeurs au lieu de champs de saisie vides, vous pouvez le faire en ajoutant l'argument default_value
à la fonction percentage()
. Le tuple hosts_up_lower
de l'exemple qui vient d'être montré ressemble à ceci :
("hosts_up_lower",
Tuple(
title = _("Lower percentage threshold for host in UP status"),
elements = [
Percentage(title=_("Warning"), default_value=90.0),
Percentage(title=_("Critical"), default_value=80.0),
],
)
),
Notez que ces valeurs affichées dans l'interface graphique ne sont pas les valeurs par défaut définies plus bas via check_default_parameters
dans l'enregistrement du plugin de surveillance. Si vous souhaitez afficher les mêmes valeurs par défaut dans l'interface graphique qui s'appliquent également à la fonction de surveillance, vous devez veiller à ce que les valeurs soient cohérentes aux deux endroits.
Enfin, enregistrez le nouveau jeu de règles à l'aide des éléments importés et définis par vos soins. La fonction rulespec_registry.register()
est disponible à cet effet :
rulespec_registry.register(
CheckParameterRulespecWithItem(
check_group_name = "myhostgroups_advanced",
group = RulespecGroupCheckParametersApplications,
match_type = "dict",
item_spec = _item_valuespec_myhostgroups_advanced,
parameter_valuespec = _parameter_valuespec_myhostgroups_advanced,
title = lambda: _("Host group status"),
)
)
Les explications suivantes s'appliquent :
Si votre check n'utilise pas d'élément, la fonction interne sera
CheckParameterRulespecWithoutItem
... La ligneitem_spec
est alors omise.Le nom
check_group_name
du jeu de règles établit la connexion avec les plugins de check. Un plugin de check qui souhaite utiliser ce jeu de règles doit utiliser le même nom quecheck_ruleset_name
lors de son enregistrement. Le nom ne doit en aucun cas être identique à un jeu de règles existant, car cela l'écraserait. Pour éviter ce risque, il est préférable d'utiliser un préfixe dans le nom.Le
group
détermine l'endroit où le jeu de règles doit apparaître dans le Setup. Avec la valeur sélectionnée dans l'exemple, vous le trouverez sous Setup > Services > Service monitoring rules dans la première case Applications, Processes & Services.La plupart de ces groupes sont définis dans le fichier~/lib/check_mk/gui/plugins/wato/utils/__init__.py
. Vous y trouverez également des exemples de création de nouveaux groupes.Le
match_type
est toujours le"dict"
.Saisissez les noms des deux fonctions créées précédemment, à savoir
item_spec
etparameter_valuespec
.title
définit le titre du jeu de règles tel qu'il apparaît dans l'interface graphique de Checkmk. Cependant, le titre n'est pas spécifié directement en tant que texte, mais en tant que fonction exécutable qui renvoie le texte (d'oùlambda:
).
Test du jeu de règles
Une fois que vous avez créé le fichier du jeu de règles, vous devez tester si tout fonctionne jusqu'à présent - toujours sans connexion au plugin de check. Pour ce faire, vous devez d'abord redémarrer l'Apache de l'instance afin que le nouveau fichier soit lu. Cette opération s'effectue à l'aide de l'instruction :
OMD[mysite]:~$ omd restart apache
Le jeu de règles devrait ensuite être trouvé dans le site Setup sur la page mentionnée ci-dessus. Vous pouvez également trouver le jeu de règles en utilisant la fonction de recherche dans le menu de configuration - mais seulement après avoir redémarré Redis :
OMD[mysite]:~$ omd restart redis
Le jeu de règles que vous venez de définir ressemble à ceci dans l'interface graphique :
Dans la condition, vous trouverez le champ Host group name défini avec l'aide en ligne :
Checkmk a d'ailleurs inclus dans votre jeu de règles les textes relatifs à l'utilisation des expressions régulières.
Créez une règle et essayez différentes valeurs, comme le montre la capture d'écran ci-dessus. Si cela fonctionne sans erreur, vous pouvez maintenant utiliser les paramètres de contrôle dans la fonction de check.
Utilisation du jeu de règles dans un plugin de surveillance, check plugin
Pour que la règle prenne effet, vous devez autoriser le plugin de surveillance à accepter les paramètres de contrôle et lui indiquer quelle règle doit être utilisée. Pour ce faire, ajoutez deux nouvelles lignes à la fonction d'enregistrement :
register.check_plugin(
name = "myhostgroups_advanced",
sections = ["myhostgroups"],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
check_default_parameters = {},
check_ruleset_name = "myhostgroups_advanced",
)
Avec l'entrée check_default_parameters
, vous pouvez définir les valeurs par défaut qui s'appliquent tant qu'aucune règle n'a été créée. Cette ligne doit être présente lors de l'enregistrement. Dans le cas le plus simple, passez un dictionnaire vide {}
.
Deuxièmement, transmettez le nom check_ruleset_name
à la fonction d'enregistrement, c'est-à-dire le nom que vous avez attribué au jeu de règles ci-dessus à l'aide de check_group_name
. De cette façon, Checkmk sait à partir de quel jeu de règles les paramètres doivent être déterminés.
Checkmk va maintenant essayer de passer des paramètres à la fonction de check. Pour que cela fonctionne, vous devez étendre la fonction de check de manière à ce qu'elle attende l'argument params
, qui est inséré entre item
et section
:
def check_myhostgroups_advanced(item, params, section):
Si vous construisez un check sans élément, le item
est omis et le params
se trouve au début.
Il est fortement recommandé de produire le contenu de la variable params
avec print
comme premier test :
def check_myhostgroups_advanced(item, params, section):
print(params)
Lorsque le plugin de surveillance check sera exécuté, les deux lignes imprimées (une pour chaque service) ressembleront à ceci :
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced -v localhost
Parameters({'hosts_up_lower': (70.0, 60.0), 'services_ok_lower': (75.0, 65.0)})
Parameters({'hosts_up_lower': (70.0, 60.0), 'services_ok_lower': (75.0, 65.0)})
Parameters({'hosts_up_lower': (70.0, 60.0), 'services_ok_lower': (75.0, 65.0)})
Une fois que tout est prêt et fonctionne correctement, veillez à supprimer à nouveau les instructions |
Adaptez maintenant votre fonction de check pour que les paramètres transférés puissent prendre effet. Obtenez les deux tuples des paramètres avec le nom sélectionné dans la règle :
def check_myhostgroups_advanced(item, params, section):
hosts_up_lower = params["hosts_up_lower"]
services_ok_lower = params["services_ok_lower"]
Plus loin dans la fonction de check, les valeurs seuils précédemment codées en dur (90, 80)
sont alors remplacées par les variables hosts_up_lower
et services_ok_lower
:
hosts_up_perc = 100.0 * num_hosts_up / num_hosts
yield from check_levels(
hosts_up_perc,
levels_lower = (hosts_up_lower),
metric_name = "hosts_up_perc",
label="UP hosts",
boundaries = (0, 100),
notice_only = True,
)
services_ok_perc = 100.0 * num_services_ok / num_services
yield from check_levels(
services_ok_perc,
levels_lower = (services_ok_lower),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0, 100),
notice_only = True,
)
Si une règle a été configurée, vous pouvez maintenant surveiller les groupes d'hôtes de l'exemple avec les valeurs seuils qui ont été définies via l'interface graphique. Cependant, si aucune règle n'a été définie, cette fonction de check se plantera, car les paramètres par défaut du plugin de surveillance ne sont pas remplis et le plugin générera une adresse KeyError
en l'absence de règle.
Ce problème peut toutefois être résolu si les valeurs par défaut sont définies lors de l'enregistrement :
register.check_plugin(
name = "myhostgroups_advanced",
sections = ["myhostgroups"],
service_name = "Host group %s",
discovery_function = discover_myhostgroups_advanced,
check_function = check_myhostgroups_advanced,
check_default_parameters = {"hosts_up_lower": (90, 80), "services_ok_lower": (90, 80)},
check_ruleset_name = "myhostgroups_advanced",
)
Vous devriez toujours transférer les valeurs par défaut de cette manière (et ne pas intercepter la situation des paramètres manquants dans le plugin check), car ces valeurs par défaut peuvent également être affichées dans l'interface Setup. Par exemple, dans la reconnaissance du service pour un hôte, sur la page Services of host, dans le menu Display, il y a l'entrée Show check parameters..
Sur GitHub, vous trouverez à la fois le fichier contenant lejeu de règleset leplugin de surveillance, check, amélioré par le jeu de règles. |
Utilisation d'un jeu de règles existant
Il est peu probable, mais pas impossible, qu'un jeu de règles livré avec Checkmk corresponde à votre fonction de contrôle. Cela ne peut en fait être le cas que si votre contrôle évalue quelque chose pour lequel Checkmk dispose déjà de plugins de contrôle sous le même formulaire, par exemple la surveillance d'une température ou d'autres valeurs mesurées par des capteurs. Cependant, si un tel jeu de règles correspond à votre plugin de contrôle, vous pouvez alors vous épargner la création de votre propre jeu de règles.
Les jeux de règles existants pour les paramètres de contrôle fournis avec Checkmk se trouvent dans le répertoire ~/lib/check_mk/gui/plugins/wato/check_parameters/
.
Prenez par exemple le fichier memory_simple.py
, qui déclare un jeu de règles avec la section suivante :
rulespec_registry.register(
CheckParameterRulespecWithItem(
check_group_name = "memory_simple",
group = RulespecGroupCheckParametersOperatingSystem,
item_spec = _item_spec_memory_simple,
match_type = "dict",
parameter_valuespec = _parameter_valuespec_memory_simple,
title = lambda: _("Main memory usage of simple devices"),
)
)
Comme pour le jeu de règles auto-écrit, le mot-clé check_group_name
, qui est ici défini à "memory_simple"
, est décisif. Il établit la connexion avec le plugin de surveillance. Vous le faites en enregistrant le plugin de surveillance avec le mot-clé check_ruleset_name
, par exemple comme ceci :
register.check_plugin(
name = "foobar",
service_name = "Foobar %s",
discovery_function = discover_foobar,
check_function = check_foobar,
check_ruleset_name = "memory_simple",
check_default_parameters = {},
)
Ici aussi, il est nécessaire de définir des valeurs par défaut à l'aide du mot-clé check_default_parameters
.
5. Personnalisation de l'affichage des métriques
Dans l'exemple ci-dessus, vous avez laissé le plugin de surveillance check myhostgroups_advanced
générer des métriques pour toutes les valeurs mesurées et calculées. Nous avons présenté deux façons d'y parvenir. Premièrement, les métriques des valeurs calculées ont été créées dans le cadre de la fonction check_levels()
avec l'argument metric_name
, par exemple de la manière suivante :
yield from check_levels(
services_ok_perc,
levels_lower = (services_ok_lower),
metric_name = "services_ok_perc",
label = "OK services",
boundaries = (0.0, 100.0),
notice_only = True,
)
Ensuite, nous avons généré les métriques mesurées directement avec l'objet Metric()
- pour le nombre de services dans l'état OK, par exemple, comme ceci : ~/local/lib/check_mk/base/plugins/agent_based/myhostgroups.py :
yield Metric(name="num_services_ok", value=num_services_ok)
Les métriques seront immédiatement visibles dans l'interface utilisateur graphique de Checkmk sans que vous ayez à faire quoi que ce soit. Il y a cependant quelques restrictions :
Les métriques saisies ne sont pas automatiquement combinées dans un graphique, au lieu de cela, chacune apparaît individuellement.
La métrique n'a pas de titre propre, mais affiche le nom de la variable interne de la métrique.
Aucune unité permettant une représentation significative n'est utilisée (par exemple, GB au lieu d'octets individuels).
Une couleur est choisie au hasard.
Un "Perf-O-Meter", c'est-à-dire l'aperçu graphique de la métrique sous la forme d'une barre, n'apparaît pas automatiquement dans la liste des services (par exemple, dans la vue qui affiche tous les services d'un hôte).
Pour compléter l'affichage de vos métriques dans ces aspects, vous aurez besoin de définitions de métriques.
Les exemples présentés dans ce chapitre ne sont pas couverts par l'API Check. |
5.1. Utilisation de définitions de métriques existantes
Avant de créer une nouvelle définition de métrique, vous devez d'abord vérifier si Checkmk ne dispose pas déjà d'une définition appropriée. Les définitions de métriques prédéfinies se trouvent dans le répertoire ~/lib/check_mk/gui/plugins/metrics/
.
Pour l'utilisation du processeur, par exemple, vous trouverez la métrique portant le nom util
dans le fichier cpu.py
:
metric_info["util"] = {
"title": _l("CPU utilization"),
"unit": "%",
"color": "26/a",
}
Si votre plugin de contrôle mesure l'utilisation du processeur en pourcentage, vous pouvez utiliser cette définition de métrique sans problème. Il vous suffit de saisir "util"
comme nom de la métrique dans votre fonction de contrôle. Tout le reste sera alors automatiquement dérivé de cette définition.
5.2. Création d'une nouvelle définition de métrique
S'il n'existe pas de définition de métrique appropriée, il vous suffit d'en créer une vous-même.
Pour notre exemple, définissez votre propre métrique pour le nombre de services dans l'état OK. Pour ce faire, créez un fichier dans ~/local/share/check_mk/web/plugins/metrics
:
from cmk.gui.i18n import _
from cmk.gui.plugins.metrics import metric_info
metric_info["num_services_ok"] = {
"title": _("Services in OK status"),
"unit": "count",
"color": "15/a",
}
Voici l'explication :
L'importation et l'utilisation du trait de soulignement (
_
) pour l'internationalisation sont facultatives, comme nous l'avons déjà vu lors de la création des jeux de règles.La clé (ici
"num_services_ok"
) est le nom de la métrique et doit correspondre à ce que la fonction check produit. Choisissez un nom unique afin qu'aucune métrique existante ne soit "écrasée".Le
title
est l'en-tête du graphique métrique et remplace le nom de la variable interne utilisé précédemment.Vous pouvez connaître les définitions disponibles pour les unités (
unit
) dans le fichier~/lib/check_mk/gui/plugins/metrics/unit.py
.La définition de la couleur
color
utilise une palette. Chaque couleur de la palette comporte/a
et/b
. Il s'agit de deux nuances de la même couleur. Dans les définitions métriques existantes, vous trouverez également de nombreux codes de couleur directs tels que"#ff8800"
. Ceux-ci seront progressivement supprimés et remplacés par des couleurs de la palette, car ils offrent un aspect plus uniforme et peuvent également être plus facilement adaptés aux thèmes de couleur de l'interface graphique.
Cette définition dans le fichier métrique garantit désormais que le titre, l'unité et la couleur de la métrique sont affichés de manière appropriée.
Comme pour la création d'un jeu de règles, le fichier de métriques doit d'abord être lu avant que la modification ne soit visible dans l'interface graphique, ce qui se fait en redémarrant l'Apache de l'instance :
OMD[mysite]:~$ omd restart apache
Le graphique des métriques se présente alors comme suit dans l'interface graphique de Checkmk :
5.3. Graphiques avec plusieurs métriques
Si vous souhaitez combiner plusieurs métriques en un seul graphique (ce qui est souvent très utile), vous aurez besoin d'une définition de graphique que vous pourrez ajouter au fichier de métriques créé dans la section précédente. Cela se fait via le dictionnaire global graph_info
.
Dans notre exemple, les deux métriques num_services_ok
et num_services
doivent être affichées dans le même graphique. Les définitions des métriques sont les suivantes :
from cmk.gui.i18n import _
from cmk.gui.plugins.metrics import (
metric_info,
graph_info,
)
metric_info["num_services_ok"] = {
"title": _("Services in OK status"),
"unit": "count",
"color": "15/a",
}
metric_info["num_services"] = {
"title": _("Number of services"),
"unit": "count",
"color": "24/a",
}
Ajoutez maintenant un graphique qui montre ces deux métriques sous forme de lignes :
graph_info["num_services_combined"] = {
"metrics": [
("num_services_ok", "line"),
("num_services", "line"),
],
}
La première entrée sous metrics
détermine quelle métrique est utilisée pour le titre du graphique. Le résultat est le graphique combiné dans l'interface graphique de Checkmk :
5.4. Métriques dans le Perf-O-Meter
Vous souhaitez afficher un Perf-O-Mètre pour une métrique dans la ligne de la liste des services ? Cela pourrait ressembler à ceci, par exemple :
Pour créer un tel Perf-O-Mètre, vous avez besoin d'un autre fichier, cette fois dans le répertoire ~/local/share/check_mk/web/plugins/perfometer
:
from cmk.gui.plugins.metrics import perfometer_info
perfometer_info.append(
{
"type": "logarithmic",
"metric": "num_services_ok",
"half_value": 25,
"exponent": 2.0,
}
)
Les Perf-O-Mètres sont un peu plus délicats que les graphiques, car ils n'ont pas de légende, ce qui rend difficile l'affichage des plages de valeurs. Comme le Perf-O-Mètre ne peut pas savoir quelles sont les valeurs possibles et que l'espace est très limité, de nombreux plugins de check intégrés utilisent une représentation logarithmique. C'est également le cas dans l'exemple ci-dessus :
type
sélectionne le format d'affichage des valeurs, dans ce cas la représentation logarithmique.metric
indique le nom de la métrique, dans ce cas le nombre de services dans l'état OK.half_value
est la valeur mesurée qui est affichée exactement au milieu du Perf-O-Mètre. Pour une valeur de25
, la barre est donc à moitié pleine.exponent
spécifie le facteur nécessaire pour remplir 10 % supplémentaires de la plage. Ainsi, dans l'exemple, une valeur mesurée de50
remplirait la barre jusqu'à 60 %, et une valeur de100
jusqu'à 70 %.
L'avantage de cette méthode : si vous équipez une liste de services du même type avec des Perf-O-Mètres similaires, vous pouvez rapidement comparer visuellement les Perf-O-Mètres entre eux, car ils utilisent tous la même échelle. Et malgré le petit format d'affichage, vous pouvez facilement reconnaître les différences dans les valeurs très petites et très grandes. Les valeurs dans un tel affichage ne sont cependant pas fidèles à leur échelle réelle.
Le Perf-O-Meter ci-dessus affiche une métrique, mais pas celle qui est responsable du statut du service. Ce n'est pas le nombre de services dans l'état OK, mais leur pourcentage qui détermine le statut du service du groupe d'hôtes affiché.
Pour afficher la métrique du pourcentage (services_ok_perc
), vous pouvez utiliser un Perf-O-Mètre linéaire. C'est toujours utile s'il y a une valeur maximale connue. Par exemple, cela ressemblerait à ceci dans le fichier :
perfometer_info.append(
{
"type": "linear",
"segments": ["services_ok_perc"],
"total": 100.0,
}
)
Et ainsi dans l'interface graphique :
C'est déjà une amélioration. Cependant, l'état du service n'est pas seulement déterminé par le pourcentage de services dans l'état OK, mais aussi par le pourcentage d'hôtes dans l'état UP. Il y a plusieurs méthodes pour combiner plusieurs métriques dans un Perf-O-Mètre. Une méthode ressemble à ceci :
perfometer_info.append(
{
"type": "dual",
"perfometers": [
{
"type": "linear",
"segments": ["hosts_up_perc"],
"total": 100.0,
},
{
"type": "linear",
"segments": ["services_ok_perc"],
"total": 100.0,
},
],
}
)
Cela permet de s'assurer que les deux métriques partagent la même barre dans le Perf-O-Mètre et sont affichées l'une à côté de l'autre :
Vous trouverez de nombreux exemples sur ce thème dans les plugins de surveillance fournis par Checkmk - dans le fichier ~/lib/check_mk/gui/plugins/metrics/perfometers.py
.
6. Formatage des nombres
Les nombres sont souvent affichés dans les pages Summary et Details d'un service. Afin de vous faciliter la tâche et d'uniformiser la sortie de tous les plugins de check, il existe des fonctions auxiliaires pour l'affichage des différents types de taille. Toutes ces fonctions sont des sous-fonctions du module render
et sont donc appelées avec render.
. Par exemple, render.bytes(2000)
produit le texte 1.95 KiB
.
Toutes ces fonctions ont en commun le fait que leur valeur est indiquée dans une unité dite canonique ou naturelle. Cela signifie que vous ne devez jamais réfléchir et qu'il n'y a pas de difficultés ou d'erreurs lors de la conversion. Par exemple, les temps sont toujours indiqués en secondes et les tailles des disques durs, des fichiers, etc. sont toujours indiquées en octets et non en kilo-octets, kibo-octets, blocs ou autres confusions de ce genre.
Utilisez ces fonctions même si vous n'aimez pas trop l'affichage, qui sera de toute façon standardisé pour l'utilisateur. Les versions futures de Checkmk pourront peut-être modifier l'affichage, voire le rendre configurable par l'utilisateur, comme c'est déjà le cas pour l'affichage de la température, par exemple. Votre plugin de surveillance, check plugin, en bénéficiera alors également.
Avant de pouvoir utiliser la fonction render
dans votre plugin de surveillance, vous devez également l'importer :
from .agent_based_api.v1 import check_levels, Metric, register, render, Result, Service, State
Après cette description détaillée de toutes les fonctions d'affichage (fonctions de rendu), vous trouverez un résumé sous la forme d'un tableau facile à lire.
6.1. Temps, périodes, fréquences
Les spécifications de temps absolu (timestamps) sont formatées avec render.date()
ou render.datetime()
. L'information est toujours donnée en heure Unix, c'est-à-dire en secondes à partir du 1er janvier 1970, 00:00:00 UTC - le début de l'époque Unix. C'est également le format utilisé par la fonction Python time.time()
.
L'avantage de cette représentation est qu'elle est très facile à calculer, par exemple le calcul d'une période, lorsque les heures de début et de fin sont connues. La formule est alors simplement duration = end - start
. Ces calculs fonctionnent quel que soit le fuseau horaire, les changements d'heure d'été ou les années bissextiles.
render.date()
ne donne que la date, render.datetime()
ajoute l'heure. La sortie se fait en fonction du fuseau horaire dans lequel se trouve le serveur Checkmk qui exécute le check. Exemples :
Appel | Sortie |
---|---|
|
|
|
|
|
|
|
|
Ne soyez pas surpris que render.datetime(0)
n'affiche pas l'heure de 00:00
, mais celle de 01:00
, car nous écrivons ce guide utilisateur dans le fuseau horaire de l'Allemagne, qui est en avance d'une heure sur l'heure UTC standard (du moins pendant l'heure standard, car le 1er janvier ne correspond pas à l'heure d'été).
Pour les périodes de temps (ou intervalles de temps), il existe également la fonction render.timespan()
. Cette fonction reçoit une durée en secondes et la restitue sous un formulaire lisible par l'homme. Pour les intervalles de temps plus importants, les secondes ou les minutes sont omises. Si vous avez un intervalle de temps dans un objet TimeDelta
, utilisez la fonction total_seconds()
pour lire le nombre de secondes sous la forme d'un nombre à virgule flottante.
Appeler | Sortie |
---|---|
|
|
|
|
|
|
|
|
Une fréquence est en fait la réciproque du temps. L'unité canonique est le Hz, qui signifie la même chose que 1 / sec (la réciproque d'une seconde). Un exemple de son utilisation est la fréquence d'horloge d'une unité centrale :
Appel | Sortie |
---|---|
|
|
6.2. Octets
En ce qui concerne la mémoire vive, les fichiers, les disques durs, les systèmes de fichiers et autres, l'unité canonique est l'octet. Étant donné que les ordinateurs organisent généralement ces choses en puissances de deux, par exemple en unités de 512, 1024 ou 65 536 octets, il a été établi dès le début qu'un kilo-octet n'est pas 1000, et donc mille fois l'unité, mais 1024 (2 à la puissance de 10) octets. Le légendaire Commodore 64 avait 64 kilo-octets de mémoire et non 65.536.
Malheureusement, à un moment donné, les fabricants de disques durs ont eu l'idée de spécifier la taille de leurs disques en unités de 1000. Comme la différence entre 1000 et 1024 est de 2,4 % pour chaque taille, et que ces chiffres sont multipliés, un disque d'une taille de 1 Go (1024 fois 1024 fois 1024) devient soudain 1,07 Go. Cela se vend mieux.
Cette fâcheuse confusion existe encore aujourd'hui et continue de produire des erreurs. Pour y remédier, la Commission électrotechnique internationale (CEI) a défini de nouveaux préfixes basés sur le système binaire. Ainsi, aujourd'hui, un kilooctet est officiellement 1000 octets et un kibibyte est 1024 octets (2 à la puissance 10). En outre, on devrait dire Mebibyte, Gibibyte et Tebibyte. Les abréviations sont donc KiB, MiB, GiB et TiB.
Checkmk se conforme à cette norme et vous aide grâce à un certain nombre de fonctions de rendu personnalisées afin de vous assurer que vous produisez toujours le résultat correct. Par exemple, il existe la fonction render.disksize()
spécialement conçue pour les disques durs et les systèmes de fichiers, qui produit son résultat en puissances de 1000.
Appel | Sortie |
---|---|
|
|
|
|
|
|
Lorsqu'il s'agit de la taille des fichiers, il est souvent d'usage de spécifier la taille exacte en octets sans arrondir. Cela présente l'avantage de vous permettre de voir très rapidement si un fichier a été modifié, même de façon minime, ou si deux fichiers sont (probablement) identiques. La fonction render.filesize()
est utilisée à cet effet :
Appel | Sortie |
---|---|
|
|
|
|
|
|
Si vous souhaitez obtenir une valeur qui n'est pas la taille d'un disque dur ou d'un fichier, il vous suffit d'utiliser la fonction générique render.bytes()
. Vous obtiendrez ainsi la sortie dans les 1024 puissances "classiques" de la notation officielle :
Appel | Sortie |
---|---|
|
|
|
|
|
|
6.3. Largeurs de bande, débits de données
Les utilisateurs de réseaux ont leurs propres termes et façons d'exprimer les choses. Et comme toujours, Checkmk s'efforce d'adopter la façon conventionnelle de communiquer dans chaque domaine. C'est pourquoi il existe trois fonctions de rendu différentes pour les débits de données et les vitesses. Ce qu'elles ont toutes en commun, c'est que les débits sont transmis en octets par seconde, même si la sortie réelle est en bits !
render.nicspeed()
représente la vitesse maximale d'une carte réseau ou d'un port du switch. Comme il ne s'agit pas de valeurs mesurées, il n'est pas nécessaire d'arrondir. Bien qu'aucun port ne puisse envoyer des bits individuels, les données sont exprimées en bits pour des raisons historiques.
Important : vous devez toutefois également indiquer ici les octets par seconde !
Appeler | Sortie |
---|---|
|
|
|
|
render.networkbandwidth()
est destiné à une vitesse de transmission réellement mesurée dans le réseau. La valeur d'entrée est à nouveau en octets par seconde :
Call | Sortie |
---|---|
|
|
|
|
|
|
Lorsqu'il ne s'agit pas d'un réseau et que des débits de données sont encore fournis, les octets sont de nouveau utilisés. Le cas le plus fréquent est celui des débits d'E/S des disques durs. La fonction render.iobandwidth()
, qui travaille avec des puissances de 1000 dans Checkmk, est utilisée à cet effet :
Appel | Sortie |
---|---|
|
|
|
|
|
|
6.4. Pourcentages
La fonction render.percent()
représente un pourcentage - arrondi à deux décimales. Elle constitue une exception par rapport aux autres fonctions en ce sens qu'elle ne transmet pas la valeur naturelle réelle - c'est-à-dire le rapport - mais le pourcentage réel. Par exemple, si un objet est à moitié plein, vous ne devez pas transmettre 0.5
mais 50
.
Comme il peut parfois être intéressant de savoir si une valeur est presque nulle ou exactement nulle, les valeurs sont marquées par l'ajout d'un caractère "<" pour les valeurs supérieures à zéro mais inférieures à 0,01 %.
Appeler | Sortie |
---|---|
|
|
|
|
|
|
6.5. Résumé
En conclusion, voici un aperçu de toutes les fonctions de rendu :
Fonction | Entrée | Description de la fonction | Exemple de sortie |
---|---|---|---|
|
Heure Unix |
Date |
|
|
Heure Unix |
Date et heure |
|
|
Secondes |
Durée / âge |
|
|
Hz |
Fréquence (par exemple, fréquence d'horloge) |
|
|
Octets |
Taille d'un disque dur, base 1000 |
|
|
Octets |
Taille d'un fichier, précision totale |
|
|
Octets |
Taille, base 1024 |
|
|
Octets par seconde |
Vitesse de la carte réseau |
|
|
Octets par seconde |
Vitesse de transmission |
|
|
Octets par seconde |
Largeurs de bande IO |
|
|
Nombre en pourcentage |
Pourcentage, arrondi de manière significative |
|
7. Résolution des problèmes
La gestion correcte des erreurs occupe (malheureusement) une grande partie du travail de programmation. La bonne nouvelle est que l'API Check prend déjà en charge une grande partie du travail de gestion des erreurs. Pour certains types d'erreurs, il est donc préférable de ne pas les gérer vous-même.
Si Python rencontre une situation inattendue, il réagit par une exception. Voici quelques exemples :
Vous convertissez une chaîne en nombre avec
int()
, mais la chaîne ne contient pas de nombre, par exempleint("foo")
.Vous utilisez
bar[4]
pour accéder au cinquième élément debar
, mais ce dernier ne comporte que quatre éléments.Vous appelez une fonction qui n'existe pas.
Pour décider de la manière de traiter les erreurs, il est tout d'abord important de connaître le point exact du code où une erreur se produit. Vous pouvez utiliser l'interface graphique ou la ligne d'instruction pour ce faire - en fonction de l'endroit où vous travaillez actuellement.
7.1. Exceptions et rapports de plantage dans l'interface graphique
Si une exception se produit lors de la surveillance ou de l'identification d'un service sur le site Setup, le site Summary contient des références au rapport de plantage qui vient d'être créé. Il se présente par exemple comme suit :
En cliquant sur l'icône, vous affichez une page de détails dans laquelle vous :
pouvez voir le fichier dans lequel le plantage s'est produit,
recevoir toutes les informations relatives au plantage, telles que la liste des erreurs survenues dans le programme(traceback), les valeurs actuelles des variables locales, la sortie de l'agent et bien d'autres choses encore, et
peut nous envoyer le rapport (Checkmk GmbH) en guise de retour d'information.
La trace d'appels vous aide, en tant que développeur, à déterminer s'il s'agit d'une erreur dans le programme (par exemple, l'appel d'une fonction inexistante) ou de données de l'agent qui n'ont pas pu être traitées comme prévu. Dans le premier cas, vous voudrez corriger l'erreur, dans le second cas, il est souvent judicieux de ne rien faire.
L'envoi du rapport n'est bien sûr utile que pour les plugins de surveillance qui font officiellement partie de Checkmk. Si vous mettez vos propres plugins à la disposition de tiers, vous pouvez demander à vos utilisateurs de vous envoyer les données.
7.2. Vue de tables d'exceptions sur la ligne d'instruction
Si vous exécutez votre plugin de surveillance à l'aide de la ligne d'instruction, vous ne recevrez aucune indication sur l'ID des rapports de plantage générés. Vous ne verrez que le message d'erreur résumé :
OMD[mysite]:~$ cmk --detect-plugins=myhostgroups_advanced localhost
Error in agent based plugin myhostgroups: invalid syntax (myhostgroups.py, line 11)
Si vous ajoutez l'option --debug
en tant que paramètre d'appel supplémentaire, vous recevrez la trace d'appels de l'interpréteur Python :
OMD[mysite]:~$ cmk --debug --detect-plugins=myhostgroups_advanced localhost
Traceback (most recent call last):
File "/omd/sites/mysite/bin/cmk", line 97, in <module>
errors = config.load_all_agent_based_plugins(
^^^^^^^^^^^^
File "/omd/sites/mysite/lib/python3/cmk/base/config.py", line 1673, in load_all_agent_based_plugins
errors = agent_based_register.load_all_plugins()
^^^^^^^^^^^^^
File "/omd/sites/mysite/lib/python3/cmk/base/api/agent_based/register/init.py", line 48, in load_all_plugins
raise exception
File "/omd/sites/mysite/lib/python3/cmk/utils/plugin_loader.py", line 49, in load_plugins_with_exceptions
importlib.import_module(full_name)
File "/omd/sites/mysite/lib/python3.11/importlib/init.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1206, in _gcd_import
File "<frozen importlib._bootstrap>", line 1178, in _find_and_load
File "<frozen importlib._bootstrap>", line 1149, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 936, in exec_module
File "<frozen importlib._bootstrap_external>", line 1074, in get_code
File "<frozen importlib._bootstrap_external>", line 1004, in source_to_code
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/omd/sites/mysite/local/lib/python3/cmk/base/plugins/agent_based/myhostgroups.py", line 11
parsed =
^
SyntaxError: invalid syntax
Si l'erreur ne se reproduit pas lors du prochain appel à --debug
, par exemple parce qu'une nouvelle sortie d'agent est disponible, vous pouvez également voir les derniers rapports de plantage dans le système de fichiers :
OMD[mysite]:~$ ls -lhtr ~/var/check_mk/crashes/check/ | tail -n 5
drwx------ 1 mysite mysite 44 Sep 3 05:15 f47550fc-4a18-11ee-a46c-001617122312/
drwx------ 1 mysite mysite 44 Sep 3 05:17 38657652-4a19-11ee-a46c-001617122312/
drwx------ 1 mysite mysite 44 Sep 3 09:31 9e716690-4a3c-11ee-9eaf-001617122312/
drwx------ 1 mysite mysite 44 Sep 3 10:40 479b20ea-4a46-11ee-9eaf-001617122312/
drwx------ 1 mysite mysite 44 Sep 4 14:11 fdec3ef6-4b2c-11ee-9eaf-001617122312/
Il y a deux fichiers dans chacun de ces dossiers :
crash.info
contient un dictionnaire Python avec des traces d'appels et beaucoup plus d'informations. Un coup d'œil au fichier avec le Pager est souvent suffisant.agent_output
contient la sortie complète de l'agent qui était en cours au moment du plantage.
7.3. Sortie de débogage personnalisée
Dans les exemples ci-dessus, nous utilisons la fonction print()
pour afficher le contenu des variables ou la structure des objets pour vous en tant que développeur. Ces fonctions de sortie de débogage doivent être supprimées du plugin check fini.
Au lieu de les supprimer, vous pouvez également faire en sorte que la sortie de débogage ne s'affiche que lorsque le plugin de check est appelé depuis la console en mode débogage. Pour ce faire, importez l'objet de débogage de la boîte à outils Checkmk et, si nécessaire, l'aide au formatage pprint()
. Vous pouvez maintenant produire une sortie de débogage en fonction de la valeur de l'objet de débogage :
from cmk.utils import debug
from pprint import pprint
def check_mystuff(section):
if debug.enabled():
pprint(section)
Notez que toute sortie de débogage restante doit être utilisée avec parcimonie et limitée à des indices qui aideront les utilisateurs suivants à déboguer. Les erreurs évidentes et prévisibles de l'utilisateur (par exemple, que le contenu de la section de l'agent indique que le plugin de l'agent a été mal configuré) doivent être répondues avec l'état UNKNOWN et inclure des notes explicatives dans le résumé.
7.4. Sortie non valide de l'agent
La question est de savoir comment réagir si la sortie de l'agent n'est pas dans le formulaire que vous attendez, qu'elle provienne de l'agent Checkmk ou qu'elle soit reçue via SNMP. Supposons que vous attendiez toujours trois mots par ligne, que faire si vous n'en obtenez que deux ?
S'il s'agit d'un comportement autorisé et connu de l'agent, vous devez bien sûr l'intercepter et travailler avec une distinction de cas. Toutefois, si ce comportement n'est pas autorisé, il est préférable de faire comme si la ligne était toujours composée de trois mots, par exemple avec la fonction d'analyse suivante :
def parse_foobar(string_table):
for foo, bar, baz in string_table:
# ...
Si une ligne ne comporte pas exactement trois mots, une exception est générée et vous recevez le rapport de plantage très utile que nous venons de mentionner.
Si vous accédez à des clés d'un dictionnaire dont on s'attend à ce qu'elles manquent occasionnellement, il peut être judicieux de réagir en conséquence. Pour ce faire, vous pouvez définir le service sur CRIT ou UNKNOWN et placer une note dans le résumé concernant la sortie de l'agent qui ne peut pas être évaluée. Dans tous les cas, il est préférable d'utiliser la fonction get()
du dictionnaire plutôt que d'attraper l'exception KeyError
. En effet, get()
renvoie un objet de type None
ou un remplacement facultatif à passer comme second paramètre si la clé n'est pas disponible :
def check_foobar(section):
foo = section.get("bar")
if not foo:
yield Result(state=State.CRIT, summary="Missing key in section: bar")
return
# ...
7.5. Éléments manquants
Que se passe-t-il si l'agent produit des données correctes, mais que l'élément à vérifier est manquant ? Comme ceci, par exemple :
def check_foobar(item, section):
# Try to access the item as key in the section:
foo = section.get(item)
if foo:
yield Result(state=State.OK, summary="Item found in monitoring data")
# If foo is None, nothing is yielded here
Si l'élément que vous recherchez n'est pas inclus, la boucle est parcourue et Python abandonne simplement à la fin de la fonction sans renvoyer de résultat via yield
. Et c'est exactement la bonne approche ! Parce que Checkmk reconnaît que l'élément à surveiller est manquant et génère le statut correct et un texte standard approprié avec UNKNOWN.
7.6. Test avec des fichiers spool
Si vous souhaitez simuler des sorties d'agent particulières, les fichiers spool sont très utiles. Vous pouvez les utiliser pour tester des cas limites qui sont autrement difficiles à recréer. Ou vous pouvez utiliser directement la sortie d'agent qui a conduit à un rapport de plantage pour modifier un plugin de check.
Désactivez d'abord votre plugin d'agent normal, par exemple en révoquant son autorisation d'exécution. Créez ensuite un fichier dans le répertoire /var/lib/check_mk_agent/spool/
qui contient la section d'agent (ou les sections d'agent attendues) que votre plugin de check attend, y compris l'en-tête de section, et qui se termine par Newline. La prochaine fois que l'agent est appelé, le contenu du fichier spool sera transféré à la place de la sortie du plugin d'agent.
7.7. Les anciens plugins de surveillance, check plugin, deviennent lents pour de nombreux services
Avec certains plugins de contrôle qui utilisent des éléments, il est tout à fait possible que, sur les grands serveurs, plusieurs centaines de services soient générés. Si aucune fonction d'analyse distincte n'est utilisée, cela signifie que la liste entière de centaines de lignes doit être parcourue pour chacun des centaines d'éléments. Le temps nécessaire à la recherche augmente donc au carré du nombre d'éléments listés, ce qui signifie des dizaines de milliers de comparaisons pour des centaines de services. Si, en revanche, la liste imbriquée est transférée dans un dictionnaire, le temps nécessaire à la recherche d'un élément n'augmente que de façon linéaire avec la taille du dictionnaire.
Dans le wiki Python, vous trouverez un aperçu des coûts de recherche dans différents types de données, y compris une explication et la notation O.L'utilisation de la fonction parse réduit la complexité de la recherche de O(n) à O(1).
Comme les anciennes versions de cet article n'utilisaient pas la fonction parse, vous devez identifier ces plugins de surveillance check et les réécrire pour utiliser une fonction parse.
8. Fichiers et répertoires
Chemin d'accès au fichier | Fonction |
---|---|
|
Emplacement de stockage pour les plugins de surveillance, de surveillance, de check plugin rédigés par vos soins. |
|
Emplacement de stockage de vos jeux de règles pour les paramètres de contrôle. |
|
Emplacement de stockage pour vos propres définitions de métriques. |
|
Emplacement de stockage pour vos propres définitions de Perf-O-Meters. |
|
Vous trouverez ici les définitions des jeux de règles de tous les plugins de surveillance fournis par Checkmk. |
|
Ce fichier définit les groupes de l'interface Setup dans lesquels vous pouvez stocker de nouveaux jeux de règles. |
|
Vous trouverez ici les définitions des métriques des plugins fournis. |
|
Ce fichier contient les unités prédéfinies pour les métriques. |
|
Ce répertoire fait référence à un hôte Linux surveillé. L'agent Checkmk pour Linux attend ici les extensions de l'agent (plugins d'agent). |