Embedding JNRPE - Tutorial

As of version 2.0 you have the ability to embed JNRPE inside your own application. It's a very simple operation that will allow you to expose your application so that Nagios can query such data through check_nrpe commands.

Compiling against jnrpe-lib

The easiest way to compile an application using jnrpe-lib is through the use of maven.

If you don't want to use maven, you have to manually download the dependencies.

Compiling using maven

Create the following directory structure:

  +- src/
       +- main/
           +- java/
  +- pom.xml

and put your sources under the 'java' directory.

Create a file called pom.xml in the same directory as 'src'. This are the jnrpe-lib data:

  • group-id : net.sf.jnrpe * artifact-id : jnrpe-lib

    Create the pom.xml file according to the maven documentation.

    run

      mvn package
    

Custom compiling

If you don't use maven, than you will have to download jnrpe-lib and all its dependecies manually.

You can download jnrpe-lib and its dependencies (deps.tar.gz) here

The application example

Through the tutorial we will refer to a very simple application that computes two random number between 1 and 100. Next we will add the ability to check through Nagios the number values and return a warning or critical if the random number falls inside a given range../check_nrpe -n -H 127.0.0.1 -c runTest -a 'random1!33:66!67:'

Follows the example application:

  
  public class Example
  {
      private int m_iRandom1 = 0;
      private int m_iRandom2 = 0;
      private Random m_random = new Random();
         
      /**
       * This method updates the variables with the next random number
       */
      public void updateVariables()
      {
          m_iRandom1 = m_random.nextInt(100);  // We want to values to be between 0 and 100
          m_iRandom2 = m_random.nextInt(100);
      }   
      
      
      /**
       * The main method
       */
      public static void main(String[] args) throws Exception
      {
         Example example = new Example();
         example.updateVariables();
      
         // Change variable values every 5 seconds 
         while(true)
         {
             Thread.sleep(5000);
             example.updateVariables();
         }
      } 
  }
  

Creating the JNRPE plugin

As first step we must create a JNRPE plugin that is able to monitor our object. Every JNRPE plugin must implement the IPluginInterface interface:

  public class ExamplePlugin implements IPluginInterface
  {
      private final Example m_instanceToCheck;
      
      public ExamplePlugin(Example ex)
      {
          m_instanceToCheck = ex;
      }
  
      @Override
      public ReturnValue execute(ICommandLine cl)
      {
          String sVariable = cl.getOptionValue("get");  // (1)
          
          if (sVariable.equalsIgnoreCase("random1")) 
              return new ReturnValue("RANDOM1: " + m_instanceToCheck.getRandom1());  // (2)
  
          if (sVariable.equalsIgnoreCase("random2"))
              return new ReturnValue("RANDOM2: " + m_instanceToCheck.getRandom2());
  
          return new ReturnValue(IJNRPEConstants.STATE_UNKNOWN, sVariable + " is unknown");
      }
  }

This first version of the plugin always returns an OK state and, as text, the variable name and it's value.

The code line identified by (1) means that we want the value of the 'get' option: that means that the plugin must be able to receive an option named 'get' and that that option must accept an argument (the value).

This is very important because we must describe all the option our plugin is able to support to JNRPE.

The line identified by (2) is very simple: simply returns an OK return value.

To describe the plugin to JNRPE we have to instantiate a PluginDefinition object:

  IPluginInterface tp = new ExamplePlugin(example);
  PluginDefinition pluginDef = 
                   new PluginDefinition("TestPlugin", "Simple Test Plugin description", tp)  // PluginName : TestPlugin, // (1)
                   .addOption(new PluginOption()  // (2)
                               .setOption("g")            // The plugin accept the short form parameter 'g'  // (3)
                               .setLongOpt("get")         // The long form parameter                         // (4)
                               .setArgName("variable")    // The paramater has an argument called 'variable' // (5)
                               .setArgsOptional(false)    // The parameter argument is mandatory             // (6)
                               .setRequired(true)         // The parameter is mandatory                      // (7)
                               );

Lets analyze the code:

  • (1) Here we instantiate the plugin definition giving a plugin name (TestPlugin) and a short description.
  • (2) Here we add an option to the plugin: take in mind that the plugins must be described as if they were 'command line' application. Every plugin has a command line. You can repeat this line for every other option your plugin must accept.
  • (3) - (4) Here we say that the option can be identified by both the short command '-g' and the long command '--get'.
  • (5) Here we say that the option has an arg named 'variable'
  • (6) Here we say that the argument is mandatory, i.e. you can't cal 'Test Plugin --get' but you have to specify an argument like 'Test Plugin --get random1'
  • (7) Here we are saying that the plugin option is mandatory, i.e. the '--get' option must be present.

Now that we have created the plugin, we have to register it inside the JNRPE plugin repository.

  PluginRepository pluginRepository = new PluginRepository(); // Creates the repository
  pluginRepository.addPluginDefinition(pluginDef);            // Adds our plugin to the repository

Ok: the plugin is ready and JNRPE is aware of its existence. Since a plugin can be used to execute different tasks, now we have to say to JNRPE how to use the plugin. We will accomplish that creating a 'command' based on this plugin.

Creating the command

As with plugins, all commands are described through a 'command definition' object. In the following example we will define a command based on the 'TestPlugin' that will pass the 'get' parameter with the argument received by check_nrpe.

  CommandDefinition commandDef = new CommandDefinition("runTest", "TestPlugin")  // CommandName : runTest, plugin : TestPlugin
              .addArgument(
               new CommandOption("get", "$ARG1$")); // The command will take a parameter called get that asks for an argument
                                                    // The argument will the argument received from check_nrpe

