Code

Corrected example
[nagiosplug.git] / doc / developer-guidelines.sgml
index 6e72192661b5a1184cf0bd6a790f250f62848bfb..1ce78ff401b67e81bd018d62c7db044c553a9474 100644 (file)
@@ -5,66 +5,25 @@
   <bookinfo>
     <authorgroup>
       <author>
-       <firstname>Karl</firstname>
-       <surname>DeBisschop</surname>
-       <affiliation>
-         <address><email>karl@debisschop.net</email></address>
-       </affiliation>
+        <affiliation>
+          <orgname>Nagios Plugins Development Team</orgname>
+        </affiliation>
       </author>
-
-      <author>
-       <firstname>Ethan</firstname>
-       <surname>Galstad</surname>
-       <authorblurb>
-         <para>Author of Nagios</para>
-         <para><ulink url="http://www.nagios.org"></ulink></para>
-       </authorblurb>
-       <affiliation>
-         <address><email>netsaint@linuxbox.com</email></address>
-       </affiliation>
-      </author>
-
-      <author>
-       <firstname>Hugo</firstname>
-       <surname>Gayosso</surname>
-       <affiliation>
-         <address><email>hgayosso@gnu.org</email></address>
-       </affiliation>
-      </author>
-
-         
-       <author>
-       <firstname>Subhendu</firstname>
-       <surname>Ghosh</surname>
-       <affiliation>
-               <address><email>sghosh@sourceforge.net</email></address>
-       </affiliation>
-       </author>
-       
-       <author>
-       <firstname>Stanley</firstname>
-       <surname>Hopcroft</surname>
-       <affiliation>
-               <address><email>stanleyhopcroft@sourceforge.net</email></address>
-       </affiliation>
-       </author>       
-
     </authorgroup>
 
-    <pubdate>2002</pubdate>
+    <pubdate>2009</pubdate>
     <title>Nagios plug-in development guidelines</title>
        
     <revhistory>
        <revision>
-          <revnumber>0.4</revnumber>
-          <date>2 May 2002</date>
+          <revnumber>1796</revnumber>
+          <date>2007-09-24 14:51:07 -0400 (Mon, 24 Sep 2007)</date>
        </revision>
     </revhistory>
 
        <copyright>
-               <year>2000 2001 2002</year> 
-               <holder>Karl DeBisschop, Ethan Galstad, 
-               Hugo Gayosso, Stanley Hopcroft, Subhendu Ghosh</holder>
+               <year>2000 - 2009</year>
+               <holder>Nagios Plugins Development Team</holder>
        </copyright>
 
 </bookinfo>
@@ -75,8 +34,8 @@
     the plug-in developers and encourage the standarization of the
     different kind of plug-ins: C, shell, perl, python, etc.</para>
 
-        <para>Nagios Plug-in Development Guidelines Copyright (C) 2000-2003
-        (Karl DeBisschop, Ethan Galstad, Stanley Hopcroft, Subhendu Ghosh, Ton Voon, Jeremy T. Bouse)</para>
+        <para>Nagios Plug-in Development Guidelines Copyright (C) 2000-2009
+        (Nagios Plugins Team)</para>
 
         <para>Permission is granted to make and distribute verbatim
         copies of this manual provided the copyright notice and this
        <para>
        Nagios plugins are developed to the GNU standard, so any OS which is supported by GNU
        should run the plugins. While the requirements for compiling the Nagios plugins release 
-       is very small, to develop from CVS needs additional software to be installed. These are the 
-       minimum levels of software required:
+       are very basic, developing from the Git repository requires additional software to be
+       installed. These are the minimum levels of software required:
 
        <literallayout>
-       gnu make 3.79
-       automake 1.6
-       autoconf 2.54
-       gettext 0.11.5
+       GNU make 3.79
+       GNU automake 1.9.2
+       GNU autoconf 2.59
+       GNU m4 1.4.2
+       GNU libtool 1.5
        </literallayout>
 
-       To compile from CVS, after you have checked out the code, run:
+       To compile from Git, after you have cloned the repository, run:
        <literallayout>
        tools/setup
        ./configure
                the entire output to appear in a pager message, which will get chopped
                off after a certain length.</para>
 
