Chapitre 72. Développement de plugins pour être utilisés avec Perl intégré à Nagios

Introduction

Stanley Hopcroft a beaucoup travaillé sur l'interpréteur Perl intégré et a commenté les avantages et inconvénients de son utilisation. Il a également donné plusieurs trucs utiles pour écrire des plugins Perl qui fonctionnent correctement avec l'interpréteur intégré. La majeure partie de cette documentation provient de ses commentaires.

Notez que ePN, tel qu'il est utilisé dans cette documentation, fait référence à Perl intégré à Nagios [embedded Perl Nagios], ou si vous préférez, Nagios compilé avec un interpréteur Perl intégré.

Public visé

  • Développeurs Perl de niveau moyen; ceux qui ont une idée des puissantes fonctionnnalités du langage sans en avoir une connaissance appronfondie.

  • Ceux qui ont une appréciation pratique plutôt qu'un grand niveau de compréhension.

  • Si vous êtes à l'aise avec les objets Perl, la gestion de nom, les structures de données et le déboguer, ça devrait suffire.

Les choses que vous devriez faire quand vous développez un plugin Perl (ePN ou pas)

  • Générez toujours un affichage

  • Utilisez use utils et importez ce qui en est exporté ($TIMEOUT %ERRORS &print_revision &support)

  • Jetez un œil sur la façon dont sont écrits les plugins Perl standards, comme par exemple :

    • Quittez toujours avec une valeur $ERRORS{CRITICAL}, $ERRORS{OK}, etc.

    • Utilisez getopt pour lire les paramètres de la ligne de commande

    • Gérez les dépassements de délai

    • Appelez print_usage (que vous fournissez) quand il n'y a pas de paramètre à la commande

    • Utilisez des noms de paramètres standard (par exemple H 'host', V 'version')

