Otherwise, the plugin is compiled into a subroutine in a new package by
=over 4
=item 1 creating a package name from the plugin file name (C<Embed::Persistent::valid_package_name>)
=item 2 turning off subroutine redefinition warnings (C<use subs 'CORE::GLOBAL::exit'>)
=item 3 overriding CORE::GLOBAL::exit from within package main (C<sub CORE::GLOBAL::exit { die "ExitTrap: \$_[0] (yada)"; }>)
This allows the plugin to both call exit without taking down the persistence framework, and to return the exit code to the
Nagios.
=item 4 prepending the plugin text with code to let the plugin function as a subroutine.
The plugin command line arguments are expected to be in @ARGV, so @ARGV is set to the subroutine arguments (@_).
The new subroutine also sets the warning level to trap all warnings that may have been caused by
by the transformation (the -w option to Perl in the text is no longer significant (because the shebang line is not fed to exec()).
=item 5 writing the plugin as the subroutine named B<hndlr> in the new package.
=item 6 returning either a code reference to the subroutine named hndlr in the package named in item 1, OR the
compilation error trapped by eval 'string'. It is the callers responsibility to check either ERRSV (from C) or $@ (from Perl)
and skip run_package() if these values are true.
=back
=item Embed::Persistent::run_package( plugin_filename, DO_CLEAN, (SV *) plugin_hndlr_cr, plugin_argument_string )
E<10>
Returns (plugin_return_code, plugin_output)
run_plugin() actually runs the plugins with the arguments contained in the (space separated string) 4th argument.
=back
=head1 DIFFERENCES FROM PERSISTENT.PL
The example B<persistent.pl> takes no account of
=over 4
=item * Capturing output from the Perl program being run
This framework ties STDOUT to a scalar that stores the result of PRINT or PRINTF.
=item * Running Perl programs in child processes
This is the largest single difference between this framework and the example program persistent.pl. The example uses one
subroutine (eval_file()) to compile and run the program. This is unsuitable for a process like Nagios that
fork a new process to run a plugin. (It is unsuitable because were the child process
to call eval_file() and then the update its copy of %Cache, other child processes would not get the updated %Cache,
and would therefore recompile the plugin).
Instead, eval_file() is split into two: eval_file() and run_package().
Eval_file is called by the Nagios parent process to compile the plugin
and update %Cache. Child processes forked in base/checks.c have the same copy of %Cache and call run_plugin() to check the
last compilation error (from %Cache) and run the plugin if the plugin was error free.
=item * Dealing with Perl programs that call exit
This framework redefines exit() to die emitting a string containing the plugin return code (the first argument of exit).
Since the plugin is run by eval(), B<$@> contains this string from which the return code is extracted.
=item * Providing command line arguments to the Perl program
This framework sets @ARGV in the B<Hndlr> subroutine to the remaining subroutine arguments.
All of these clever ideas came from, AFAIK, Stephen Davies.
=back
=head1 BUGS
=item * MEMORY LEAK
This framework does nothing to prevent the memory leaks mentioned in B<perlembed>, relying on operator intervention.
Probably the best way of doing so is by periodically scheduling
=over 4
=item 1 A check of the memory used by the Nagios process (by running for example the standard Nagios plugin check_procs)
=item 2 Restarting Nagios with the (supplied with Nagios) startup script (restart command).
=back
If you do periodically restart Nagios, make sure that
=over 4
=item 1 plugins all set the PATH environment variable if they need other system binaries (otherwise, if the
init script is excec'd by cron, the PATH will be reset and the plugins will fail - but only when reatsrted by cron).
=7= |