Zabbix::Tiny Simple Usage

Zabbix::Tiny is a Perl module that I wrote to automate much of the boilerplate that I found myself writing when I wanted to script against the Zabbix API.  This article will take a brief look at exactly what advantages are provided by using Zabbix::Tiny.  Finally a  simple example script is provided, along with a step-by-step explanation of what it does.

An example Perl code that logs into Zabbix using Zabbix::Tiny module

Why Use Zabbix::Tiny?

Before delving into it’s usage, it seems a good idea to cover exactly what problems it solves:

  • Maintaining authorization credentials:  A client using the Zabbix API requires an authentication token (named auth) before it can access any data.  This token is obtained using the user.login method. It must then be retained and used in every subsequent API call.  Zabbix::Tiny will handle this automatically.
  • Generation of Request IDs:  JSON-RPC v2.0 (which the Zabbix API uses) contains an id parameter for each transaction.  Each transaction within a session should have a unique identifier (named id) that is used to correlate a response to its request.  In my experience the Zabbix API is rather permissive, and re-using the same value in subsequent requests did not cause a failure, however Zabbix::Tiny will still generate a new random string for each request for correctness.  This is done automatically, so there is no need to write any additional code.
  • Login:  Instantiation of the Zabbix::Tiny argument requires the Zabbix API URL, a username, and a password, and handles the login action – no manual call to user.login is ever needed.  Zabbix::Tiny will even delay the login action until an actual data call is made to the API.  In this way, you can write a script that creates the Zabbix:Tiny early on and data is only sent to the Zabbix API if needed.  Additionally, this allows for Zabbix::API to be used in long running (daemon) scripts, because it can re-login on an expired session.
  • Log out:  It’s easy to forget to log out, but it’s best practice to do so.  The destructor for the Zabbix::Tiny object calls the user.logout method for you automatically.
  • Data Serialization:  Conversion between Perl data structures and JSON is automatic.

Using Zabbix::Tiny

Below is a simple script that creates a Zabbix::Tiny object, and requests data for a single host using the Zabbix API’s host.get method.  The number of hosts returned is constrained to a single host by using the limit parameter.  Refer to the Perl and Zabbix API – Getting started article for an explanation of other modules used in this script, as well as how the credentials are loaded.

First, the configuration file:

[zab_cred]
url  = http://localhost/zabbix/api_jsonrpc.php
user = apiuser
pass = T0pS3cReT!

The configuration file just contains the information needed to log into the Zabbix API. Here’s the actual script:

#!/usr/bin/env perl
use Modern::Perl;
use Zabbix::Tiny;
use Config::Tiny;
use FindBin qw($Bin);
use Data::Dumper;

my $gbl_file = "$Bin/../globals.conf";
my $global = Config::Tiny->read($gbl_file);

my $zbx = Zabbix::Tiny->new(
    server   => $global->{zab_cred}->{url},
    password => $global->{zab_cred}->{pass},
    user     => $global->{zab_cred}->{user}
);

my $hosts = $zbx->do(
    'host.get',
    {
        monitored => 1,
        limit => 1
    }
);

print Dumper $hosts;

my $name = $hosts->[0]->{host};
say $name;

Before running the script, let’s look at a few things.  In lines 8 and 9 the global configuration file is read using Config::Tiny and stored in the variable $global.  In lines 11 through 15, the new method is used to create a Zabbix::Tiny object named $zbx.  From this point on, anytime a method or property of this object is needed, it will be called against $zbx.

During the creation of $zbx in lines 12 through 14, rather than assigning the values to scalar  variable ( like $password = $global->{zab_cred}->{pass}  ), and then using the scalar variable, the reference to the value in the configuration file is used directly.  I chose to use the reference here because it is the only time that these values will be used in this script, so it doesn’t make much sense to prepare a more abbreviated way of accessing them repeatedly.

It’s important to remember that Zabbix::Tiny doesn’t make a connection to the Zabbix API to login until it needs other data, so at this point in the script (line 16), a network connection to the Zabbix server has not yet been made.  This occurs in line 17 when the do method of $zbx is called.  The result of do is stored in the $hosts variable, then in line 25 the contents of $hosts are printed using Data::Dumper.

It’s important to note that $hosts will contain an array (a list) of hosts, even though only one host was requested (and returned).  In line 27, $hosts->[0]->{host} refers to the value of ‘host’ from record zero (the first record) in this list.  This value is assigned to $name, and in line 28 this value is printed with say (say prints the value followed by a new line).

Here are the results of running the script:

[ben:~/zabbix/scripts]$ ./ex1.pl
$VAR1 = [
          {
           'ipmi_authtype' => '-1',
           'ipmi_disable_until' => '0',
           'jmx_disable_until' => '0',
           'ipmi_username' => '',
           'tls_connect' => '1',
           'tls_accept' => '1',
           'maintenance_from' => '0',
           'tls_psk' => '',
           'disable_until' => '0',
           'ipmi_errors_from' => '0',
           'ipmi_password' => '',
           'description' => '',
           'snmp_error' => '',
           'proxy_hostid' => '0',
           'templateid' => '0',
           'error' => '',
           'ipmi_error' => '',
           'name' => 'www1',
           'maintenance_type' => '0',
           'lastaccess' => '0',
           'ipmi_privilege' => '2',
           'hostid' => '10143',
           'maintenanceid' => '0',
           'snmp_errors_from' => '0',
           'host' => 'Web Server 1',
           'tls_issuer' => '',
           'errors_from' => '0',
           'snmp_disable_until' => '0',
           'jmx_errors_from' => '0',
           'jmx_error' => '',
           'maintenance_status' => '0',
           'ipmi_available' => '0',
           'status' => '0',
           'tls_psk_identity' => '',
           'jmx_available' => '0',
           'snmp_available' => '0',
           'tls_subject' => '',
           'flags' => '0',
           'available' => '1'
          }
        ];
Web Server 1

Passing params to the do method

Before concluding this article, I wanted to take a look at how arguments are passed to the do method, because there are a few different ways to do this which will work, but there is an actual preferred syntax.  Here’s how it’s written (which is the preferred way):

my $hosts = $zabbix->do(
    'host.get',
    {
        monitored => 1,
        limit => 1
    }
);

The following will work as well, but is not preferred:

my $hosts = $zabbix->do(
    'host.get',
    monitored => 1,
    limit => 1
);

So, why is the first example preferred?  The second example is shorter, and is a bit easier to read, so why the first?

The difference lies in the fact that in the first example only two arguments are technically passed to  do:  The host.get method, and an anonymous hash reference containing the arguments.  The second example passes five arguments to do:  The host.get method, followed by monitored, 1, limit, and 1.  This was the original implementation of Zabbix::Tiny, but it turned out that this caused a problem because a few of the Zabbix API methods (such as map.delete) take an unnamed list of variables as arguments rather than key => value pairs.  When passing a list, it’s not possible for Zabbix::Tiny to determine if the values should be encoded to JSON as an (un-ordered) array, or as an associative array.  By using a reference, the data is already encoded – either in curly brackets as a hashref (associative array), or with square brackets as an arrayref (unnamed array).  The older syntax (the one in the second example) is maintained for backwards compatibility, but should not be used in new scripts.

2 thoughts on “Zabbix::Tiny Simple Usage”

Leave a Reply