Ce que vous devez faire quand vous écrivez un plugin Perl pour ePN

  1. <DATA> ne peut pas être utilisé ; utilisez ici des documents à la place, par exemple :

    my $data = <<DATA;
    portmapper 100000
    portmap 100000
    sunrpc 100000
    rpcbind 100000
    rstatd 100001
    rstat 100001
    rup 100001
    ..
    DATA
    
    %prognum = map { my($a, $b) = split; ($a, $b) } split(/\n/, $data) ;
                    
    
  2. BEGIN Les blocks ne fonctionneront pas comme vous l'attendez. Il vaut mieux les éviter.

  3. Assurez-vous de la parfaite propreté du code à la compilation, comme par exemple

    • utilisez use strict

    • utilisez perl -w (les autres paramètres (notamment T) ne sont d'aucune aide)

    • utilisez perl -c

  4. Evitez les variables de portée lexicale (my) déclarées globalement comme moyen de passer des variable aux fonctions. En fait ceci est fatal si la fonction est appelée par le plugin plus d'une fois lorsque le contrôle est exécuté. Ces fonctions se comportent comme des encapsulations [closures] qui verrouillent les variables lexicales globales sur leur première valeur lors des appels suivants à la fonction. Si toutefois votre variable globale est en lecture seule (une structure de données complexe par exemple), ce n'est pas un problème. Ce que Bekman recommande en remplacement est une des solutions suivantes :

    • faites une fonction anonyme et appelez-la à travers une référence au code, par exemple :

      remplacez ceci        par 
      
          my $x = 1 ;          my $x = 1 ;
          sub a { .. Process $x … }  $a_cr = sub { … Process $x … } ;
          .               .
          .               .
          a ;              &$a_cr ;
          $x = 2            $x = 2 ;
          a ;              &$a_cr ;
      
          # les encapsulations anonymes reprennent __toujours__ la valeur lexicale courante
          
      
    • mettez la variable globale et la fonction qui l'utilise dans leur propre paquetage [package] (comme objet ou module)

    • passez les variables aux fonctions comme références ou alias (\$lex_var or $_[n])

    • remplacez les variables lexicales par des variables globales au paquetage et excluez les des objections faites par 'use strict' en déclarant 'use vars qw(global1 global2 ..)'

  5. Sachez où trouvez plus d'informations.

    Vous pouvez obtenir des informations utiles des indices habituels (les livres O'Reilly, plus Object Oriented Perl de Damien Conways) mais pour les bonnes réponses dans ce contexte commencez par le guide du mod_perl de Stas Bekman sur http://perl.apache.org/guide/.

    Ce document merveilleux au format livre n'a strictement rien à voir avec Nagios, mais tout à voir avec l'écriture de programmes pour l'interpréteur Perl intégré à Apache (par exemple le mod_perl de Doug MacEachern).

    La page man perlembed est essentielle pour le contexte et les encouragements.

    Si l'on considère que Lincoln Stein et Doug MacEachern savent deux-trois choses sur Perl et l'intégration de Perl, leur livre Writing Apache Modules with Perl and C vaut certainement d'être lu.

  6. Sachez que votre plugin peut retourner d'étranges valeurs avec ePN, et que cela est probablement dû au point 4 ci-dessus.

  7. Soyez prêt à déboguer en :

    • ayant un ePN de test

    • ajoutant des instructions print à votre plugin pour afficher la valeur des variables sur STDERR (STDOUT ne peut pas être utilisé)

    • ajoutant des instructions print à p1.pl pour afficher ce qu'ePN pense qu'est votre plugin avant d'essayer de le lancer (vi)

    • lançant l'ePN en avant-plan (probablement en conjonction avec les recommandations précédentes)

    • utilisant le module Deparse sur votre plugin pour voir comment l'analyseur syntaxique l'a optimisé, et ce que l'interpréteur reçoit réellement (voir Constants in Perl de Sean M. Burke, The Perl Journal, automne 2001)

      perl -MO::Deparse <votre_programme>
      
  8. Sachez qu'ePN transforme votre plugin lui aussi, et si tout le reste a échoué essayez de déboguer la version transformée.

    Comme vous pouvez le constater ci-dessous p1.pl réécrit votre plugin comme une fonction appelé 'hndlr' dans le paquetage nommé Embed::<quelque-chose-ayant-rapport-avec-le-nom-de-fichier-de-votre-plugin>.

    Votre plugin attend peut-être des paramètres de la ligne de commande dans @ARGV, donc pl.pl assigne également @_ à @ARGV.

    Ceci à son tour est évalué et si eval remonte une erreur (qu'elle soit syntaxique ou d'exécution), le plugin est jeté dehors.

    La copie d'écran suivante montre comment un ePN de test a transformé le plugin check_rpc avant d'essayer de l'exécuter. Seule une petite partie du code du plugin est montrée ici, car nous ne nous intéressons qu'aux transformations que l'ePN lui fait subir). Les transformations sont affichées en rouge :

    package main;
    use subs 'CORE::GLOBAL::exit';
    sub CORE::GLOBAL::exit { die "ExitTrap: $_[0] (Embed::check_5frpc)"; }
    package Embed::check_5frpc; sub hndlr { shift(@_);
    @ARGV=@_;
    #! /usr/bin/perl -w
    #
    # check_rpc plugin for Nagios
    #
    # usage:
    #    check_rpc host service
    #
    # Check if an rpc serice is registered and running
    # using rpcinfo - $proto $host $prognum 2>&1 |";
    #
    # Use these hosts.cfg entries as examples
    #
    # command[check_nfs]=/some/path/libexec/check_rpc $HOSTADDRESS$ nfs
    # service[check_nfs]=NFS;24x7;3;5;5;unix-admin;60;24x7;1;1;1;;check_rpc
    #
    # initial version: 3 May 2000 by Truongchinh Nguyen and Karl DeBisschop
    # current status: $Revision: 1.19 $
    #
    # Copyright Notice: GPL
    #
    … rest of plugin code goes here (it was removed for brevity) …
    }
                    
    
  9. Ne pas utiliser use diagnostics dans un plugin lancé par votre ePN de production. Je pense qu'il force la valeur de retour à CRITICAL dans tous les plugins Perl.

  10. Envisagez l'utilisation d'un mini Perl intégré pour vérifier votre plugin. Cela ne suffit pas à valider votre plugin avec l'ePN, mais si le plugin échoue à ce test il échouera également avec l'ePN. Un exemple de mini ePN est inclus dans le répertoire contrib/ de la distribution de Nagios à cette fin. Placez-vous dans le répertoire contrib/ et tapez make mini_epn pour le compiler. Il doit être exécuté depuis le répertoire où se trouve p1.pl (ce fichier est distribué avec Nagios).