NAME

Zabbix::API -- Access the JSON-RPC API of a Zabbix server

SYNOPSIS

use Zabbix::API;

my $zabbix = Zabbix::API->new(server => 'http://example.com/zabbix/api_jsonrpc.php',
                              verbosity => 0);

eval { $zabbix->login(user => 'calvin',
                      password => 'hobbes') };

if ($@) { die 'could not authenticate' };

my $items = $zabbix->fetch('Item', params => { search => { ... } });

DESCRIPTION

This module manages authentication and querying to a Zabbix server via its JSON-RPC interface. (Zabbix v1.8+ is required for API usage; prior versions have no JSON-RPC API at all.)

What you need to start out is probably the fetch method in Zabbix::API; be sure to check out also what the various Zabbix::API::Foo classes do, as this is how you'll be manipulating the objects you have just fetched.

Finally, there are examples in the examples/ folder (well, at least one) and in the unit tests.

METHODS

new(server => URL, [verbosity => INT], [env_proxy => BOOL])

This is the main constructor for the Zabbix::API class. It creates a LWP::UserAgent instance but does not open any connections yet. env_proxy is passed to the LWP::UserAgent constructor, so if it is set to a true value then the UA should follow $http_proxy and others.

server is misleading, as the URL expected is actually the whole path to the JSON-RPC page, which usually is http://example.com/zabbix/api_jsonrpc.php.

Returns an instance of the Zabbix::API class.

login(user => STR, password => STR)

Send login information to the Zabbix server and set the auth cookie if the authentication was successful.

Due to the current state of flux of the Zabbix API, this may or may not work depending on your version of Zabbix. user.authenticate is marked as having been introduced in version 1.8; so is user.login, which deprecates authenticate. Our method uses login. Version 1.8.4 is confirmed as working with login.

logout()

