Developer Guide

Components

Components are essentially just a directory on your Fusion server with some specific PHP files included inside. Whenever you upload a component zip file into the component management page, all Fusion does behind the scenes is unzip it into a specific directory (/usr/local/nagiosfusion/html/includes/components/). Because of the naming convention of the files included, the code is magically (it isn't magic) included everytime the Nagios Fusion codebase is instantiated.

In order to make sure this happens properly, we have to adhere to a few standards. We've outlined those standards in this document. All of the functions that we use in this document should be outlined in the accompanying function reference - the same goes for the callbacks and poll callbacks.

Before you dig in and work with the examples included here, make sure you've set your appropriate PHP warning/error settings for development. We generally like to make sure that display_errors is set to On, and error_reporting is set to E_ALL & ~E_NOTICE in our /etc/php.ini file. Make sure you restart your apache server after setting these values (service httpd restart or systemctl restart httpd).

This document assumes you're working on a CentOS or Red Hat Enterprise Linux server (version 6 or 7) with a stock new install of Nagios Fusion 4. If you've changed your file locations, you'll have to make those adjustments on your own.

A New Component

We're going to start off with our very own component. In order to save time, we're going to perform the development directly on the Fusion server. Don't worry, we can always export our component once it's been completed to share with the world.

A good starting point is usually determining what it is we want to do. You're in luck since we've already decided what we're doing. We'll make a Fusion component that includes a bit of text on each of the child pages.

So to start, we'll first create a directory and make some files:

mkdir -p /usr/local/nagiosfusion/html/includes/components/bitoftext/
cd /usr/local/nagiosfusion/html/includes/components/bitoftext/
touch bitoftext.inc.php

You see that file we touched? Notice that the file name is the same name as the folder we created, with .inc.php appended. This is important, because if that file didn't exist, our component would never be included in the Nagios Fusion codebase upon instantiation. In all cases, there must be at least a file with the same base name of the folder it is contained in appended by .inc.php in order for that component to be included (.e.g: [component]/[component].inc.php). You can have other files in there as well, but those would have to be explicitly included from your inc.php file.

Now fire up your favorite editor to edit our file (vi bitoftext.php). Let's make the file look like the following, and then we'll explain what it all means in the next sections:

<?php

register_bitoftext();
function register_bitoftext() {

    $component_args = array(

        COMPONENT_NAME              => 'bitoftext',
        COMPONENT_TITLE             => 'Bit of Text',
        COMPONENT_VERSION           => '1.0.0',
        COMPONENT_DATE              => '06/01/2017',
        COMPONENT_AUTHOR            => 'Nagios Enterprises and Friends',
        COMPONENT_DESCRIPTION       => 'Place a bit of text on each child page',
        COMPONENT_REQUIRES_VERSION  =>  4000,
        COMPONENT_FUNCTION          => 'bitoftext_successful_registration',
    );

    register_component($component_args);
}

Component Arguments

This is a pretty basic PHP file. We start with the opening tag <?php and then jump right into calling a function (register_bitoftext();) that we define on the next line.

This function is what's responsible for passing our arguments into Fusion to attempt and register the component. We have a long list of data that we can supply to Fusion.

IndexExplanation
COMPONENT_NAME REQUIRED - The short, unique name of the component.
COMPONENT_TITLE REQUIRED - The full title of the component. This is displayed with the component information.
COMPONENT_VERSION The version of the component. This is displayed with the component information.
COMPONENT_AUTHOR The author of the component. This is displayed with the component information.
COMPONENT_DESCRIPTION REQUIRED - A brief description of the component. This is displayed with the component information.
COMPONENT_DATE The date that this component was last updated. This is displayed with the component information.
COMPONENT_COPYRIGHT The copyright notice of the component. This is displayed with the component information.
COMPONENT_LICENSE The license applied to this component. This is displayed with the component information.
COMPONENT_HOMEPAGE The webpage about the author, or where to find more details about the component. This is displayed with the component information.
COMPONENT_CONFIG_FUNCTION The configure function. This is a PHP function callback string. If this is specified, then there will be an icon under the manage components page in the 'Settings' column. The function specified here must accept a specific argument, and alter the output/processing depending on the value supplied by Fusion.
COMPONENT_REQUIRES_VERSION The minimum product version that this component can work with. The version of your Fusion can be found with the output of the function get_product_release().
COMPONENT_FUNCTION This is a PHP function callback string. If the component register successfully, then this is the function that is executed. Preferrably, you'll want to put all of the callback registrations inside of the function you specify here.
COMPONENT_ERROR_MESSAGE The error message to display if your component can't be registered.

Our function register_bitoftext() builds our component argument array - which specifies our COMPONENT_FUNCTION as bitoftext_successful_registration - and then passes the array into the register_component() function.

So what does the register_component() function do, you ask? This let's Fusion perform some magic (it isn't magic) behind the scenes to make sure everything passed in was fine. If you've set the COMPONENT_FUNCTION array index - then there won't be any issues - the component will simply print out an error message in the list and never finish registration.

Component Configuration

Although this doesn't have anything to do with the component we're building: we're going to talk a bit about the COMPONENT_CONFIG_FUNCTION before we continue on. In the table above, we said this argument array index corresponds to a PHP function callback string.

The function you define only needs to accept a single argument, we'll call it $mode. Fusion sends a different value depending on where in the component configure process the user is.

Let's say that a user clicks on your 'Settings' icon in the manage components page. In that case, Fusion will call your COMPONENT_CONFIG_FUNCTION defined function with $mode set as COMPONENT_CONFIG_MODE_GET. In this case, your function needs to return some output that will contain form elements.

