Shinken : example de Hack rapide du code

Gabès Jean ( 05 May 2010 ) blog Talk /

Un exemple de hack rapide

Dans un précédent post, j'ai déjà parlé des méthodes de développement que j'ai utilisé dans Shinken. Tout ceci a pour but de faciliter le développement par la suite, comme le rajout facile d'une propriété sans avoir à se soucier des héritages, distributions sur les différents éléments de l'architecture, etc etc.

Nous allons en voir un exemple avec un cas simple : le rajout d'un paramètre pour l'historique du flapping dans Shinken. En effet, Nagios et Shinken sont capables de détecter un élément qui fait le "yoyo" entre deux états. Plutôt que de spammer les users avec des notifications UP/DOWN/UP/DOWN, les schedulers sont assez malin (entendez utilisent un bête algorithme) pour s'apercevoir que l'état à changé X% de fois au cours des N derniers tests. La valeur X était déjà paramétrable pour les hôtes et les services, mais celle de N était hardcodée à 20 états.

Le problème c'est que 20 états ce n'est pas assez pour détecter un yoyo sur toute la nuit. Il arrive donc souvent des cas où l'on est averti pour rien, juste car on ne peux pas augmenter cette valeur. C'est dommage :cry:

Et bien plus maintenant :mrgreen: !

Je l'ai rajouté dans Shinken en quelques lignes qui vont vous monter à quel point c'est simple d'aller hacker dans ce code, 5 lignes seulement dans notre cas :-D

La modification

Tout se joue dans deux fichiers sources :

  • config.py : qui gère les paramètres de configurations globaux
  • schedulingitem.py : qui gère les algorithmes d'ordonnancement, des demandes de checks et autres.

Dans le premier (config.py) on remarque un tableau nommé properties vers le début du fichier avec toutes les propriétés possibles pour le fichier principal (nagios.cfg).

Qu'à cela ne tienne, on va rajouter notre nouvelle propriété :

'flap_history' : {'required':False, 'default':'20', 'pythonize': to_int, 'class_inherit' : [(Host, None), (Service, None)]},

On rajoute donc le paramètre flap_history, qui n'est pas obligatoire (required=False), vaut par défaut 20, se transforme en objet int depuis la lecture de la chaîne de caractère dans le fichier, et va être présentée aux classes Host et Service avec ce même nom de flap_history (rôle de None, expliqué un peu plus haut dans le code, si vous mettez un nouveau nom, c'est lui qui sera utilisé pour cette classe).

Et voila, c'est tout pour la configuration ! Et oui, rien de plus. L'Arbiter va lire la configuration, transformer en entier la valeur, mettre 20 si elle est absente et va la fournir aux configurations envoyées aux schedulers automatiquement ! Là, ne pas hacker un tel code, c'est plus que de la fainéantise :lol:

NOTE 2021: ça reste encore une de mes réalisations favorite du code de Shinken

On a réglé le problème de la configuration, maintenant on va utiliser notre nouvelle propriété. Ceci se passe dans deux fonctions du fichier schedulingitem.py : add_flapping_change et update_flapping. La première rajoute le changement d'état sur la pile de 20 éléments et s'assure que la pile fait toujours au plus 20 éléments. La seconde fait le calcul de pourcentage de changement à proprement parlé.

Les schedulingitems sont les hosts/services (une classe commune pour factoriser le code), et l'objet est nommé self en Python. On a dit que la propriété a été envoyée sur les classes Host et Service car c'est un paramètre global à tous les hôtes et services, pas la peine de le multiplier par le nombre d'hôtes et services. En Python, pour accéder à sa classe (qui est un objet comme un autre), il suffit de faire :

self.__class__

Donc là pour obtenir notre valeur, il suffit de faire :

flap_history = self.__class__.flap_history

On remplace les trois occurrences de 20 qui trainent dans le code par flap_history et c'est réglé, on peut tester/commiter 8-) :

if len(self.flapping_changes) > flap_history:
    r += i*(1.2-0.8)/flap_history + 0.8
    r = r / flap_history

Au final

Nous avons vu la définition et l'utilisation d'un paramètre global dans Shinken. C'est très simple, et il ne faut pas se priver :-) Nous verrons une autre fois le rajout d'un paramétrage dans un service ou un hôte, c'est encore plus simple qu'ici car il n'y a pas besoin de passer par l'accrochage dans les classes Host et Service. Mais ce sera pour une prochaine fois, j'ai un git push à faire.

Si vous souhaitez hacker vous aussi, n'hésitez pas :

git clone git://github.com/naparuba/shinken.git

J'accepte volontiers les patchs :)

Juste pour info, dans le code de Nagios, si on voulait faire la même chose, il faudrait changer la macro MAX_STATE_HISTORY_ENTRIES en simple variable :

 grep -r MAX_STATE_HISTORY_ENTRIES * | wc -l
 30

30 lignes au minimum juste pour la partie traitement! Je n'ose même pas regarder combien de lignes ceci va coûter pour la configuration, mais bien plus d'une, ça c'est sûr... :-?

Notez bien que je ne dis pas ça pour me moquer des développeurs de Nagios, comme quoi le code est imbitable non, car je n'aurais sûrement pas fait mieux en C. C'est juste pour illustrer que parfois, utiliser des techniques de développements avancées (le développement dynamique qui a un peu irrité lors de l'annonce de Shinken sur la mailing list), ça ne fait pas de mal à l'efficacité...


Archives