CheckMK

De Justine's wiki
Aller à la navigation Aller à la recherche

Cette page contient diverses astuces pour l'outil de supervision qu'est Check_MK

Lire / vider les logwatch

Pour cela, il suffit d'accéder à l'interface de logwatch via https://adressedu/site/logwatch.py

Tester un agent

A faire depuis le serveur.

<syntaxhighlight lang='bash'> OMD[mysite]:~$ telnet 10.1.1.2 6556 Trying 10.1.1.2... Connected to 10.1.1.2. Escape character is '^]'. <<<check_mk>>> Version: 1.2.7i1 AgentOS: linux AgentDirectory: /etc/check_mk DataDirectory: /var/lib/check_mk_agent SpoolDirectory: /var/lib/check_mk_agent/spool PluginsDirectory: /usr/lib/check_mk_agent/plugins </syntaxhighlight>

Installer un agent avec systemd (à tester)

<source lang="bash">

  1. How to install Check MK Agent on ubuntu 16.04
  1. Install check_mk_agent:
  2. - sudo apt-get install check-mk-agent (will install older version)
  3. - On your Check_MK dashboard, go to "Monitoring Agents", click the link for "Check_MK Agent for Linux", save the raw text
  4. on your server:

sudo vi /usr/bin/check_mk_agent

  1. paste Check_MK dashboard > Monitoring Agents > Check_MK Agent for Linux

sudo chmod +x /usr/bin/check_mk_agent

  1. Setup Systemd

sudo vi /etc/systemd/system/check_mk.socket

  1. paste Check_MK dashboard > Monitoring Agents > systemd SOCKET definition file

sudo vi /etc/systemd/system/check_mk@.service

  1. paste Check_MK dashboard > Monitoring Agents > systemd SERVICE definition file
  1. start

sudo systemctl daemon-reload sudo systemctl enable check_mk.socket sudo systemctl start check_mk.socket

  1. Add firewall rule from specific OMD Server IP

sudo ufw allow from 15.15.15.0/24 to any port 6556

  1. test on another host

nc -v <ip address> 6556 </source>

Ecriture d'un plugin SNMP

https://docs.checkmk.com/master/en/devel_check_plugins.html#snmp https://docs.checkmk.com/master/en/snmp.html http://www.pawelko.net/?s=check_mk

Un mot sur le terme plugin

Jusque ici, j'ai beaucoup utilisé des sondes : un script posé sur la cible et qui est exécuté au lancement de l'agent, formatte des infos et les renvoie. Ce sont ce que j'appelle des sondes. Les plugins fonctionnent autrement. Dans le cas où je passe par un agent:

  • Je créée sur la machine supervisée, dans /usr/lib/check_mk_agent/plugins, un fichier au nom quelconque et qui contiendra les valeurs suivantes:

<source> <<<NomDuService>>> Commande renvoyant les infos brutes

  1. Par exemple:

<<<uptime>>> uptime -p </source> Ainsi, l'agent verra un plugin, et rajoutera dans sa sorte une section NomDuService, laquelle contiendra de l'information.

  • Sur mon serveur CMK, je vais créer un plugin en python décrivant comment ce plugin est utilisé. Il décrit la façon dont les données renvoyées doivent être interprétées (gravité...).

Préambule

Traditionnellement, CMK procède de la façon suivante : la cible (machine supervisée) possède un agent. Le serveur de supervision va interroger cette cible qui renvoie alors ces informations. Les informations sont récupérées grâce à des commandes shell et mise en forme dans un long str qui est renvoyé au serveur. Dans le cas de SNMP, c'est différent. On ne passe par cet agent : le serveur CMK va utiliser des scripts qu'il possède afin de savoir comment interroger la cible via SNMP.

Les bases de SNMP

SNMP

Il faut configurer le serveur en question pour qu'il accepte les requêtes SNMP. On peut utiliser n'importe quelle version et community.

Ensuite, on créée le serveur dans CMK, on donne les paramètres SNMP, on fait un diag pour voir si ça fonctionne. Simple.