+               <para>As Nagios does not capture stderr output, you should only output to 
+               STDOUT and not print to STDERR.</para>
+
                <section><title>Print only one line of text</title>
                <para>Nagios will only grab the first line of text from STDOUT
                when it notifies contacts about potential problems. If you print
-               multiple lines, you're out of luck. Remember, keep it short and
-               to the point.</para>
+               multiple lines, you're out of luck (though this will be a feature of 
+               Nagios 3). Remember, keep your output short and to the point.</para>
 
                <para>Output should be in the format:</para>
                <literallayout>
-               METRIC STATUS: Information text
+               SERVICE STATUS: Information text
                </literallayout>
                <para>However, note that this is not a requirement of the API, so you cannot depend on this
                being an accurate reflection of the status of the service - the status should always 
                -v options for additional verbosity, up to a maximum of 3. The standard
                type of output should be:</para>
 
-               <table id="verbose_levels"><title>Verbose output levels</title>
+               <table id="verboselevels"><title>Verbose output levels</title>
                        <tgroup cols="2">
                                <thead>
                                        <row>
 
                <section><title>Screen Output</title>
                <para>The plug-in should print the diagnostic and just the
-               synopsis part of the help message.  A well written plugin would
+               usage part of the help message.  A well written plugin would
                then have --help as a way to get the verbose help.</para>
+
                <para>Code and output should try to respect the 80x25 size of a
                crt (remember when fixing stuff in the server room!)</para>
                </section>
                
-           <section><title>Return the proper status code</title>
-               <para>See <xref linkend="ReturnCodes"> below
-               for the numeric values of status codes and their
-               description. Remember to return an UNKNOWN state if bogus or
-               invalid command line arguments are supplied or it you are unable
-               to check the service.</para>
-               </section>
-               
                <section><title>Plugin Return Codes</title>
                <para>The return codes below are based on the POSIX spec of returning
                a positive value.  Netsaint prior to v0.0.7 supported non-POSIX
                                                <entry align="center"><para>3</para></entry>
                                                <entry valign="middle"><para>Unknown</para></entry>
                                                <entry><para>Invalid command line arguments were supplied to the 
-                                               plugin or the plugin was unable to check the status of the given 
-                                               hosts/service</para></entry>
+                                               plugin or low-level failures internal to the plugin (such as unable to fork,
+                                               or open a tcp socket) that prevent it from performing the specified
+                                               operation. Higher-level errors (such as name resolution errors,
+                                               socket timeouts, etc) are outside of the control of plugins and should
+                                               generally NOT be reported as UNKNOWN states.
+                                               </para></entry>
                                        </row>
                                </tbody>
                        </tgroup>
       
                </section>
 
-               <section id="thresholdformat"><title>Threshold range format</title>
-               <para>Thresholds ranges define the warning and critical levels for plugins to 
-               alert on. The theory is that the plugin will do some sort of check which returns
+               <section id="thresholdformat"><title>Threshold and ranges</title>
+               <para>A range is defined as a start and end point (inclusive) on a numeric scale (possibly
+               negative or positive infinity).
+               </para>
+               <para>A threshold is a range with an alert level (either warning or critical). Use the
+               set_thresholds(thresholds *, char *, char *) function to set the thresholds.
+               </para>
+               <para>The theory is that the plugin will do some sort of check which returns
                back a numerical value, or metric, which is then compared to the warning and 
-               critical thresholds.
-               This is the generalised format for threshold ranges:</para>
+               critical thresholds. Use the get_status(double, thresholds *) function to
+               compare the value against the thresholds.</para>
+               <para>This is the generalised format for ranges:</para>
 
                <literallayout>
                [@]start:end
        
                <para>Notes:</para>
                <orderedlist>
-               <listitem><para>start &gt; end></para>
+               <listitem><para>start &le; end</para>
                        </listitem>
                <listitem><para>start and ":" is not required if start=0</para>
                        </listitem>
                        </listitem>
                </orderedlist>
                