Try to log out properly. Unfortunately, the user.logout method is completely undocumented and does not appear to work at the moment (see the bug report here: https://support.zabbix.com/browse/ZBX-3907). Users of this distribution are advised not to log out at all. They will not be able to log back in until the server has decided their ban period is over (around 30s). Furthermore, another bug in Zabbix (resolved in 1.8.5) prevents successful logins to reset the failed logins counter, which means that after three (possibly non-consecutive) failed logins every failed login triggers the ban period.

The test suite logs in and out once per test file. The logout method does not work. There are more than three test files. Do the math :(

raw_query(method => STR, [params => HASHREF])

Send a JSON-RPC query to the Zabbix server. The params hashref should contain the method's parameters; query parameters (query ID, auth cookie, JSON-RPC version, and HTTP request headers) are set by the method itself.

Return a HTTP::Response object.

If the verbosity is set to 1, will print the HTTP::Response to STDOUT. If set to 2, will print the Data::Dumper output of same (it also contains the HTTP::Request being replied to).

If the verbosity is strictly greater than 0, the internal LWP::UserAgent instance will also print HTTP request progress.

query(method => STR, [params => HASHREF])

Wrapper around raw_query that will return the decoded result data instead.

api_version

Query the Zabbix server for the API version number and return it.

fetch(CLASS, [params => HASHREF])

This method fetches objects from the server. The PARAMS hashref should contain API method parameters that identify the objects you're trying to fetch, for instance:

$zabbix->fetch('Item', params => { search => { key_ => 'system.uptime' } });

The default value of PARAMS is an empty hashref, which should mean "fetch every object of type CLASS".

The method delegates a lot of work to the CLASS so that it can be as generic as possible. Any CLASS name in the Zabbix::API namespace is usable as long as it descends from Zabbix::API::CRUDE (to be precise, it should implement a number of methods, some of which CRUDE implements, some of which are provided by specialized subclasses provided in the distribution). The string Zabbix::API:: will be prepended if it is missing.

Returns an arrayref of CLASS instances.

fetch_single(CLASS, [params => HASHREF])

Like fetch, but also checks how many objects the server sent back. If no objects were sent, returns undef. If one object was sent, returns that. If more objects were sent, throws an exception. This helps against malformed queries; Zabbix tends to return all objects of a class when a query contains strange parameters (like "searhc" or "fliter").

useragent

Accessor for the LWP::UserAgent object that handles HTTP queries and responses. Several useful options can be set: timeout, redirects, etc.

verbosity([VERBOSITY])

Mutator for the verbosity level.

Implemented verbosities so far are 0, 1 and 2, where:

0

does not emit any messages,

1

prints out the LWP::UserAgent progress messages and the responses sent by the Zabbix server,

2

prints out the LWP::UserAgent progress messages and dumps to stdout (via Data::Dumper) the queries sent to the server and the responses received.

LOW-LEVEL ACCESS

A few methods are not intended for general consumption, but you never know. Plus it gives me a space to document them and raises POD coverage.

reference(OBJECT)

"Indexes" the object in a local stash. The fetch method (and the objects' pull) plugs into this so that you have only one real object, and modifying a host directly and modifying an item's host (via ->host is the same thing.

dereference(OBJECT)

Removes the object's index in the local stash. This is called by the objects' delete method.

refof(OBJECT)

Returns the correct reference to an object fetched from the server; in other words, looks in the stash for an object that has the same id. This is used in indexing objects, to ensure that the stashed objects are updated instead of just creating doubles.

stash([STASH])

Mutator for the local stash (a hashref of type => id => object).

Several attributes are available if you want to dig into the class' internals, through the standard blessed-hash-as-an-instance mechanism. Those are:

server

A string containing the URL to which JSON-RPC queries should be POSTed.

verbosity

Verbosity level. So far levels 0 to 2 are supported (i.e. do something different).

A string containing the current session's auth cookie, or the empty string if unauthenticated.

env_proxy

Direct access to the LWP::UserAgent initial configuration regarding proxies. Setting this attribute after construction does nothing.

BUGS AND MISSING FEATURES

THE GREAT RACE CONDITION

Consider the following:

my $host = $zabbix->fetch('Host', params => ...);

my $same_host = Zabbix::API::Host->new(root => $zabbix,
                                       params => same...);

$same_host->push;

is_deeply($host, $same_host); # yup
isnt($host, $same_host); # also yup

This means you can change the attribute A in $host and push it, and it will change on the server; then you can change some other attribute B in $same_host and push it, and it will change on the server... and attribute A will be changed back to its old value before you changed it in $host since $host and $same_host are different references to different objects and don't know about each other! Of course this is also true if someone else is fiddling with the hosts directly on the web interface or in any other way.

To work around this, you have to pull() just before you start changing things. Currently Zabbix::API does its best to return existing references when you fetch() from the server; ideally $host and $same_host would also point to the same object, but they don't.

MOOSE, ABSENCE OF

The distribution doesn't use Moose, because it was written with light dependencies in mind. This is actually a problem in that I do not have the time to write proper accessors to cover all types of manipulations one might expect on, for instance, a graph's items. Hence to push (in the stack sense) a new item into a graph's list of items, you have to use the push builtin on the dereferenced items mutator, instead of writing something like

$graph->items->push($foo);

which would be easy to allow with Moose traits. Plus, I had to write boilerplate validation code, which would have been taken care of by Moose at least where types and type coercions are concerned.

It is quite slow. The server itself does not appear to be lightning fast; at least a recent Zabbix (1.8.5) on a Debian squeeze VM takes a couple seconds to reply to even trivial JSON-RPC queries. This is compounded by the fact that Zabbix::API is being extra paranoid about default values and name/id collisions and fetches data maybe more often than necessary, for instance immediately before and after a push().

Several types of objects are not implemented in this distribution; feel free to contribute them or write your own distribution (see Zabbix::API::CRUDE for the gory API details).

The logout business.

SEE ALSO

The Zabbix API documentation, at http://www.zabbix.com/documentation/start

LWP::UserAgent

AUTHOR

Fabrice Gabolde <fabrice.gabolde@uperto.com>

COPYRIGHT AND LICENSE

Copyright (C) 2011 SFR

This library is free software; you can redistribute it and/or modify it under the terms of the GPLv3.

2 POD Errors

The following errors were encountered while parsing the POD:

Around line 482:

Expected text after =item, not a number

Around line 487:

Expected text after =item, not a number