Étapes de préparation

Principe

La détection de service se fait en deux phases. D'abord, D'abord, une détection SNMP a lieu, afin de déterminer quels plugins sont utilisables sur la machine en question. Pour ça, on scanne quelques OIDs, le plus important étant sysdescr : 1.3.6.1.2.1.1.0. Cet OID donne toujours une description de l'appareil, par exemple "Cisco NX-OS(tm) n5000". Rien qu'en se basant sur cet OID, on peut déterminer si un plugin sera utile; si ça ne suffit pas, on peut ajouter d'autres OID à la détection SNMP.

Ensuite, la découverte des des données de supervision proprement dites a lieu (c'est la détection de services, comme avec un agent quand je vais découvrir les services que celui-ci me renvoie). Elles sont ensuite combinées dans une table et fournies à la fonction de discovery du check dans l'argument "section", qui comme d'habitude détermine les items à surveiller.

Enfin, les checks ont lieu. On sait alors déjà quels plugins sont utilisés puisqu'on a fait nos découvertes. Ici les données sont récupérées par un walk SNMP et à partir de ça l'argument "section" peut être renseigné.

En résumé, on a pas besoin d'un agent, mais:

  • d'OIDs individuels et de texte à y chercher pour la détection SNMP (est-ce que mon plugin s'applique ici ?)
  • de zones SNMP sur lesquelles faire des walks afin de récupérer les infos.

Les plugins SNMP sont considérés comme des plugins,

Un mot sur les MIBs

Alors, les MIBs, CMK peut fonctionner sans. Il a son propre set de MiBs par défaut, qui décrivent des zones générales dans l'arbre des OID. Mais il se peut qu'elles ne suffisent pas : on peut alors récupérer une MIB sur le site du vendeur, afin que CMK puisse traduire des OIDs en noms lors de ses walks. Les MIBs se mettent alors dans local/share/check_mk/mibs :

Pour rappel, chaque site CMK a son propre utilisateur sur le serveur, et le home de cet utilisateur contient tous les fichiers de configuration.

<source> root@supervision:/home/justine# su - sys OMD[sys]:~$ cd local/share/check_mk/mibs/ OMD[sys]:~/local/share/check_mk/mibs$ ls OMD[sys]:~/local/share/check_mk/mibs$ #Déposer les mibs ici :) </source>

Récupérer les OIDs intéressants

Pour faire un plugin, je dois savoir ce que je veux monitorer. La première étape consiste à faire un walk *entier* afin de savoir quelles sont toutes les infos disponibles. En ligne de commande et en étant dans le bon utilisateur CMK, on a une simple commande permettant de le faire; la condition préalable est que la machine a superviser ait été correctement renseignée dans l'interface, avec ses paramètres SNMP. On aura un fichier pour nous aider à écrire notre plugin. En supposant que la machine s'appelle "mydevice01":

<source> OMD[mysite]:~$ cmk -v --snmpwalk mydevice01 mydevice01: Walk on ".1.3.6.1.2.1"...3898 variables. Walk on ".1.3.6.1.4.1"...6025 variables. Wrote fetched data to /omd/sites/heute/var/check_mk/snmpwalks/mydevice01. </source>

Ce process peut prendre des minutes, ou même des heures. On nous dit ici que les données ont été écrites dans un fichier texte, facile à lire il ressemble à cela:

<source> .1.3.6.1.2.1.1.1.0 JetStream 24-Port Gigabit L2 Managed Switch with 4 Combo SFP Slots .1.3.6.1.2.1.1.2.0 .1.3.6.1.4.1.11863.1.1.3 .1.3.6.1.2.1.1.3.0 546522419 .1.3.6.1.2.1.1.4.0 hh@example.com .1.3.6.1.2.1.1.5.0 sw-ks-01 etc </source>

On trouve chaque OID et sa valeur (la première ligne étant le sysdescr !). Les OIDs n'étant pas parlant, et si on a les bonnes MIBs d'installées, on peut dans un second temps faire en sorte que ce walk soit traduit pour nos beaux yeux:

