12. 06. 2017 Davide Bizzarri NetEye, Unified Monitoring

How to extend or modify the APIs

NetEye API

Introduction

The NetEye APIs offer a simple way to automate and script common processes on NetEye. They expose more than 150 objects written in Perl, which can be easily used and extended. The NetEye APIs allow you to perform several actions: add/modify/remove a host, service or business process from Nagios, as well as compute the availability of these objects over a given period of time. The APIs are open source, and you can find the Perl code installed at /var/lib/neteye/API. However, if you modify your code locally, your changes will be overwritten at the next API update. In this article I will show you how to do make your changes to the NetEye APIs persist across updates. 

Prerequisites

  • Knowledge of Perl
  • Knowledge of NetEye and its standard functions
  • A NetEye installation

This guide has been tested on NetEye 3.9. It may also be possible to use this method with older or newer versions, but we can’t yet guarantee it.

A simple script

Let’s start with this script that lists each service of the type neteye and the command that is launched for each Nagios service.

use warnings;
use strict;

use NetEye::Config;
use NetEye::Monitoring::Host;

# Create the NetEye Config Object
# this object manages the entire configuration of NetEye and for
# this reason it is required by many other objects
my $ConfigObject = NetEye::Config->new(
        AutoPersist => 0
);

# Search for the host with the name 'neteye' and return the object representing the host
my $NetEyeHost = NetEye::Monitoring::Host->new(
        ConfigObject => $ConfigObject 
)->searchForObject(
        Properties => { name => 'neteye' }
);

# Retrieve all services on the host neteye
# services is an array of service objects
my $Services = $NetEyeHost->getServices();

