Zabbix’s API has the advantage of being both extremely flexible and extremely powerful. Scripts that leverage the API can address many of the perceived ‘short-comings’, or commonly requested features of Zabbix. I wrote the Zabbix::Tiny
module as a small interface to the API to abstract some of the boiler plate that I was repeating in each script I was writing without it. Rather than delve directly into the module and it’s uses, I wanted to first cover a few of the dependencies I rely on for (nearly) every script that I write using the Zabbix API. Any articles that I write in the future will consider these points as implied.

Shebang and Modern::Perl
As a she-bang line, I prefer #!/usr/bin/env perl
to something like #!/usr/bin/perl
primarily because as a FreeBSD user the correct path is /usr/local/bin/perl
, so the former example enhances portability.
“Modern Perl” can mean several things. It can be referring to a general philosophy of current Perl best practices. It’s also the title of a (highly recommended) book and website that champions these practices. It is also the name of a specific Perl module that will set a few simple parameters in a script.
It’s the third usage, the module, that is relative here. In a nutshell it’s like use strict;
, use warnings;
, and use 5.010;
reduced to a single line. Combining the shebang and Modern::Perl, means that every script I write starts like this:
#!/usr/bin/env perl use Modern::Perl;
CPAN and cpanminus
CPAN is the Comprehensive Perl Archive Network. It is one of the largest collections of free software libraries in the world, and is the general standard for distribution of modules for Perl. Cpanminus is a simplified minimalist interface for installing modules from CPAN. As an example, Modern::Perl is not included with perl. It’s a module that can be installed from the CPAN using cpanminus (or other CPAN client if you prefer). It’s quite simple:
#> cpanminus Modern::Perl
Note that there’s still plenty of additional caveats. You’ll need root or sudo if installing modules globally, and perlbrew or local::lib if not. Some distributions favor their own package management systems, especially for modules that are used in core components of the distribution. The aforementioned perlbrew can address this. I would (again) recommend the Modern Perl book (it’s free!) as a resource for more information.
Zabbix::Tiny
As mentioned above, is a module that I wrote which eliminates some of the repetitive tasks and monotonous code writing when using Perl to interface with the Zabbix API. This module is also available on CPAN. To install it:
#> cpanminus Zabbix::Tiny
Because I use this module for every script I write that interacts with the Zabbix API, these scripts always begin like this:
#!/usr/bin/env perl use Modern::Perl; use Zabbix::Tiny;
File Hierarchy
I tend to keep my scripts in a single directory, and then use git and GitLab (GitLab offers free private repositories) to provide version control as well as a rudimentary method of sharing these scripts between hosts. Even though GitLab offers private repositories, I really do not want credentials pushed there – ever. Additionally, I may use the same script against more than one Zabbix server, and not want to have different branches, etc. for each server URL. To address this, I’ll use configuration files. Here’s the directory hierarchy I use to address this. Assume that my base directory is /usr/home/ben/
, I’ll have the following:
A configuration file that holds user credentials, Zabbix server URL(s), and anything else I either want to keep private, or would use in more than one script, /usr/home/ben/globals.conf
I also have a directory that I’ll use to contain my scripts. This is the directory that I’ll track with git.
#> ls /usr/home/ben/scripts/ .git aggregate_items.pl ex1.pl .gitignore conf/ ex2.pl
Within the conf/
directory, I’ll have a configuration file for each script (if it needs one):
#> ls /usr/home/ben/scripts/conf/ ex1.conf ex2.conf ex1.conf.dist ex2.conf.dist
The .dist
files are just example files showing the options for the script. There is an entry for conf/*.conf
in my .gitignore
files so that the actual configuration files don’t get tracked with git, and thus don’t clobber actual script configurations when I pull changes from GitLab.
Config::Tiny
OK – I’ve got configuration files, but how do I read them? Config::Tiny is a module that reads (and writes) .ini style configuration files. I generally use two files per script – global configuration and per-script configuration. Here’s an example of how these look:
#> cat /usr/home/ben/globals.conf [zabbix] url=https://zabbix.domain.lan/zabbix/api_jsonrpc.php user = apiuser pass = supersecret #> cat /usr/home/ben/scripts/conf/ex1.conf [email] to = ben@domain.lan from = zabbix@domain.lan cc = someone@domain.lan
Config::Tiny can then be used to set the values into the file in the following manner. Note: since this script doesn’t connect to the Zabbix API, there’s no need to use Zabbix::Tiny
#!/usr/bin/env perl use Modern::Perl; use Config::Tiny; ## Set the filenames as variables my $gbl_file = "/usr/home/ben/globals.conf"; my $conf_file = "/usr/home/ben/scripts/conf/ex1.conf"; ## Use Config::Tiny to read the config files my $global = Config::Tiny->read($gbl_file); my $conf = Config::Tiny->read($cnf_file); ## Assign these to easier to us scalar variables my $url = $global->{zabbix}->{url}; my $user = $global->{zabbix}->{user}; my $pass = $global->{zabbix}->{pass}; my $to = $conf->{email}->{to}; my $from = $conf->{email}->{from}; ## Do something with the variables say "Log into $url as $user"; say "Mail $to from $from"; ## Or use the Config::Tiny hashref directly, too. say "Copy: " . $conf->{email}->{from};
This will produce the following when run:
#> ./ex1.pl Log into https://zabbix.atgncloud.com/api_jsonrpc.php as apiuser Mail ben@domain.lan from zabbix@domain.lan Copy: zabbix@domain.lan
FindBin
FindBin is a Perl core module – this means that you don’t have to install it from CPAN, but you still have to declare use FindBin; in your script. FindBin can be used to find the original directory of the perlscript. This is useful when your configuration file is in a sub directory relative path from your script. For example, if I moved all of these files to a different user directory (/usr/home/whosgonna/
for example), the configuration files would fail to load because they have a hard coded path. The file can be updated to use FindBin and keep relative paths this way. Changes between the previous example and this in bold text:
#!/usr/bin/env perl use Modern::Perl; use Config::Tiny; use FindBin qw($Bin); ## Set the filenames as variables my $gbl_file = "$Bin/../globals.conf"; my $conf_file = "$Bin/conf/ex1.conf"; ## Use Config::Tiny to read the config files my $global = Config::Tiny->read($gbl_file); my $conf = Config::Tiny->read($cnf_file); ## Assign these to easier to us scalar variables my $url = $global->{zabbix}->{url}; my $user = $global->{zabbix}->{user}; my $pass = $global->{zabbix}->{pass}; my $to = $conf->{email}->{to}; my $from = $conf->{email}->{from}; ## Do something with the variables say "Log into $url as $user"; say "Mail $to from $from"; ## Or use the Config::Tiny hashref directly, too. say "Copy: " . $conf->{email}->{from};
Data::Dumper
Data::Dumper can print out a Perl data structure, making it invaluable for troubleshooting and development purposes. While most of the scripts that I use don’t require Data::Dumper when complete, in many cases it’s used while writing the script to make sure that the data received is correct. Updating the same script as before:
#!/usr/bin/env perl use Modern::Perl; use Config::Tiny; use FindBin qw($Bin); use Data::Dumper; ## Set the filenames as variables my $gbl_file = "$Bin/../globals.conf"; my $conf_file = "$Bin/conf/ex1.conf"; ## Use Config::Tiny to read the config files my $global = Config::Tiny->read($gbl_file); my $conf = Config::Tiny->read($cnf_file); ## Assign these to easier to us scalar variables my $url = $global->{zabbix}->{url}; my $user = $global->{zabbix}->{user}; my $pass = $global->{zabbix}->{pass}; my $to = $conf->{email}->{to}; my $from = $conf->{email}->{from}; ## Do something with the variables say "Log into $url as $user"; say "Mail $to from $from"; ## Or use the Config::Tiny hashref directly, too. say "Copy: " . $conf->{email}->{from}; ## Show the data struture of $conf print Dumper $conf;
Now the script will do the following. I’ve reduced some of the indentation from Data::Dumper to allow the text to better fit the page:
#> ./ex1.pl Log into https://zabbix.atgncloud.com/api_jsonrpc.php as apiuser Mail ben@domain.lan from zabbix@domain.lan Copy: zabbix@domain.lan $VAR1 = bless( { 'email' => { 'from' => 'zabbix@domain.lan', 'to' => 'ben@domain.lan', 'cc' => 'someone@domain.lan' } }, 'Config::Tiny' );
A few other useful Modules
The above modules and pragmas are in all but the most trivial scripts that I use when connecting to the Zabbix API. There are a few other modules that I commonly use depending on the intent of the script. In no particular order:
Log::Log4perl – I also use this in nearly every non-trivial script. It’s somewhat complex and doesn’t directly impact these scripts, so I’ve omitted it from these examples.
MIME::Lite::TT::HTML – This module can be used to send html (and text) emails using template toolkit for formatting.
DBI – This is the Perl module for abstraction of database access. Generally speaking, you should not be accessing the Zabbix database directly, but I find frequently I’m cross referencing other databases against information in Zabbix.
DateTime – Correct handling of date and time in Perl, including calculation and other datetime math.
List::Util – Contains functions for getting maximum, minimum, sum, product, etc from a list of values.
Summary Script Skeleton
As a summary, here’s a skeleton of what I’d use for scripts using the Zabbix API.
#!/usr/bin/env perl use Modern::Perl; use Zabbix::Tiny; use Config::Tiny; use FindBin qw($Bin); use Data::Dumper; my $gbl_file = "$Bin/../global_configs.conf"; my $global = Config::Tiny->read($gbl_file); my $zabbix = Zabbix::Tiny->new( server => $global->{zabbix}->{url}, password => $global->{zabbix}->{pass}, user => $global->{zabbix}->{user} );
3 thoughts on “Perl and Zabbix API – Getting Started”