<source> OMD[heute]:~$ cmk --snmptranslate mydevice01 > translated Processing 9923 lines. finished. </source>

Ici, on redirige tout ça dans "translated", sinon ça s'affiche sur la sortie standard. On a alors:

<source> .1.3.6.1.2.1.1.1.0 JetStream 24-Port Gigabit L2 Managed Switch with 4 Combo SFP Slots --> SNMPv2-MIB::sysDescr.0 .1.3.6.1.2.1.1.2.0 .1.3.6.1.4.1.11863.1.1.3 --> SNMPv2-MIB::sysObjectID.0 .1.3.6.1.2.1.1.3.0 546522419 --> DISMAN-EVENT-MIB::sysUpTimeInstance .1.3.6.1.2.1.1.4.0 hh@example.com --> SNMPv2-MIB::sysContact.0 .1.3.6.1.2.1.1.5.0 sw-ks-01 --> SNMPv2-MIB::sysName.0 .1.3.6.1.2.1.1.6.0 Core Switch Serverraum klein --> SNMPv2-MIB::sysLocation.0 .1.3.6.1.2.1.1.7.0 3 --> SNMPv2-MIB::sysServices.0 .1.3.6.1.2.1.2.1.0 27 --> IF-MIB::ifNumber.0 .1.3.6.1.2.1.2.2.1.1.1 1 --> IF-MIB::ifIndex.1 .1.3.6.1.2.1.2.2.1.1.2 2 --> IF-MIB::ifIndex.2 </source>

Écriture d'un plugin

Maintenant qu'on a nos OID, on va développer le plugin. On va faire trois choses:

  • Pour sa détection SNMP, spécifier quelles OIDs doivent contenir quel texte pour que notre plugin soit lancé.
  • Déclarer quelles OIDs seront interrogées pour la supervision.
  • Ecrire un plugin analogue à ceux utilisés pour un check par agent.

Jusque ici tout allait bien... Mais ce n'est plus le cas. La doc dit d'enregistrer, pour les deux premières étapes, une section dans local/lib/check_mk/base/plugins/agent_based/foo.py... Mais le dossier local/lib/check_mk n'existe pas. Et en prenant mes checks compellent, qui sont dans ~/local/share/check_mk/checks, ça n'as pas la même tête. Ces checks datent certes de 2015. Mais alors, à quoi doit ressembler mon fichier ?

Qu'est-ce que c'est que ce bazar ? Analyse d'un check compellent

Je sais que mes checks Compellent, installés par un package, fonctionnent (et ça sans agent). Le dossier Checks ne contient pas que des checks SNMP, certes; mais ceux-ci en sont.

En voici un:

<source lang="python">

  1. Check_mk Plugin For Dell Compellent SC4020
  2. Licence : GPL
  3. Cyril Pawelko - cyril@pawelko.net
  4. 03/2015

def inventory_dell_compellent_ctlrfan(info):

   return [ ("%s" % (x[2]) , None) for x in info ]

def check_dell_compellent_ctlrfan(item, _no_params, info):

       for line in info:
               if line[2] == item:
                       ident = "Enclosure Fan %s (%s)" % (line[0],line[2])
                       #  ScStatus (INTEGER) {up( 1 ),down( 2 ),degraded( 3 )}
                       if line[1] == "1" : return (0,ident + " is OK")
                       elif line[1] == "3" : return (1, ident + " is degraded(!)")
                       elif line[1] == "2" : return (2, ident + " is down(!!)")
                       else : return(3, ident + " state unknown")
       return (3, "Controller Fan %s not found" % item )

