The approaches we looked at earlier—direct database edits and XML import/export—were either risky or limited. Editing the database is risky because there is very little validation, and upgrading to a newer version of Zabbix can change the database schema, making our tools and approaches invalid. XML import/export was nice, but very limited—it did not allow modifying users, network discovery rules, actions lots, and lots of things in the Zabbix configuration.
This is where the Zabbix API could help. It is a JSON-based interface to Zabbix configuration and data. It offers way more functionality than XML import/export does, although there are still bits and pieces of configuration that cannot be controlled using it.
The Zabbix API currently is frontend based: it is implemented in PHP. To use it, we connect to the web server running the frontend and issue our requests. There are a lot of ways to do this, but here, we will try to do things in a manner that is language independent—we will use curl
and issue the requests from the shell.
The Zabbix API is request-response based. We send a request and get a response—either the data we requested or a success/failure indicator. Let's look at some simple, practical examples of what one can do with the API. We will use simple curl
requests to the API. Let's try this on the Zabbix server:
$ curl -s -X POST -H 'Content-Type: application/json-rpc' -d '' http://127.0.0.1/zabbix/api_jsonrpc.php
In this request, we use the POST
method and send the JSON string with the -d
parameter—empty for now. We also specify the -s
parameter, which enables silent or quiet mode and suppresses progress and error messages. The URL is the Zabbix API endpoint, api_jsonrpc.php
. This will be the same for all API requests. Additionally, we specify the content type to be application/json-rpc
. This is required. If omitted, the Zabbix API will return an empty response, which does not help much. The request we issued should return a response like this:
{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid Request.","data":"JSON-rpc version is not specified."},"id":null}
That did not work, but at least there's an error message. Let's proceed with more valid requests now.
One of the simplest things we can do is query the API for the Zabbix version. This will return the frontend version, which is considered to be the same as the API version. This is the only request that does not require being logged in, besides the login request itself.
To make it easier to edit and issue the requests, let's assign the JSON to a variable, which we will then use in the curl
command.
$ json='{"jsonrpc":"2.0","method":"apiinfo.version","id":1}'
We are using a method called apiinfo.version
. How to know which methods are available and what their names are? That information can be found in the Zabbix manual, and we will explore it a bit later. Let's send this request to the API now. API responses lack a trailing newline, and that might make them harder to read—let's also add a newline in the curl
command:
$ curl -s -w '
' -X POST -H 'Content-Type: application/json-rpc' -d "$json" http://localhost/zabbix/api_jsonrpc.php
Notice the use of the $json
variable in double quotes for the -d
parameter and the -w
parameter to add the newline. This command should return the API version:
{"jsonrpc":"2.0","result":"3.0.0","id":1}
The version of this instance is 3.0.0. What about the jsonrpc
and id
values? The jsonrpc
value specifies the JSON-RPC version itself. The Zabbix API uses version 2.0, so this will be the same in all requests and all responses. The id
value was specified by us in the request, and the response had the same value. It could be useful if we used a framework that allowed asynchronous requests and responses—that way, we could correlate the responses to requests. JSON also supports batching, where multiple requests can be sent in a single connection and responses can be matched by the ID, but this feature is currently broken in Zabbix 3.0.
Before one can perform any useful operations via the API, they must log in. Our JSON string would be as follows:
$ json='{"jsonrpc":"2.0","method":"user.login","id":2,"params":{"user":"Admin","password":"zabbix"}}'
Now, run the same curl
command we used to get the API version. In all further API requests, we will only change the json
variable and then reuse the same curl
command. In this case, assuming a correct username and password, it should return the following:
{"jsonrpc":"2.0","result":"df83119ab78bbeb2065049412309f9b4","id":2}
This response also has an alphanumeric string in the result
property, which is very important for all further work with the API. This is an authentication token or session ID that we will have to submit with all subsequent requests. For our tests, just copy that string and use it in the json
variable later.
Hosts may be enabled or disabled by setting a single value. Let's disable our IPMI host and re-enable it a moment later. To do this, we will need the host ID. Usually, when using the API, we'd query the API itself for the ID. In this case, let's keep things simple and look up the ID in the host properties— as with the item before, open the host properties and copy the value for the hostid
parameter from the URL. With that number available, let's set our JSON variable:
$ json='{"jsonrpc":"2.0","method":"host.update","params":{"hostid":"10132","status":1},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
Run the curl
command:
{"jsonrpc":"2.0","result":{"hostids":["10132"]},"id":1}
This should indicate success, and the host should be disabled—check the host state in the frontend. Enabling it again is easy, too:
$ json='{"jsonrpc":"2.0","method":"host.update","params":{"hostid":"10132","status":0},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
Run the curl
command again to re-enable this host.
Now on to creating a host using the API. Let's set our JSON variable:
$ json='{"jsonrpc":"2.0","method":"host.create","params":{"host":"API created host","interfaces":[{"type":1,"main":1,"useip":1,"ip":"127.0.0.2","dns":"","port":"10050"}],"groups":[{"groupid":"2"}],"templates":[{"templateid":"10104"}]},"auth": "df83119ab78bbeb2065049412309f9b4","id":1}'
In the default Zabbix database, the group ID of 2
should correspond to the Linux servers group, and the template ID of 10104
should correspond to the Template ICMP Ping template. If the IDs are different on your system, change them in this JSON string. Run the curl
command now, and the host should be created successfully:
{"jsonrpc":"2.0","result":{"hostids":["10148"]},"id":1}
As part of the response, we also got the ID of the new host. Feel free to verify in the frontend that this host has been created.
And the returned ID will be useful now. Let's delete the host we just created:
$ json='{"jsonrpc":"2.0","method":"host.delete","params":["10148"],"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
Run the curl
command again. The host should be successfully deleted.
{"jsonrpc":"2.0","result":{"hostids":["10148"]},"id":1}
Value maps could not be controlled via the API before Zabbix 3.0. They were needed for many templates, though, and people resorted to SQL scripts or even manually creating value maps with hundreds of entries. That's dedication. In Zabbix 3.0, things are much easier, and now, value maps are supported both in the API and XML import/export. Let's create a small value map:
$ json='{"jsonrpc":"2.0","method":"valuemap.create","params":{"name":"Mapping things","mappings":[{"value":"this","newvalue":"that"},{"value":"foo","newvalue":"bar"}]},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
Run the curl
command:
{"jsonrpc":"2.0","result":{"valuemapids":["16"]},"id":1}
If you check the new value map in the frontend, it is a bit easier to read than in that JSON:
We covered value maps in Chapter 3, Monitoring with Zabbix Agents and Basic Protocols.
The methods we have discussed so far mostly dealt with configuration. We may also query some historical data. For example, to grab item history data, we would need to know several things:
Both of these can be found out by opening the item properties in the configuration section—the ID will be in the URL, and the type of information will be in that dropdown. Why do we have to specify the type of information? Unfortunately, the Zabbix API does not look it up for us but tries to find the values only in a specific table. By default, the history_uint
(integer values) table is queried. To get the values for the CPU load item on A test host, the JSON string would look like this:
$ json='{"jsonrpc":"2.0","method":"history.get","params":{"history":0,"itemids":"23668","limit":3},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
Here are a couple extra parameters worth discussing here:
history
parameter tells the API which table to query. With 0
, the history
table is queried. With 1
, the history_str
table is queried. With 2
, the history_log
table is queried. With 3
, history_int
is queried (which was the default). With 4
, the history_text
table is queried. We must manually match this value to the setting in the item properties.limit
parameter limits the number of entries returned. This is quite useful here, as an item could have lots and lots of values. By the way, limit
is supported for all other methods as well—we can limit the number of entries when retrieving hosts, items, and all other entities.Now, run the curl
command:
{"jsonrpc":"2.0","result":[{"itemid":"23668","clock":"1430988898","value":"0.0000","ns":"215287328"},{"itemid":"23668","clock":"1430988928","value":"0.0000","ns":"221534597"},{"itemid":"23668","clock":"1430988958","value":"0.0000","ns":"229668635"}],"id":1}
We got our three values, but the output is a bit hard to read. There are many ways to format JSON strings, but in the shell, the easiest would be using Perl or Python commands. Rerun the curl
command and append to it | json_pp
:
$ curl … | json_pp
This will invoke the Perl JSON tool, where pp stands for pure Perl, and the output will be a bit more readable:
{ "jsonrpc" : "2.0", "id" : 1, "result" : [ { "clock" : "1430988898", "itemid" : "23668", "value" : "0.0000", "ns" : "215287328" }, { "ns" : "221534597", "value" : "0.0000", "itemid" : "23668", "clock" : "1430988928" }, { "value" : "0.0000", "ns" : "229668635", "clock" : "1430988958", "itemid" : "23668" } ] }
Alternatively, use python -mjsontool
, which will invoke Python's JSON tool module. That's a bit more typing, though.
In the output from the history.get
method, each value is accompanied with an item ID, UNIX timestamp, and nanosecond information, the same as the history tables we looked at earlier. That's not very surprising, as the API output comes from those tables. If we convert these values to human-readable format as discussed before by running date -d@<UNIX timestamp>
, we will see that they are not recent—actually, they are the oldest values. We can get the most recent values by adding the sortfield
and sortorder
parameters:
$ json='{"jsonrpc":"2.0","method":"history.get","params":{"history":0,"itemids":"23668","limit":3,"sortfield":"clock","sortorder":"DESC"},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
These will sort the output by the clock value in descending order and then grab the three most recent values—check the returned Unix timestamps to make sure of that. If there are multiple values with the same clock value, other fields will not be used for secondary sorting.
We can also retrieve trend data—a new feature in Zabbix 3.0:
$ json='{"jsonrpc":"2.0","method":"trend.get","params":{"itemids":"23668","limit":3},"auth":"df83119ab78bbeb2065049412309f9b4","id":1}'
The Zabbix API does not allow submitting historical data—all item values have to go through the Zabbix server using the zabbix_sender
utility, which we discussed in Chapter 11, Advanced Item Monitoring. There are rumors that the API might be moved to the server side, which might allow merging data-submitting in the main API.
The Zabbix API is really great, but there are a few issues with it worth knowing about:
host status
value to a completely bogus value, making that host disappear from the frontend, although no new host with that name could be created. Be very, very careful with the possibility of sending incorrect data to the Zabbix API. It might complain about that data, or it might just silently accept it and make some silly changes.incorrect parameters
for a long JSON input string.While we looked at a low-level API example, you are not likely to use shell scripts to work with the Zabbix API. The shell is not that well suited for working with JSON data even with extra tools, so another programming or scripting language might be a better choice. For many of those languages, one would not have to implement full raw JSON handling, as there are libraries available. At the time of writing this, a list of available libraries is maintained at http://zabbix.org/wiki/Docs/api/libraries. Alternatively, just go to http://zabbix.org and look for the Zabbix API libraries link.
All of these libraries are community supplied. There are no quality guarantees, and any bugs should be reported to the library maintainers, not to Zabbix.
For example, a Perl library called Zabbix::Tiny
aims to be a very simple abstraction layer for the Zabbix API, solving the authentication and request ID issues and other repetitive tasks when working with the API. It can be easily installed from the Comprehensive Perl Archive Network (CPAN):
# cpan Zabbix::Tiny
To create a new user, we would save the following in a file:
use strict; use warnings; use Zabbix::Tiny; my $zabbix = Zabbix::Tiny->new( server => http://localhost/zabbix/api_jsonrpc.php, password => 'zabbix', user => 'Admin', ); $zabbix->do( 'user.create', alias => 'new_user', passwd => 'secure_password', usrgrps => [ '13' ], name => 'New', surname => 'User', type => 3, );
This would create a new user. While most parameters are self-explanatory, the type
parameter tells the API whether this is a user, admin, or super admin. A value of 3
denotes the super admin user type. The group ID is hardcoded to 13
—that is something to customize. If the file we saved this in were called zabbix_tiny-add_user.pl
, we would call it like this:
$ perl zabbix_tiny-add_user.pl
While this might seem longer than our raw JSON string, it also deals with logging in, and it is easier to write than raw JSON. For more information on this particular Zabbix API library, refer to http://zabbix.org/wiki/Docs/howto/Perl_Zabbix::Tiny_API.
There are a lot of different Zabbix API libraries for various languages—Python alone has seven different libraries at the time of writing this. It can be a bit of a challenge to choose the best one.
If programming around a library is not your thing, there is also a Python-based project to create command line tools for API operations, called Zabbix Gnomes. It can be found at https://github.com/q1x/zabbix-gnomes.
We only covered a small portion of the Zabbix API in this chapter; there's lots and lots more. If you plan to use it, consult the official Zabbix manual for information on all the methods, their parameters, and object properties. At the time of this writing, the Zabbix API manual can be found at https://www.zabbix.com/documentation/3.0/manual/api—but even if that changes, just visit https://www.zabbix.com, and look for the documentation.