-               <para>Note: Not all plugins are coded to expect ranges in this format. It is
-               planned for a future release to
-               provide standard libraries to parse and compare metrics against ranges. There
-               will also be some work in providing multiple metrics.</para>
+               <para>Note: Not all plugins are coded to expect ranges in this format yet.
+               There will be some work in providing multiple metrics.</para>
+
+               <table id="ExampleRanges"><title>Example ranges</title>
+                       <tgroup cols="2">
+                               <thead>
+                                       <row>
+                                               <entry><para>Range definition</para></entry>
+                                               <entry><para>Generate an alert if x...</para></entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry>10</entry>
+                                               <entry>&lt; 0 or &gt; 10, (outside the range of {0 .. 10})</entry>
+                                       </row>
+                                       <row>
+                                               <entry>10:</entry>
+                                               <entry>&lt; 10, (outside {10 .. &infin;})</entry>
+                                       </row>
+                                       <row>
+                                               <entry>~:10</entry>
+                                               <entry>&gt; 10, (outside the range of {-&infin; .. 10})</entry>
+                                       </row>
+                                       <row>
+                                               <entry>10:20</entry>
+                                               <entry>&lt; 10 or &gt; 20, (outside the range of {10 .. 20})</entry>
+                                       </row>
+                                       <row>
+                                               <entry>@10:20</entry>
+                                               <entry>&ge; 10 and &le; 20, (inside the range of {10 .. 20})</entry>
+                                       </row>
+                                       <row>
+                                               <entry>10</entry>
+                                               <entry>&lt; 0 or &gt; 10, (outside the range of {0 .. 10})</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
+               <table id="CommandLineExamples"><title>Command line examples</title>
+                       <tgroup cols="2">
+                               <thead>
+                                       <row>
+                                               <entry><para>Command line</para></entry>
+                                               <entry><para>Meaning</para></entry>
+                                       </row>
+                               </thead>
+                               <tbody>
+                                       <row>
+                                               <entry>check_stuff -w10 -c20</entry>
+                                               <entry>Critical if "stuff" is over 20, else warn if over 10 (will be critical if "stuff" is less than 0)</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -w~:10 -c~:20</entry>
+                                               <entry>Same as above. Negative "stuff" is OK</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -w10: -c20</entry>
+                                               <entry>Critical if "stuff" is over 20, else warn if "stuff" is below 10 (will be critical if "stuff" is less than 0)</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -c1:</entry>
+                                               <entry>Critical if "stuff" is less than 1</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -w~:0 -c10</entry>
+                                               <entry>Critical if "stuff" is above 10; Warn if "stuff" is above zero</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -c5:6</entry>
+                                               <entry>The only noncritical range is 5:6</entry>
+                                       </row>
+                                       <row>
+                                               <entry>check_stuff -c10:20</entry>
+                                               <entry>Critical if "stuff" is less than 10 or over 20</entry>
+                                       </row>
+                               </tbody>
+                       </tgroup>
+               </table>
                </section>
 
                <section><title>Performance data</title>
                <orderedlist>
                <listitem><para>space separated list of label/value pairs</para>
                        </listitem>
-               <listitem><para>label can contain any characters</para>
+               <listitem><para>label can contain any characters except the equals sign or single quote (')</para>
                        </listitem>
                <listitem><para>the single quotes for the label are optional. Required if 
-                       spaces, = or ' are in the label</para>
+                       spaces are in the label</para>
                        </listitem>
                <listitem><para>label length is arbitrary, but ideally the first 19 characters
                        are unique (due to a limitation in RRD). Be aware of a limitation in the
                        same UOM</para>
                        </listitem>
                <listitem><para>warn and crit are in the range format (see 
-                       <xref linkend="thresholdformat">)</para>
+                       <xref linkend="thresholdformat">). Must be the same UOM</para>
                        </listitem>
                <listitem><para>UOM (unit of measurement) is one of:</para>
                        <orderedlist>
                <para>It is up to third party programs to convert the Nagios plugins 
                performance data into graphs.</para>
                </section>