Then once the user submits the form, Fusion will call that same function with $mode set as COMPONENT_CONFIG_MODE_SET. It will include the form elements you returned as text in the get mode. This is too easy. So let's make a quick fake function to show an example:

function customlogin_config_func($mode = null) {

    switch ($mode) {

        case COMPONENT_CONFIG_MODE_GET:

            return '<label>Some text: <input type="text" name="sometext" /></label>';

        case COMPONENT_CONFIG_MODE_SET:

            $sometext = grab_request_var("sometext");
            /* do some processing with $sometext */

    }
}

Note the use of the function grab_request_var. This function is explained in greater detail in the Functions Reference page.

Now back to our regularly scheduled component...

Registering Callbacks

One of the things that made extending Nagios XI so easy has been brought into the new Fusion: callbacks! A callback is essentially a defined moment in time during the instantiation and execution of the application that you can hook into and add your own processing.

We hook into callbacks by registering functions to be executed during the callback we specify. A common callback that's registered is the CALLBACK_MENU_INITIALIZED. This is the callback executed when the menu items are being initialized, so that we can extend the menu object with our own links.

Let's take a look at the Network Operation Center component's use of registering a callback during menu initialization:

    register_callback(CALLBACK_MENU_INITIALIZED, 'register_noc_menu');

/* ... */

function register_noc_menu($cb, &$menu) {

    $menu->add_link(menu_link(_('Network Operations Center'), 'includes/components/noc/noc.php'), 'home-server-status');
}

We'll get more into more detail about how these functions work and the arguments they accept on the Functions Reference page. But for now we're going to piggy back off of this example to finally build our bitoftext_successful_registration function.

Since this is going to be the function that Fusion executes once registration is successful, we'll keep all of our callback registrations inside of that function. Take a look:

function bitoftext_successful_registration() {

    register_callback(CALLBACK_HEADER_END, 'bitoftext_header');
}

Again a nice and simple function. Don't worry, a full list of callbacks is available on the Callbacks Reference page. All you need to know right now is that we'll be injecting some text onto each page after the header has been printed on child pages.

What is a child page? It's true, we're psychic. A child page is the page built in the inner frame of the Fusion interface. The main navigation header, side navigation, and footer are all part of a parent page. When you click a link anywhere in Fusion, the inner frame is the page that is updated. And Fusion is so smart that it can tell which pages are child pages and which are parent pages.

Now let's define our bitoftext_header function. All callbacks registered need to accept two arguments: the first argument will be the callback type ($cbtype) followed by the arguments generated during the callback execution ($cbargs). Some of the callbacks pass $cbargs and expect you to alter it in some way - which means you need to accept this argument as a reference (&$cbargs) such as in the case of the register_noc_menu function listed previously.

In our case, we don't need to pass the arguments as reference:

function bitoftext_header($cbtype, $cbargs) {

    if ($cbtype == CALLBACK_HEADER_END) {

        $childpage = grab_array_var($cbargs, 'child', false);

        if ($childpage) {

            echo "<h4>This is a Bit of Text</h4>";
        }
    }
}

This should be fairly self explanatory. We use the Fusion function grab_array_var to see if $cbargs['child'] is set (if it isn't we give it a default value of false). We then check if $childpage is true and if so we echo some code.

If you've been following along so far, whenever you view (almost) any page in Fusion, there should be an obnoxious bit of text up at the top of the page! It's probably (it isn't) magic!

Registering Poll Callbacks

That's pretty much it for our component. There is a specific topic we should touch on before we move on: poll callbacks.

Fusion is all about connecting all of your remote servers from one interface. It handles this by periodically polling those remote servers and storing the data in a database for quick retrieval when you access that interface.

This is all handled behind the scenes - magically (it isn't magic) - with the use of poll callbacks. Poll callbacks work a bit like regular callbacks, except for a few major differences:

  • A specific poll callback type won't be executed unless at least one of that type is registered.
  • The poll callback functions accept the raw poll data and return the sanitized data.
  • All of the data returned by a poll callback function is available to the entire interface.

We'll definitely cover this in more detail on the Poll Callbacks Reference page.

Putting it All Together

What follows is the entirety of the component we built together:

<?php

register_bitoftext();
function register_bitoftext() {

    $component_args = array(

        COMPONENT_NAME              => 'bitoftext',
        COMPONENT_TITLE             => 'Bit of Text',
        COMPONENT_VERSION           => '1.0.0',
        COMPONENT_DATE              => '06/01/2017',
        COMPONENT_AUTHOR            => 'Nagios Enterprises and Friends',
        COMPONENT_DESCRIPTION       => 'Place a bit of text on each child page',
        COMPONENT_REQUIRES_VERSION  =>  4000,
        COMPONENT_FUNCTION          => 'bitoftext_successful_registration',
    );

    register_component($component_args);
}

function bitoftext_successful_registration() {

    register_callback(CALLBACK_HEADER_END, 'bitoftext_header');
}

function bitoftext_header($cbtype, $cbargs) {

    if ($cbtype == CALLBACK_HEADER_END) {

        $childpage = grab_array_var($cbargs, 'child', false);

        if ($childpage) {

            echo "<h4>This is a Bit of Text</h4>";
        }
    }
}

If that exists inside of the file /usr/local/nagiosfusion/html/includes/components/bitoftext/bitoftext.inc.php you should now be able to navigate to your Manage Components page, and click on the 'Download' icon under the 'Actions' column. This will download a zip on your local computer that you can upload to the Nagios Exchange to share with the world!