Again, as with plugins, now we have to register the command inside the command repository:

  CommandRepository commandRepository = new CommandRepository();  // Creates the command repository
  commandRepository.addCommandDefinition(commandDef);             // register the command inside the repository

We are almost done: now we have to instantiate JNRPE and start listening for requests.

  JNRPE engine = new JNRPE(pluginRepository, commandRepository); // JNRPE must know both plugin and command repository
  engine.addAcceptedHost("127.0.0.1");                           // Will accept requests from localhost
  engine.listen("127.0.0.1", 5666);                              // Will listen on 127.0.0.1 on port 5666

Follows the whole main method.

   public static void main(String[] args) throws InterruptedException
   {
       Example example = new Example();
       example.updateVariables();
       
       // Instantiate the plugin
       IPluginInterface tp = new ExamplePlugin(example);
       
       // Describe the plugin
       PluginDefinition pluginDef = new PluginDefinition("TestPlugin", "Simple Test Plugin description", tp)  // PluginName : TestPlugin, 
                   .addOption(new PluginOption()
                               .setOption("g")            // The plugin accept the short form parameter 'g'
                               .setLongOpt("get")         // The long form parameter
                               .setArgName("variable")    // The paramater has an argument called 'variable'
                               .setArgsOptional(false)    // The parameter argument is mandatory
                               .setRequired(true)         // The parameter is mandatory
                               );
       
       PluginRepository pluginRepository = new PluginRepository(); // Creates the repository
       pluginRepository.addPluginDefinition(pluginDef);            // Adds our plugin to the repository
       
       // Describes the command
       CommandDefinition commandDef = new CommandDefinition("runTest", "TestPlugin")  // CommandName : runTest, plugin : TestPlugin
                   .addArgument(new CommandOption("get", "$ARG1$")); // The command will take a parameter called get that asks for an argument
                                                                     // The argument will be replaced with what will be received by check_nrpe
             
       CommandRepository commandRepository = new CommandRepository();  // Creates the command repository
       commandRepository.addCommandDefinition(commandDef);             // register the command inside the repository
            
       JNRPE engine = new JNRPE(pluginRepository, commandRepository); // JNRPE must know both plugin and command repository
       engine.addAcceptedHost("127.0.0.1");                           // Will accept requests from localhost
       engine.listen("127.0.0.1", 5666);                              // Will listen on 127.0.0.1 on port 5666
       
      // This is just to update the variable values of the example and is
      // not mandatory at all
       while(true)
       {
           Thread.sleep(5000);
           example.updateVariables();
       }
   }

Run the java application, than try the following command:

  check_nrpe -n -H 127.0.0.1 -c runTest -a 'random1'

You just executed your first JNRPE embedded plugin!

Adding some complexity

The plugin we've created in the previous paragraph always returns OK. In this chapter we will change it so that it will be able to return WARNING or CRITICAL depending on the value of the random variables.

To perform such checks, we will add a '-w|--warning' and a '-c|--critical' parameter to our plugin. Both the -w and -c parameter will have an argument describing the waning/critical thresholds.

Checking thresholds is very easy through the use of the ThresholdUtil class.

Here is the changed plugin class.

  
  public class ExamplePlugin implements IPluginInterface
  {
      private final Example m_instanceToCheck;
      
      public ExamplePlugin(Example ex)
      {
          m_instanceToCheck = ex;
      }
  
      @Override
      public ReturnValue execute(ICommandLine cl)
      {
          String sVariable = cl.getOptionValue("get");
          
          int iValue;
          
          if (sVariable.equalsIgnoreCase("random1"))
              iValue = m_instanceToCheck.getRandom1();
          else if (sVariable.equalsIgnoreCase("random2"))
              iValue = m_instanceToCheck.getRandom2();
          else
              return new ReturnValue(IJNRPEConstants.STATE_UNKNOWN, sVariable + " is unknown");
          
          String sCriticalThreshold = cl.getOptionValue("critical");
          String sWarningThreshold = cl.getOptionValue("warning");
          
          if (ThresholdUtil.isValueInRange(sCriticalThreshold, iValue))
              return new ReturnValue("CRITICAL - " + sVariable + " : " + iValue);
  
          if (ThresholdUtil.isValueInRange(sWarningThreshold, iValue))
              return new ReturnValue("WARNING - " + sVariable + " : " +iValue);
  
          return new ReturnValue("OK - " + sVariable + " : " +iValue);
      }
  }
  

Now that we have changed the plugin class, we have to change the plugin definition too:

  PluginDefinition pluginDef = new PluginDefinition("TestPlugin", "Simple Test Plugin", tp)
                  .addOption(new PluginOption()
                              .setOption("g")
                              .setLongOpt("get")
                              .setArgName("variable")
                              .setArgsOptional(false)
                              .setRequired(true))
                  .addOption(new PluginOption()
                              .setOption("w")
                              .setLongOpt("warning")
                              .setArgName("value")
                              .setArgsOptional(false)
                              .setRequired(false))
                  .addOption(new PluginOption()
                              .setOption("c")
                              .setLongOpt("critical")
                              .setArgName("value")
                              .setArgsOptional(false)
                              .setRequired(false)
                              );

Finally, we have to change the command definition

  CommandDefinition commandDef = new CommandDefinition("runTest", "TestPlugin")
                  .addArgument(new CommandOption("get", "$ARG1$"))
                  .addArgument(new CommandOption("warning", "$ARG2$"))
                  .addArgument(new CommandOption("critical", "$ARG3$")
                  );

Now we can invoke the plugin through the command:

  ./check_nrpe -n -H 127.0.0.1 -c runTest -a 'random1!33:66!67:'