Chapter 9. Extending Zabbix

Understanding the Zabbix monitoring protocol allows us to write scripts, agents, and custom probes. In other words, it allows us to freely extend Zabbix's monitoring capabilities by expanding its means to collect data.

When it comes to actually controlling and administrating its monitoring objects, though, the only point of access that we have mentioned until now is the web frontend. Whether you need to add a user, change the sampling frequency of an item, or look at historical data, you always need to use the frontend as a user interface.

This is certainly a convenient solution for day-to-day activities as all you need to have is access to a simple browser. The frontend itself is also quite powerful and flexible as you can conveniently perform mass operations on many objects of the same type and control different proxies from the same spot.

On the other hand, not every large and complex operation can be performed conveniently through a web application, and sometimes, you don't need to just visualize data, but you need to export it and feed it to other programs in order to further analyze it. This is where the Zabbix API comes in. As you will learn in this chapter, Zabbix's JSON-RPC API provides all the functions available to the frontend, including user management, monitoring configurations, and access to historical data.

In the following pages, we will cover the following topics:

  • Writing code to connect to the API and make queries through it
  • Creating custom operations to manage your installation
  • Writing complex and conditional mass operations
  • Exporting monitoring data in a number of different formats

Let's start with a look at the general API architecture and the way to set up your code in order to interact with it.

Exploring the Zabbix API

Zabbix provides an entry point to interact with, manipulate, configure, and create objects in Zabbix. This API is available through its PHP frontend at http://<your-zabbix-server>/zabbix/api_jsonrpc.php.

The communication protocol is JSON-based, and the medium used is obviously HTTP/HTTPS.

Zabbix's JSON-RPC API provides a nice interface and exposes a lot of functionalities. Once authenticated, it will allow you to perform any kind of operation on Zabbix objects. Now, if you need to configure Zabbix in a large or very large network, this Zabbix API can be really useful. As a practical example, you can consider that you may need to add a large number of devices that, most probably, are already defined in a separate document. The API provides the entry point to add all of them in Zabbix by simply using a dedicated script.

The Zabbix API was introduced with Zabbix Version 1.8 and went through changes up until the current Version 2.4. This version can be considered more stable and mature, but it is still officially in the draft state, so things may change a little in the future versions. This does not mean that it's not suitable for a production environment; on the contrary, the bigger the installation, the more beneficial can be the usage of the API to script for complex and time-consuming operations.

The following code is a simplified JSON request to the Zabbix API:

{
  "jsonrpc": "2.0",
  "method": "method.name",
  "params": {
    "param_1_name": "param_1_value",
    "param_2_name": "param_2_value"
  },
  "id": 1,
  "auth": "159121ba47d19a9b4b55124eab31f2b81"
}

The following points explain what the preceding lines of code represent:

  • "jsonrpc": "2.0": This is a standard JSON PRC parameter that is used to identify the protocol version; this will not change across your requests.
  • "method": "method.name": This parameter defines the operation that should be performed; for instance, it can be host.create or item.update.
  • "params": This specifies the parameter needed by the method in JSON. Here, if you want to create an item, the most common parameters will be "name" and "key_".
  • "id": 1: This field is useful to tie a JSON request to its response. Every response will have the same "id" provided in the request. This "id" is useful when you are going to send multiple requests at once if those requests don't need to be serialized or be sequential.
  • "auth": "159121ba47d19a9b4b55124eab31f2b81": This is the authentication token used to identify an authenticated user; for more details, refer to the next section.

Note

For a detailed description of all the possible parameters and methods, refer to the official Zabbix documentation available at https://www.zabbix.com/documentation/2.4/manual/appendix/api/api.

Now, it is important to remember that the whole communication usually is on HTTP. This is something to consider if we interact with Zabbix from our workstation or from a different network location. To interact with the Zabbix API, the first thing you need is authentication by the server, and here, it is clear how important it is to have the whole communication encrypted and to use a secured channel. There are two different exposures for you to consider:

  • Use https instead of http; otherwise, the whole authentication will be in the clear format and readable
  • Be aware of the sensitivity of the data being transmitted

Now, it is time to perform the first step here with the API. The step you can do is ask the version after the authentication.