# Loop inside all services
for my $Service ( @{$Services} ) {

        # Retrieve the ServiceName object of the actual Service
        my $ServiceName = $Service->getServiceName();

        # Print in a line the name of the Host, the name of the Service and the command of the Service
        printf("Host: %s, Service: %s, Command: '%s'\n", $NetEyeHost->get('name'), $ServiceName->get('name'), $Service->get('command_line') // '');
}

1;

When we execute the script, the result should look similar to this:

$ perl ListHostServices.pl
Host: neteye, Service: Local_NetEye_Hardware_Status, Command: ''
Host: neteye, Service: Local_NetEye_Service_Status, Command: ''
Host: neteye, Service: Local_PerfData_Freschness, Command: 'check_perfdata!-c 500 -R -C'
Host: neteye, Service: Local_Total_Processes, Command: 'check_local_procs!150!200!RSZDT'
Host: neteye, Service: SMSD_Fileage, Command: 'check_file_age!30!180!/var/log/smstools.log'
Host: neteye, Service: SMSD_Process_running, Command: 'check_procs_process!2:2!2:2!smsd'
Host: neteye, Service: SMSD_SMS_QUEUE, Command: ''
Host: neteye, Service: SMSD_Modem_Status, Command: 'check_modem_smst! '
Host: neteye, Service: OCSNG_Duplicate_Hosts, Command: 'check_ocs_inventory!duplicates -x "localhost"'
Host: neteye, Service: OCSNG_Outdated_Items, Command: 'check_ocs_inventory!age -w 30 -c 90'

As you can see above, the NetEye APIs don’t have to be included as they are added automatically. This happens because the environment variable PERL5LIB includes the absolute path to the NetEye APIs. If you want to verify this, you can run the env command in a Linux shell on NetEye:

$ env
HOSTNAME=host
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
PERL5LIB=/var/lib/neteye/API/perl
...

Adding a new method to the host object

As mentioned before we cannot directly modify the host object on /var/lib/neteye/API/perl/NetEye/Monitoring/Host.pm because it would be overwritten at the next update. To modify it persistently we need to create a new file in /var/lib/neteye/API/perl/Extend/Monitoring/Host.pm. (If the Extend and Monitoring directories do not exist, we first need to create them.) Then we add the following lines to the file Host.pm:

package NetEye::Monitoring::Host;

sub getServiceNames {
        my ( $Self ) = @_;

        my @ServiceNames;
        my $Services = $Self->getServices();

        for my $Service ( @{$Services} ) {
                push @ServiceNames, $Service->getServiceName();
        }

        return \@ServiceNames;
}

1;

In the first row we’ve written package NetEye::Monitoring::Host even though the file is located in Extend/Monitoring/Host.pm. In this way we tell Perl that all functions in Extend/Monitoring/Host.pm are part of the module NetEye::Monitoring::Host.
We then create a new but very similar script with the following content:

use warnings;
use strict;

use NetEye::Config;
use NetEye::Monitoring::Host;

# Include the file Extend/Host.pm to extend NetEye::Monitoring::Host
use Extend::Monitoring::Host;

my $Config = NetEye::Config->new(
        AutoPersist => 0
);

my $NetEyeHost = NetEye::Monitoring::Host->new(
        ConfigObject => $Config
)->searchForObject(
        Properties => { name => 'neteye' }
);

my $ServiceNames = $NetEyeHost->getServiceNames();

for my $ServiceName ( @{$ServiceNames} ) {

        printf("Host: %s, Service: %s\n", $NetEyeHost->get('name'), $ServiceName->get('name'));
}

1;

Overwriting a method of the host object

Let’s assume that we want the method getServices() in Host to return just those services that have a command (Param command_line). To do so we can create a new method that filters the services returned from getServices(), but we can also overwrite the method getServices() so that it returns just the filtered services. (The second option is not recommended, but there might be situations in which it is necessary to do so anyway.)
To do this we need to go back to the file Extend/Monitoring/Host.pm and modify it in this way:

package NetEye::Monitoring::Host;

sub getServices {
    my ( $Self, %Param ) = @_;

        my $ServiceHelper = NetEye::Monitoring::Service->new(
                ConfigObject => NetEye::Config->new( AutoPersist => 0 ),
        );

        my @Services = $ServiceHelper->searchFor(
                Properties => { 'host_id' => $Self->getId(), },
        );

        my @FilteredServices;
        for my $Service ( @Services ) {
                if ( $Service->get('command_line') ) {
                        push @FilteredServices, $Service;
                }
        }

        return \@FilteredServices;
}

1;

Now let’s get back to the first script that we created by adding the module Extend::Monitoring::Host. The result will look like this:

use warnings;
use strict;

use NetEye::Config;
use NetEye::Monitoring::Host;
use Extend::Monitoring::Host;

my $Config = NetEye::Config->new(
        AutoPersist => 0
);

my $NetEyeHost = NetEye::Monitoring::Host->new(
        ConfigObject => $Config
)->searchForObject(
        Properties => { name => 'neteye' }
);

my $Services = $NetEyeHost->getServices();

for my $Service ( @{$Services} ) {

        my $ServiceName = $Service->getServiceName();

        printf("Host: %s, Service: %s, Command: '%s'\n", $NetEyeHost->get('name'), $ServiceName->get('name'), $Service->get('command_line') // '');
}

1;

Let’s run it. Now the result will be:

$ perl ListHostServices.pl
Host: neteye, Service: HTTP, Command: 'check_http!-a $USER3$'
Host: neteye, Service: Local Disks Free Space, Command: 'check_local_disk!20%!10%'
Host: neteye, Service: PING, Command: 'check_ping!100.0,20%!500.0,60%'
Host: neteye, Service: MYSQL, Command: 'check_mysql!-uroot'
Host: neteye, Service: Local LOAD, Command: 'check_local_load!8,7,6!12,11,10'
Host: neteye, Service: Local Uptime, Command: 'check_local_uptime!15! '
Host: neteye, Service: Local_LoggedIn_Users, Command: 'check_local_users!10!20'

In contrast to the first time, you can see that now just the services that issued a command are printed (and those that do not have one are not shown).

Conclusion

There are many ways to achieve the same result, but in this article we wanted to show you the easiest.

Davide Bizzarri

Davide Bizzarri

R&D Software Engineer at Würth Phoenix
Hi, I'm Davide! I’m a full stack developer at Würth Phoenix. I started to use a PC at the age of ten when my parents bought our first family PC: an old Windows 98. Then, in high school, my professor introduced me to the world of software development by teaching me my first programming language, C. Since then I began to study IT and programming languages alone. After one year, I started to develop my first website that reached over one thousand views per day. Once I finished high school, I changed my job twice, until Würth Phoenix has hired me. Here I have learned many interesting things, one of the most important once is the agile development methodology which we living every day.

Author

Davide Bizzarri

Hi, I'm Davide! I’m a full stack developer at Würth Phoenix. I started to use a PC at the age of ten when my parents bought our first family PC: an old Windows 98. Then, in high school, my professor introduced me to the world of software development by teaching me my first programming language, C. Since then I began to study IT and programming languages alone. After one year, I started to develop my first website that reached over one thousand views per day. Once I finished high school, I changed my job twice, until Würth Phoenix has hired me. Here I have learned many interesting things, one of the most important once is the agile development methodology which we living every day.

Leave a Reply

Your email address will not be published. Required fields are marked *

Archive