+
+       <section><title>Translations</title>
+       <para>If possible, use translation tools for all output to respect the user's language 
+               settings. See <xref linkend="translationsdevelopers"> for guidelines 
+               for the core plugins. 
+       </para>
+       </section>
 </section>
 
 <section id="SysCmdAuxFiles"><title>System Commands and Auxiliary Files</title>
                <orderedlist>
                        
                        <listitem><para> Do not use BEGIN and END blocks since they will be called 
-                       the first time and when Nagios shuts down with Embedded Perl (ePN).  In 
+                       only once (when Nagios starts and shuts down) with Embedded Perl (ePN).  In 
                        particular, do not use BEGIN blocks to initialize variables.</para>
                        </listitem>
          
                        <listitem><para>To use utils.pm, you need to provide a full path to the
-                       module in order for it to work with ePN.</para>
+                       module in order for it to work.</para>
                        
          <literallayout>
          e.g.
                        variable. </para>
                        
 
-                       <para>Explicitly initialize each varialable in use.  Otherwise with
-                       caching enabled, the plugin will not be recompilied each time, and
+                       <para>Explicitly initialize each variable in use.  Otherwise with
+                       caching enabled, the plugin will not be recompiled each time, and
                        therefore Perl will not reinitialize all the variables.  All old
                        variable values will still be in effect.</para>
                        </listitem>
                        
-                       <listitem><para>Do not use &gt; DATA &lt; (these simply do not compile under ePN).</para>
+                       <listitem><para>Do not use &gt;DATA&lt; handles (these simply do not compile under ePN).</para>
                        </listitem>
 
