1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>11.2. Developing Plugins For Use With Embedded Perl</title>
<link rel="stylesheet" href="../stylesheets/icinga-docs.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.75.1">
<meta name="keywords" content="Supervision, Icinga, Nagios, Linux">
<link rel="home" href="index.html" title="Icinga Version 1.14 Documentation">
<link rel="up" href="ch11.html" title="Chapter 11. Development">
<link rel="prev" href="pluginapi.html" title="11.1. Icinga Plugin API">
<link rel="next" href="icinga-api.html" title="11.3. No Icinga API to install anymore">
<script src="../js/jquery-min.js" type="text/javascript"></script><script src="../js/icinga-docs.js" type="text/javascript"></script>
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<CENTER><IMG src="../images/logofullsize.png" border="0" alt="Icinga" title="Icinga"></CENTER>
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">11.2. Developing Plugins For Use With Embedded Perl</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="pluginapi.html">Prev</a> </td>
<th width="60%" align="center">Chapter 11. Development</th>
<td width="20%" align="right"> <a accesskey="n" href="icinga-api.html">Next</a>
</td>
</tr>
</table>
<hr>
</div>
<div class="section" title="11.2. Developing Plugins For Use With Embedded Perl">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="epnplugins"></a>11.2. <a name="epn_plugins"></a>Developing Plugins For Use With Embedded Perl</h2></div></div></div>
<div class="toc"><dl>
<dt><span class="section">11.2.1. <a href="epnplugins.html#introduction">Introduction</a></span></dt>
<dt><span class="section">11.2.2. <a href="epnplugins.html#targetaudience">Target Audience</a></span></dt>
<dt><span class="section">11.2.3. <a href="epnplugins.html#todo">Things you should do when developing a Perl Plugin (ePN or not)</a></span></dt>
<dt><span class="section">11.2.4. <a href="epnplugins.html#nottodo">Things you must do to develop a Perl plugin for ePN</a></span></dt>
</dl></div>
<div class="section" title="11.2.1. Introduction">
<div class="titlepage"><div><div><h3 class="title">
<a name="introduction"></a>11.2.1. Introduction</h3></div></div></div>
<p>Stanley Hopcroft has worked with the embedded Perl interpreter quite a bit and has commented on the advantages/disadvanges
of using it. He has also given several helpful hints on creating Perl plugins that work properly with the embedded interpreter.
The majority of this documentation comes from his comments.</p>
<p>It should be noted that "ePN", as used in this documentation, refers to embedded Perl Nagios, or if you prefer,
Icinga compiled with an embedded Perl interpreter.</p>
</div>
<div class="section" title="11.2.2. Target Audience">
<div class="titlepage"><div><div><h3 class="title">
<a name="targetaudience"></a>11.2.2. Target Audience</h3></div></div></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<p>Average Perl developers; those with an appreciation of the languages powerful features without knowledge of internals
or an in depth knowledge of those features.</p>
</li>
<li class="listitem">
<p>Those with a utilitarian appreciation rather than a great depth of understanding.</p>
</li>
<li class="listitem">
<p>If you are happy with Perl objects, name management, data structures, and the debugger, that's probably
sufficient.</p>
</li>
</ul></div>
</div>
<div class="section" title="11.2.3. Things you should do when developing a Perl Plugin (ePN or not)">
<div class="titlepage"><div><div><h3 class="title">
<a name="todo"></a>11.2.3. Things you should do when developing a Perl Plugin (ePN or not)</h3></div></div></div>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<p>Always always generate some output</p>
</li>
<li class="listitem">
<p>Use 'use utils' and import the stuff it exports ($TIMEOUT %ERRORS &print_revision &support)</p>
</li>
<li class="listitem">
<p>Have a look at how the standard Perl plugins do their stuff e.g.</p>
<div class="itemizedlist"><ul class="itemizedlist" type="circle">
<li class="listitem">
<p>Always exit with $ERRORS{CRITICAL}, $ERRORS{OK}, etc.</p>
</li>
<li class="listitem">
<p>Use getopt to read command line arguments</p>
</li>
<li class="listitem">
<p>Manage timeouts</p>
</li>
<li class="listitem">
<p>Call print_usage (supplied by you) when there are no command line arguments</p>
</li>
<li class="listitem">
<p>Use standard switch names (e.g. H 'host', V 'version')</p>
</li>
</ul></div>
</li>
</ul></div>
</div>
<div class="section" title="11.2.4. Things you must do to develop a Perl plugin for ePN">
<div class="titlepage"><div><div><h3 class="title">
<a name="nottodo"></a>11.2.4. Things you must do to develop a Perl plugin for ePN</h3></div></div></div>
<div class="orderedlist"><ol class="orderedlist" type="1">
<li class="listitem">
<p><DATA> can not be used; use here documents instead e.g.</p>
<pre class="screen">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) ;</pre>
</li>
<li class="listitem">
<p>BEGIN blocks will not work as you expect. May be best to avoid.</p>
</li>
<li class="listitem">
<p>Ensure that it is squeaky clean at compile time i.e.</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<p>use strict</p>
</li>
<li class="listitem">
<p>use perl -w (other switches [T notably] may not help)</p>
</li>
<li class="listitem">
<p>use perl -c</p>
</li>
</ul></div>
</li>
<li class="listitem">
<p>Avoid lexical variables (my) with global scope as a means of passing __variable__ data into subroutines. In fact this
is __fatal__ if the subroutine is called by the plugin more than once when the check is run. Such subroutines act as
'closures' that lock the global lexicals first value into subsequent calls of the subroutine. If however, your global is
read-only (a complicated structure for example) this is not a problem. What Bekman <a class="link" href="http://perl.apache.org/docs/1.0/guide/" target="_top">recommends you do instead</a>, is any of the following:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<p>make the subroutine anonymous and call it via a code ref e.g.</p>
<pre class="screen">turn this into
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</pre>
</li>
<li class="listitem">
<p>put the global lexical and the subroutine using it in their own package (as an object or a module)</p>
</li>
<li class="listitem">
<p>pass info to subs as references or aliases (\$lex_var or $_[n])</p>
</li>
<li class="listitem">
<p>replace lexicals with package globals and exclude them from 'use strict' objections with 'use vars qw(global1
global2 ..)'</p>
</li>
</ul></div>
</li>
<li class="listitem">
<p>Be aware of where you can get more information.</p>
<p>Useful information can be had from the usual suspects (the O'Reilly books, plus Damien Conways "Object Oriented Perl")
but for the really useful stuff in the right context start at Stas Bekman's mod_perl guide at <a class="link" href="http://perl.apache.org/guide/" target="_top">http://perl.apache.org/guide/</a>.</p>
<p>This wonderful book sized document has nothing whatsoever about Icinga, but all about writing Perl programs for
the embedded Perl interpreter in Apache (i.e. Doug MacEacherns mod_perl).</p>
<p>The perlembed manpage is essential for context and encouragement.</p>
<p>On the basis that Lincoln Stein and Doug MacEachern know a thing or two about Perl and embedding Perl, their book
'Writing Apache Modules with Perl and C' is almost certainly worth looking at.</p>
</li>
<li class="listitem">
<p>Be aware that your plugin may return strange values with an ePN and that this is likely to be caused by the problem in
item #4 above</p>
</li>
<li class="listitem">
<p>Be prepared to debug via:</p>
<div class="itemizedlist"><ul class="itemizedlist" type="disc">
<li class="listitem">
<p>having a test ePN and</p>
</li>
<li class="listitem">
<p>adding print statements to your plugin to display variable values to STDERR (can't use STDOUT)</p>
</li>
<li class="listitem">
<p>adding print statements to p1.pl to display what ePN thinks your plugin is before it tries to run it (vi)</p>
</li>
<li class="listitem">
<p>running the ePN in foreground mode (probably in conjunction with the former recommendations)</p>
</li>
<li class="listitem">
<p>use the 'Deparse' module on your plugin to see how the parser has optimised it and what the interpreter will
actually get. (see 'Constants in Perl' by Sean M. Burke, The Perl Journal, Fall 2001)</p>
</li>
</ul></div>
<pre class="screen"> perl -MO::Deparse <your_program></pre>
</li>
<li class="listitem">
<p>Be aware of what ePN is transforming your plugin too, and if all else fails try and debug the transformed
version.</p>
<p>As you can see below p1.pl rewrites your plugin as a subroutine called 'hndlr' in the package named
'Embed::<something_related_to_your_plugin_file_name>'.</p>
<p>Your plugin may be expecting command line arguments in @ARGV so pl.pl also assigns @_ to @ARGV.</p>
<p>This in turn gets 'eval' ed and if the eval raises an error (any parse error and run error), the plugin gets chucked
out.</p>
<p>The following output shows how a test ePN transformed the <span class="emphasis"><em>check_rpc</em></span> plugin before attempting to
execute it. Most of the code from the actual plugin is not shown, as we are interested in only the transformations that the
ePN has made to the plugin). For clarity, transformations are shown in red:</p>
<pre class="screen">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.20 $
#
# Copyright Notice: GPL
#
<span class="emphasis"><em> ... rest of plugin code goes here (it was removed for brevity) ...</em></span>
}</pre>
</li>
<li class="listitem">
<p>Don't use 'use diagnostics' in a plugin run by your production ePN. We think it causes__all__ the Perl plugins to
return CRITICAL.</p>
</li>
<li class="listitem">
<p>Consider using a mini embedded Perl C program to check your plugin. This is not sufficient to guarantee your plugin
will perform Ok with an ePN but if the plugin fails this test it will certainly fail with your ePN. <span class="color"><font color="red">[ A sample mini ePN is included in the <span class="emphasis"><em>contrib/</em></span> directory of the
Icinga distribution for use in testing Perl plugins. Change to the contrib/ directory and type 'make mini_epn' to
compile it. It must be executed from the same directory that the p1.pl file resides in (this file is distributed with
Icinga). ]</font></span></p>
</li>
</ol></div>
<a class="indexterm" name="idm140381622206384"></a>
</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="pluginapi.html">Prev</a> </td>
<td width="20%" align="center"><a accesskey="u" href="ch11.html">Up</a></td>
<td width="40%" align="right"> <a accesskey="n" href="icinga-api.html">Next</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">11.1. Icinga Plugin API </td>
<td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td>
<td width="40%" align="right" valign="top"> 11.3. No Icinga API to install anymore</td>
</tr>
</table>
</div>
<P class="copyright">© 1999-2009 Ethan Galstad, 2009-2017 Icinga Development Team, https://www.icinga.com</P>
</body>
</html>
|