Die Benutzung des Embedded Perl Interpreters
Einleitung
Stephen Davies hat für Nagios Code beigesteuert, der es ermöglicht Nagios mit der Unterstützung für einen embedded
Perl Interpreter zu kompilieren. Dies ist vor allem für die User interessant, die sehr stark Perl-basierte Plugins
einsetzen.
Stanley Hopcroft hat einige Zeit mit dem embedded Perl Interpreter gearbeitet und hat nun die Vor- und Nachteile
seiner Benutzung zusammengefassst. Er gibt auch einige hilfreiche Hinweise dazu, wie man Perl-basierte Plugins
so entwickelt, dass diese richtig mit dem embedded Perl Interpreter zusammenarbeiten. Der Grossteil dieser Dokumentation
basiert auf seinen Kommentaren.
Es sollte darauf hingewiesen werden, das mit "ePN" Nagios mit der Unterstützung des embedded Perl gemeint ist
(embedded Perl Nagios).
Vorteile
Einige Vorteile von ePN (embedded Perl Nagios) sind:
- Nagios wird weniger Zeit zur Ausfügrung von Perl Plugins benötigen, da es nun nicht mehr bei jeder Ausführung
eines solchen Plugins einen zusätzlichen Prozess (für den externen Perl Interpreter) erzeugen muss.
Stattdessen wird das Plugin durch einen library call ausgeführt.
- ePN verrigert ausserdem den System Einfluss von Perl Plugins und/oder ermöglicht es so mehr Überprüfungen
mit Perl durchzuführen, als man sonst könnte. Mit anderen Worten, es gibt weniger Anreiz Plugins in anderen Sprachen
(wie C/C++ oder Expect/TClL) zu schreiben, da diese bekannt dafür sind eine spürbar längere Zeit zur Entwicklung
benötigen als Perl (dafür aber auch ungefährt zehn Mal schneller laufen als Perl).
- Falls man kein C-Programmierer ist, hat man mit ePN die Möglichkeit die Leistung von Nagios zu erhöhen, indem
man Perl all die schwereren Arbeiten machen lässt, ohne das dadurch aber Nagios verlangsam werden würde. Man beachte
aber, dass ePN nicht das Plugin selbst beschleunigt, sondern nur den System-Overhead bei deren Ausführung verringert.
Falls man schnellere Perl Plugins haben möchte, sollte man sich mit Perl XSUBs (XS), oder C auseinandersetzen,
nachdem man sicher ist, dass Perl bereits optimiert wurde und das man bereits alle möglichen Algorithmen
(Benchmark.pm ist unbezahlbar um die Leistung von Perl Elementen zu vergleichen) bereits voll ausgeschöpft
hat.
- Die Benutzung von ePN ist eine exzellente Möglichkeit, um mehr über Perl zu lernen.
Nachteile
The disadvantages of ePN (embedded Perl Nagios) are much the same as Apache mod_perl (i.e. Apache with an embedded
interpreter) compared to a plain Apache:
- Ein Perl Programm, das mit Nagios gut funktioniert muss nicht unbedingt gut mit ePN funktionieren.
Man muss die Plugins verändern, damit sie mit ePN funktionieren.
- Perl Plugins sind unter ePN schwerer zu debuggen als unter einer Standard-Nagios-Installation.
- ePN hat eine höhere Dateigrösse (memory footprint) als ein normales Nagios.
- Einige Perl Konstrukte können nicht mit ePN benutzt werden oder verhalten sich anders, als man es eigentlich
erwarten würde.
- Man muss sich bewusst sein, dass es mehrere Wege gibt ans Ziel zu gelangen und man u.U. einen Weg wählen muss,
der nicht so attraktiv oder einleuchtend ist.
- Man benötigt ein grösseres Wissen über Perl (allerdings nichts esoterisches oder Dinge über die Perl Internas,
ausser die Plugins benutzen XSUBS).
Zeilgruppe
- Durchschnittliche Perl-Entwickler; die Entwickler die die zahlreichen möglichen Features der Sprache
zu schätzen wissen, ohne ein tieferes Wissen über die Interna von Perl zu haben.
- Falls man sich bereits mit "Perl objects", "name management", "data structures" und dem Debugger auskennt,
ist dieses ausreichend um den Weg mit ePN zu gehen.
Dinge die man tun sollte, wenn man ein Perl Plugin entwickelt (egal ob mit ePN oder ohne)
- Immer, immer irgendwelchen Output generieren lassen
- Man sollte die 'use utils' benutzen und die Sachen importieren, die exportiert werden ($TIMEOUT %ERRORS &print_revision
&support)
- Einfach einen Blick auf die Standard-Perl-Plugins werfen, wie die ihre Arbeiten erledigen.
- Immer mit $ERRORS{CRITICAL}, $ERRORS{OK}, etc. beenden
- Benutze getopt um Kommandozeilen-Argumente auszulesen
- Timeouts behandeln
- Rufe print_usage (was selbst programmiert werden muss) wenn keine Kommandozeilen-Argumente übergeben werden
- Benutze Standard-Schalternamen (z.B. H für 'host', V für 'version')
Dinge die beachtet werden müssen, wenn man Perl Plugins für ePN entwickelt
- <DATA> kann nicht benutzt werden; benutze hier stattdessen z.B. documents
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) ;
- BEGIN Blöcke werden nicht funktioneren wie erwartet. Man sollte diese möglichst vermeiden.
- Man sollte sicherstellen, das Perl absolut sauber ist zum Zeitpunkt der Kompilierung
- use strict
- use perl -w (andere Schalter [T z.B.] wird nicht helfen)
- use perl -c
- Verhindere lexical Variablen (my) mit globalem Gültigkeitsbereich um __variable__ Daten an Sub-Routine zu übergeben.
Dies ist __fatal__ wenn die Sub-Routine mehr als einmal aufgerufen wird, wenn die Überprüfung läuft. Solche Sub-Routinen
agieren als 'closures' die den ersten Wert von globalen Lexikalen in subsequenten Ausführungen von Sub-Routinen locken.
Falls die globale allerdings schreibgeschützt ist (eine komplizierte Struktur z.B.), sollte dies kein Problem sein. Was
Bekman in diesem Fall rät, ist folgendes:
- mache die Sub-Routine anonym und rufe sie z.B. via eine Code ref
veränder dieses in dieses
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 ;
# anon closures __always__ rebind the current lexical value
- setze die globalen Lexikalen in Sub-Routinen, so dass diese ihr eigenes Paket benutzen (als ein Objekt oder ein Modul)
- gebe die info an subs als eine Referenz oder Alias (\$lex_var or $_[n])
- ersetze Lexikale with Paket-Globalen und exkludiere diese aus 'use strict' objections mit 'use vars qw(global1 global2 ..)'
- Man achte darauf wo man Informationen herbekommt.
Nützliche Informationen erhält man bei den üblichen Verdächtigen (die O'Reilly books, plus Damien Conways "Object Oriented Perl")
aber für die wirklich wichtigen Dinge im richtigen Kontext sollte man mit Stas Bekman's mod_perl guide unter
http://perl.apache.org/guide/ anfangen.
Dieses wundervolle Buch enthält zwar nichts über Nagios, dafür aber alles über die Entwicklung von Perl Programmen für den embedded
Perl Interpreter in Apache (z.B. Doug MacEacherns mod_perl).
Die perlembed manpage ist essentiell für Kontext und Unterstützung.
Da Lincoln Stein und Doug MacEachern ein oder zwei Dinge über Perl und embedded Perl wissen, sollte man auch
einen Blick auf deren Buch 'Writing Apache Modules with Perl and C' werfen.
- Sollte das Plugin mit ePN seltsame Werte zurückliefern, liegt der Grund bestimmt in einem der zuvor genannten Punkte.
- Man sollte vorbereitet sein den Code mit den folgenden Dingen zu debuggen:
- mit einem ePN und
- hinzufügen von print statements in das Plugin um Variablen-Werte auf STDERR auszugeben (STDOUT kann nicht benutzt werden)
- hinzufügen von print statements in p1.pl um anzuzeigen, was ePN über das Plugin denkt bevor es ausgeführt wird (vi)
- ausführen von ePN im Vordergrund (zusammen mit den bereits genannten Punkten)
- benutze das 'Deparse'-Modul in dem Plugin, um zu sehen wie der Parser das Plugin optimiert hat und was der Interpreter letztendlich
bekommt. (hilfreich: 'Constants in Perl' von Sean M. Burke, The Perl Journal, Herbst 2001)
perl -MO::Deparse <dein_programm>
- Man sei sich aber bewusst in was ePN das Plugin verändert damit man, falls alles andere scheitert, den transformierten Code
debuggen kann.
Wie man unten sehen kann schreibt p1.pl das Plugin als eine Subroutine mit dem Namen 'hndlr' in dem Paket mit dem Namen
'Embed::<something_related_to_your_plugin_file_name>' neu.
Das Plugin erwartet u.U. Kommandozeilen-Argumente in @ARGV, deshalb ordnet pl.pl auch @_ dem @ARGV zu.
In der Umkehrung wird 'eval' ed und falls die eval einen Fehler hervorruft (irgendein parse oder run Fehler), wird das Plugin ausgeworfen.
Der folgende Output zeigt, wie ein Tets-ePN das check_rpc-Plugin umschreibt, bevor dieses ausgeführt wird.
Das meiste des Codes des eigentlichen Plugins wird nicht gezeigt, da uns hier nur die Transformierung durch das ePN interessiert).
Zur Klarheit wurden die Transformierungen rot eingefärbt:
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 netsaint
#
# 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.12 $
#
# Copyright Notice: GPL
#
... der Rest des Plugin-Code kommt hier (wurde wegen der Lesbarkeit entfernt) ...
}
- Man sollte nie 'use diagnostics' in einem Plugin verwenden, das von einer produktiven ePN-Installation benutzt wird.
Hierdurch werden nämlich __alle__ Perl Plugins CRITICAL zurückgeben.
- Benutze ein mini embedded Perl C-Programm um das Plugin zu überprüfen. Dies garantiert zwar nicht, dass das Plugin
gut mit ePN zusammenfunktioniert, falls das Plugin aber diesen Test nicht erfolgreich meistert, wird es definitiv nicht
mit ePN funktionieren.
[ Ein Beispiel-Mini-ePN ist in dem contrib/-Verzeichnis der Nagios-Distribution zum testen von Perl Plugins enthalten.
Man muss nur in das contrib/-Verzeichnis wechseln und 'make mini_epn' eingeben um es zu kompilieren. Es muss aus dem gleichen
Verzeichnis heraus ausgeführt werden, indem die p1.pl-Datei liegt (auch diese Datei wird mit Nagios geliefert). ]
Nagios mit der Unterstützung für den embedded Perl Interpreter kompilieren
Okay, nun kann wieder geatmet werden. Du willst also immernoch Nagios mit der Unterstützung für den embedded Perl
Interpreter kompilieren? ;-)
Um Nagios mit dem embedded Perl Interpreter zu kompilieren, muss man das configure-Skript zusätzlich mit der
--enable-embedded-perl-Option erneut laufen lassen. Falls man den embedded Interpreter
intern die kompilierten Skripte cachen lassen will, muss man ausserdem --with-perlcache-Option
angeben. Beispiel:
./configure --enable-embedded-perl --with-perlcache ...andere Optionen...
Hat man das configure-Skript mit den neuen Optionen laufen lassen, muss man Nagios erneut kompilieren. Um sicherzustellen,
das Nagios erfolgreich mit dem embedded Perl Interpreter kompilierte wurde, muss man das Programm nur mit dem -m-Argument
aus der Kommandozeile heraus ausrufen. Die Ausgabe des Befehls wird ungefähr wie dieses aussehen (man beachte dass der
embedded Perl Interpreter in dem options-Bereich aufgelistet wird:
[nagios@firestore ]# ./nagios -m
Nagios 1.0a0
Copyright (c) 1999-2001 Ethan Galstad (nagios@nagios.org)
Last Modified: 07-03-2001
License: GPL
External Data I/O
-----------------
Object Data: DEFAULT
Status Data: DEFAULT
Retention Data: DEFAULT
Comment Data: DEFAULT
Downtime Data: DEFAULT
Performance Data: DEFAULT
Options
-------
* Embedded Perl compiler (With caching)