First steps through the API

The first thing we can do is start interacting with the Zabbix API. Since the API requires POST to better understand the protocol, we will use curl.

With curl, you can quickly and easily transfer data from/to a service using different protocols, and here, we use HTTP in this first example; even if the channel is not secure, it is not a problem as we're simply asking the Zabbix version and as we are not yet logging in or receiving sensitive data.

$ curl --include --netrc --request POST --header "Content-Type: application/json"  http://127.0.0.1/zabbix/api_jsonrpc.php –d @-

Between the options, we set the Content-Type header as JSON and enable curl to receive data from the standard input with -d@-. Once this is done, paste the following JSON envelope:

{
"jsonrpc":"2.0",
"method":"apiinfo.version",
"id":1,
"auth":null,
"params":{}
}

Take care to close the standard input with Crtl + D.

Now, let's see the response:

HTTP/1.1 200 OK
Date: Sat, 04 Jul 2015 06:32:36 GMT
Server: Apache/2.2.15 (CentOS)
X-Powered-By: PHP/5.3.3
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST
Access-Control-Max-Age: 1000
Content-Length: 41
Connection: close
Content-Type: application/json

{"jsonrpc":"2.0","result":"2.4.5","id":1}

After the standard HTTP header of the response, we can see the result of our query, that is, the Zabbix version "result":"2.4.5".

Tip

Please bear in mind that the apiinfo.version method has been introduced with Zabbix 2.0.4. If you're working with an old version of Zabbix, it might not be supported.

Authenticating through the API

Here, we discuss an example in a nutshell because this will show us how simple communication is; later, we will analyze an example with Python since it is widely used for rapid application development.

To test the authentication from our shell, we can use curl once again. Here, since we are going to authenticate our application to the Zabbix server, it is important to use a secured connection and then https. For this test, you can log on to your Zabbix server and write the following command:

$ curl --insecure --include --netrc --request POST --header "Content-Type: application/json" https://127.0.0.1/zabbix/api_jsonrpc.php –d@-

Note that --insecure specifies to curl not to verify the server certificate. This option produces a less secure connection, but since we are the localhost, it is acceptable and will avoid a lot of certificate issues. Working on a practical example without --insecure, curl will respond with the following error:

curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html

Once this command is run, you can paste the following JSON envelope:

{
"jsonrpc": "2.0",
"method": "user.login",
"params": {
"user": "Admin",
"password": "my secret password"
},
"auth": null,
"id": 0
}

Take care to replace the "password" properties with your own password, and then you can close the standard input using Crtl + D.

curl will take care to manage the whole HTTPS connection and will return the server's full HTTP response. In this case, we are interested in the authentication token that follows the standard web server response:

HTTP/1.1 200 OK

The remaining output is as follows:

Content-Type: application/json
{"jsonrpc":"2.0","result":"403bbcdc3c01d4d6e66f68f5f3057c3a","id":0}

This response contains the token that we need to use for all the following queries on the Zabbix server.

Note

The token will expire according to the auto-logout option set for the user who is authenticating.

Now, to see how all this work, we can use curl again:

# curl --insecure --include --netrc –request POST --header "Content-Type: application/json" https://127.0.0.1/zabbix/api_jsonrpc.php –d @-

In this example, we are going to ask our server about the last history value for the Processor load (15 min average per core) item. In this particular case, on this server, the JSON envelope will be composed as follows:

{ "jsonrpc": "2.0",
    "method": "history.get",
    "params": {
        "output": "extend",
        "history": 0,
        "hostids": "10096",
         "itemid": "23966",
        "sortfield": "clock",
        "sortorder": "DESC",
        "limit": 1
    },
    "auth": "403bbcdc3c01d4d6e66f68f5f3057c3a",
    "id": 1
}

Remember that the request must contain the authentication token previously obtained using the "user.authenticate" method.

Tip

Most of the APIs contain at least four methods: get, create, update, and delete, but please be aware that certain APIs may provide a totally different set of methods.

The server response in this case is the following:

HTTP/1.1 200 OK