check_info["dell_compellent_ctlrfan"] = {

   "check_function"        : check_dell_compellent_ctlrfan,
   "inventory_function"    : inventory_dell_compellent_ctlrfan,
   "service_description"   : "%s",
   "has_perfdata"          : False,
   "snmp_scan_function"    : lambda oid: "compellent" in oid(".1.3.6.1.2.1.1.1.0").lower() and\
                                                               oid(".1.3.6.1.4.1.16139.2.15.1.7.1") != "EN-SC4020" and # SC-4020 has enclosure fans, but no controller fan \
                                                               oid(".1.3.6.1.4.1.16139.2.1.0") != None,
   "snmp_info"             : ( ".1.3.6.1.4.1.16139.2.16.1", [
                                       2, # 0 scEnclFanNbr
                                       3, # 1 scEnclFanStatus
                                       4, # 2 scEnclFanLocation
                             ]),

</source>

Trois parties:

  • inventory_dell_compellent_ctlrfan(info) : fonction d'inventaire. Je ne comprends pas ce qu'elle fait. Je suppose que pour mes deux fonctions, info est ce que renvoient les walks décrits dans la 3e partie.
  • check_dell_compellent_ctlrfan : fonction check : semble renvoyer (numéro décrivant la gravité, informations à afficher). Prend info, mais aussi _no_params et item, je ne sais pas ce que c'est.
  • check_info["dell_compellent_ctlrfan"] : définit toutes les infos concernant ce check, y compris l'appel des deux fonctions au-dessus:
    • check_function : ma fonction de check, exécutée en lui donnant les infos
    • inventory_function : ma fonction d'inventaire
    • service description : %s ? Devrait renvoyer la description du servie, mais je ne connais pas ce formatage à l'ancienne
    • has_perfdata : false ici, je suppose qu'on peut renvoyer des valeurs pour des graphes
    • snmp_scan_function : Cette horrible fonction lambda renvoie True si le mot "compellent" est dans le sysdescr et qu'on a les bons équipements
    • snmp_info : je suppose qu'il s'agit du walk, lequel renvoie les infos.

Analyse d'un check plus récent

Ici, un check plus récent pour une box (peu importe):

<source lang="python"> def inventory_adsl_line(info):

   for oid_end,adslLineCoding, adslLineType, adslLineSpecific, \
       adslAturInvSerialNumber, adslAturInvVendorID, adslAturInvVersionNumber, \
       adslAturCurrSnrMgn, adslAturCurrAtn, adslAturCurrStatus, adslAturCurrOutputPwr, \
       adslAturCurrAttainableRate, adslAtucChanCurrTxRate, adslAturChanCurrTxRate \
   in info:
       yield oid_end, None # item name follows oid enumeration

def check_adsl_line(item, params, info):

   # try to extract check parameters
   if 'downstream_params' in params:
       downstream_warn,downstream_crit = params['downstream_params']
   else:
  1. [ABREGE]

def scan_adsl(oid):

   sys_descr = oid(".1.3.6.1.2.1.1.1.0").lower()
   for type_ in [ "vigor130", "vigor165", ]:  
     if type_ in sys_descr:
       return True
   return False

check_info["adsl_line"] = {

   "check_function"        : check_adsl_line,
   "group"                 : "adsl_line",
   "inventory_function"    : inventory_adsl_line,
   "service_description"   : "ADSL at Interface  %s",
   "snmp_info"             : ( ".1.3.6.1.2.1.10.94.1.1", [ \
      OID_END, # interface number
      "1.1.1", # adslLineCoding
      "1.1.2", # adslLineType
      "1.1.3", # adslLineSpecific
      "3.1.1", # adslAturInvSerialNumber
      "3.1.2", # adslAturInvVendorID
      "3.1.3", # adslAturInvVersionNumber
      "3.1.4", # adslAturCurrSnrMgn
      "3.1.5", # adslAturCurrAtn
      "3.1.6", # adslAturCurrStatus
      "3.1.7", # adslAturCurrOutputPwr
      "3.1.8", # adslAturCurrAttainableRate
      "4.1.2", # adslAtucChanCurrTxRate
      "5.1.2", # adslAtucChanCurrTxRate
      ] ),
  "snmp_scan_function"     : scan_adsl,
  "includes"               : ["if.include"],
  "has_perfdata"           : True

} </source>

Ici, j'ai toujours ma fonction de check, mais aussi un groupe ? et on voit bien que ma fonction de scan sert à déterminer si l'équipement en question est concerné.