-                       <listitem><para>Do not use named subroutines</para> 
+                       <listitem><para>Do not use global variables in named subroutines. This is bad practise anyway, but with ePN the
+                       compiler will report an error "&lt;global_var&gt; will not stay shared ..". Values used by
+                       subroutines should be passed in the argument list.</para> 
                        </listitem>
 
                        <listitem><para>If writing to a file (perhaps recording
                
                        <listitem><para>As in <xref linkend="runtime"> all plugins need 
                        to monitor their runtime, specially if they are using network
-                       resources.  Use of the <emphasis>alarm</emphasis> is recommended.
+                       resources.  Use of the <emphasis>alarm</emphasis> is recommended
+                       noting that some Perl modules (eg LWP) manage timers, so that an alarm
+                       set by a plugin using such a module is overwritten by the module.
+                       (workarounds are cunning (TM) or using the module timer)
                        Plugins may import a default time out ($TIMEOUT) from utils.pm.
                        </para>
                        </listitem>
 
                <para>The option -v or --verbose should be present in all plugins.
                The user should be allowed to specify -v multiple times to increase
-               the verbosity level, as described in <xref linkend="verbose_levels">.</para>
+               the verbosity level, as described in <xref linkend="verboselevels">.</para>
     </section>
 
     <section>
     </section>
 </section>
 
+<section id="Testcases"><title>Test cases</title>
+<para>
+Tests are the best way of knowing if the plugins work as expected. Please
+create and update test cases where possible.
+</para>
+
+<para>
+To run a test, from the top level directory, run "make test". This will run 
+all the current tests and report an overall success rate.
+</para>
+
+<para>
+See the <ulink url="http://tinderbox.opsera.com">Nagios Plugins Tinderbox server</ulink>
+for the daily test results.
+</para>
+
+<section><title>Test cases for plugins</title>
+<para>These use perl's Test::More. To do a one time test, run "cd plugins && perl t/check_disk.t".
+</para>
+
+<para>There will somtimes be failures seen in this output which are known failures that
+need to be fixed. As long as the return code is 0, it will be reported as "test pass".
+(If you have a fix so that the specific test passes, that will be gratefully received!)
+</para>
+
+<para>
+If you want a summary test, run: "cd plugins && prove t/check_disk.t".
+This runs the test in a summary format.
+</para>
+
+<para>
+For a good and amusing tutorial on using Test::More, see this 
+<ulink url="http://search.cpan.org/~mschwern/Test-Simple-0.62/lib/Test/Tutorial.pod">
+link</ulink>
+</para>
+
+</section>
+
+<section><title>Testing the C library functions</title>
+<para>
+We use <ulink url="http://jc.ngo.org.uk/trac-bin/trac.cgi/wiki/LibTap">the libtap library</ulink>, which gives 
+perl's TAP
+(Test Anything Protocol) output. This is used by the FreeBSD team for their regression testing.
+</para>
+
+<para>
+To run tests using the libtap library, download the latest tar ball and extract. 
+There is a problem with tap-1.01 where 
+<ulink url="http://jc.ngo.org.uk/trac-bin/trac.cgi/ticket/25">pthread support doesn't appear to work</ulink>
+properly on non-FreeBSD systems. Install with 'CPPFLAGS="-UHAVE_LIBPTHREAD" ./configure && make && make check && make install'. 
+</para>
+
+<para>
+When you run Nagios Plugins' configure, it will look for the tap library and will automatically
+setup the tests. Run "make test" to run all the tests.
+</para>
+</section>
+
+</section>
 <section id="CodingGuidelines"><title>Coding guidelines</title>
        <para>See <ulink url="http://www.gnu.org/prep/standards_toc.html">GNU
        Coding standards</ulink> for general guidelines.</para>
-       <section><title>Comments</title>
+       <section><title>C coding</title>
+       
+       <para>Variables should be declared at the beginning of code blocks and 
+       not inline because of portability with older compilers.</para>
+
        <para>You should use /* */ for comments and not // as some compilers
        do not handle the latter form.</para>
-       <para>There should not be any named credits in the source code - contributors
-       should be added 
-       into the AUTHORS file instead. The only exception to this is if a routine
-       has been copied from another source.</para>
+
+       <para>You should also avoid using the type "bool" and its values
+       "true" and "false". Instead use the "int" type and the plugins' own
+       "TRUE"/"FALSE" values to keep the code uniformly.</para>
        </section>
 
-       <section><title>CVS comments</title>
-       <para>When adding CVS comments at commit time, you can use the following prefixes:
-       <variablelist>
-         <varlistentry><term>- comment</term>
-         <listitem>
-           <para>for a comment that can be removed from the Changelog</para>
-         </listitem>
-         </varlistentry>
-         <varlistentry><term>* comment</term>
-         <listitem>
-           <para>for an important amendment to be included into a features list</para>
-         </listitem>
-         </varlistentry>
-       </variablelist>
+       <section><title>Crediting sources</title>
+       <para>If you have copied a routine from another source, make sure the licence
+       from your source allows this. Add a comment referencing the ACKNOWLEDGEMENTS
+       file, where you can put more detail about the source.</para>
+       <para>For contributed code, do not add any named credits in the source code 
+       - contributors should be added into the THANKS.in file instead. 
        </para>
+       </section>
+
+       <section><title>Commit Messages</title>
        <para>If the change is due to a contribution, please quote the contributor's name 
        and, if applicable, add the SourceForge Tracker number. Don't forget to 
-update the AUTHORS file.</para>
+update the THANKS.in file.</para>
+        <para>If you have a change that is useful for noting in the next release, please
+       update the NEWS file.</para>
+       <para>All commits will be written to a ChangeLog at release time.
+       </para>
        </section>
+
+       <section id="translationsdevelopers"><title>Translations for developers</title>
+       <para>To make the job easier for translators, please follow these guidelines:</para>
+       <orderedlist>
+         <listitem><para>
+           Before creating new strings, check the po/nagios-plugins.pot file to 
+           see if a similar string
+           already exists
+         </para></listitem>
+         <listitem><para>
+           For help texts, break into individual options so that these can be reused
+           between plugins
+         </para></listitem>
+         <listitem><para>Try to avoid linefeeds unless you are working on a block of text</para></listitem>
+         <listitem><para>Short help is not translated</para></listitem>
+         <listitem><para>Long help has options in English language, but text translated</para></listitem>
+         <listitem><para>"Copyright" kept in English</para></listitem>
+         <listitem><para>Copyright holder names kept in original text</para></listitem>
+         <listitem><para>Debugging output does not need to be translated</para></listitem>
+       </orderedlist>
+       </section>
+
+       <section><title>Translations for translators</title>
+       <para>To create an up to date list of translatable strings, run: tools/gen_locale.sh</para>
+       </section>
+
 </section>
 
 <section id="SubmittingChanges"><title>Submission of new plugins and patches</title>
@@ -643,7 +784,7 @@ update the AUTHORS file.</para>
        <section id="Patches"><title>Patches</title>
        <para>If you have a bug patch, please supply a unified or context diff against the
        version you are using. For new features, please supply a diff against
-       the CVS HEAD version.</para>
+       the Git "master" branch.</para>
 
        <para>Patches should be submitted via 
        <ulink url="http://sourceforge.net/tracker/?group_id=29880&amp;atid=397599">SourceForge's
@@ -658,17 +799,37 @@ update the AUTHORS file.</para>
        Credit will always be given for any patches through a THANKS file in the distribution.</para>
        </section>
 
-       <section id="New_plugins"><title>New plugins</title>
-       <para>If you would like others to use your plugins and have it included in
-       the standard distribution, please include patches for the relevant
-       configuration files, in particular "configure.in". Otherwise submitted 
-       plugins will be included in the contrib directory.</para>
-       
-       <para>Plugins in the contrib directory are going to be migrated to the
-       standard plugins/plugin-scripts directory as time permits and per user
-       requests. The minimum requirements are:</para>
+
+       <section id="Contributedplugins"><title>Contributed plugins</title>
+       <para>Plugins that have been contributed to the project and 
+       distributed with the Nagios Plugin files are held in the contrib/ directory and are not installed
+       by default. These plugins are not officially supported by the team. 
+       The current policy is that these plugins should be owned and maintained by the original 
+       contributor, preferably hosted on <ulink url="http://exchange.nagios.org">Nagios Exchange</ulink>.
+       </para>
+       <para>If patches or bugs are raised to an contributed plugin, we will start communications with the
+       original contributor, but seek to remove the plugin from our distribution.
+       </para>
+       <para>The aim is to distribute only code that the Nagios Plugin team are responsible for.
+       </para>
+       </section>
+
+       <section id="Newplugins"><title>New plugins</title>
+       <para>If you would like others to use your plugins, please add it to
+       the official 3rd party plugin repository, 
+       <ulink url="http://exchange.nagios.org">Nagios Exchange</ulink>.
+       </para>
+
+       <para>We are not accepting requests for inclusion of plugins into 
+       our distribution at the moment, but when we do, these are the minimum
+       requirements:
+       </para>
 
       <orderedlist>
+       <listitem>
+         <para>Include copyright and license information in all files. Copyright must be solely
+               granted to the Nagios Plugin Development Team</para>
+       </listitem>
        <listitem>
          <para>The standard command options are supported (--help, --version,
          --timeout, --warning, --critical)</para>
@@ -685,25 +846,21 @@ update the AUTHORS file.</para>
        </listitem>
        <listitem>
          <para>It should also follow code format guidelines, and use functions from
-utils (perl or c or sh) rather than cooking it's own</para>
+utils (perl or c or sh) rather than using its own</para>
+       </listitem>
+       <listitem>
+         <para>Includes patches to configure.in if required (via the EXTRAS list if 
+         it will only work on some platforms)</para>
+       </listitem>
+       <listitem>
+         <para>If possible, please submit a test harness. Documentation on sample
+         tests coming soon</para>
        </listitem>
       </orderedlist>
 
-       <para>New plugins should be submitted via 
-       <ulink url="http://sourceforge.net/tracker/?group_id=29880&amp;atid=541465">SourceForge's
-       tracker system for Nagiosplug new plugins</ulink> 
-       and be announced to the nagiosplug-devel mailing list.</para>
-       
-       <para>For new plugins, provide a diff to add to the EXTRAS list (configure.in) 
-       unless you are fairly sure that the plugin will work for all platforms with 
-       no non-standard software added.</para>
-
-       <para>If possible please submit a test harness. Documentation on sample
-       tests coming soon.</para>
        </section>
 
 </section>
-
 </article>
   
 </book>