{"jsonrpc":"2.0",
"result":[
{"hosts":
[{"hostid":"10096"}],
"itemid":"23840",
"clock":"1381263380",
"value":"0.1506",
"ns":"451462502"}
],"id":1}

In this example, you have seen a way to use the authentication token to query the historical data for a particular host/item. Of course, shell scripting is not the best method to interact with the Zabbix API because it requires a lot of coding to manage the "auth" token and it is better to use something more user friendly.

Using the PyZabbix library

Now that we have a clear understanding of the API's architecture and its JSON-RPC protocol, we can move beyond the manual construction of the JSON objects and rely on a dedicated library. This will allow us to focus on the actual features of the API and not on the specifics of the implementation.

There are quite a few Zabbix API libraries available for different languages, but the one we'll use for the rest of the chapter is PyZabbix, which is written by Luke Cyca (https://github.com/lukecyca/pyzabbix/wiki). It's a small, compact Python module that stays quite close to the API while still being easy to use. Moreover, Python's interactive console makes it quite convenient to try features and build a prototype before moving seamlessly to a complete script or application.

You can install PyZabbix very easily through Pip, the Python package installer:

$ pip install pyzabbix

Once the module has been installed, you'll be able to import it and use it in your scripts to manage a Zabbix installation.

The first thing to do is create an object for the API server and get an authentication token.

The following code fragments are shown as part of an interactive session, but they can also be part of any Python code:

>>> from pyzabbix import ZabbixAPI 
>>> zh = ZabbixAPI("https://127.0.0.1/zabbix/")
>>> zh.login("Admin", "zabbix") 

Needless to say, you have to use your actual Zabbix frontend URL and user credentials for this code to work in your environment. If all goes well, this is actually all there is to it. From now on, you can use the object handler to access any API method in the following way:

 >>> zh.host.get(output="refer") 

The "refer" options will give you only the primary key and the foreign key for any returned object:

[{'hostid': '9909900000010084'}, {'hostid': '9909900000010085'}, {'hostid': '9909900000010086'}, {'hostid': '9909900000010087'}, {'hostid': '9909900000010088'}] 

Another advantage of using a Python library is that JSON data types map very cleanly onto Python ones, so much so that most of the time you won't even need to perform any additional type conversion. Here is a table that shows the specific types supported by the Zabbix API and a few examples of how they look both in JSON and within PyZabbix function calls:

Type

JSON

pyzabbix

bool

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"editable" : "true" }
"auth" : <....>
"id" : 1
}}
zh.host.get(editable="true")

flag

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"countOutput" : "1" }
"auth" : <....>
"id" : 1
}}
zh.host.get(countOutput=1)

integer

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"limit" : 10}
"auth" : <....>
"id" : 1
}}
zh.host.get(limit=10)

string

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"sortfield": "name" }
"auth" : <....>
"id" : 1
}}
zh.host.get(sortfield="name")

timestamp

{"jsonrpc": "2.0",
"method":                          "event.get",
"params": {
"time_from": "1349797228",
"time_till": "1350661228",},
"auth": <...>,
"id": 1
}
zh.event.get(time_from="1349797228", time_till= "1350661228")

array

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"hostids" : [1001, 1002, 1003] }
"auth" : <....>
"id" : 1
}}
zh.host.get(hostids=[1001, 1002, 1003])

object

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"filter": { "name": ["Alpha", "Beta"] }
"auth" : <....>
"id" : 1
} }
zh.host.get(filter={"name": ["Alpha", "Beta"]})

query

{"jsonrpc" : "2.0"
"method": "host.get",
"params" : {
"output": "extend" }
"auth" : <....>
"id" : 1
}}
zh.host.get(output="extend")

The library creates the method requests on the fly, so it's fairly futureproof, which means any new or updated methods in the API will be automatically supported.

We can now move on to explore a few concrete examples of API usage. In order to keep the code readable and to focus on the API, and not on general programming issues, all the examples will have a very simplistic and direct approach to data handling, without much data validation or error management. While you can certainly use the following fragments in interactive sessions or as part of more complex applications (or even to build a suite of dedicated command-line tools), you are strongly encouraged to make them more robust with the appropriate error-handling and data validation controls.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.180.133