Zabbix - expanding macro boundaries

When making a solution for a client, 2 tasks arose that I wanted to solve beautifully and with regular Zabbix functionality.

Task 1. Tracking the current firmware version on Mikrotik routers.

The task is solved easily - by adding an agent to the HTTP template. The agent receives the current version from the Mikrotik website, and the trigger compares the current version with the current one and issues an alert in case of a discrepancy.

When you have 10 routers, such an algorithm is not critical, but what to do with 3000 routers? Send 3000 requests to the server? Of course, such a scheme will work, but the very idea of ​​​​3000 requests did not suit me, I wanted to find another solution. In addition, there was still a drawback in such an algorithm: the other side can count such a number of requests from one IP for a DoS attack, they can simply ban it.

Task 2. Using an authorization session in different HTTP agents.

When an agent needs to receive information from "closed" pages via HTTP, an authorization cookie is needed. To do this, there is usually a standard authorization form with a "login / password" pair and setting the session ID in the cookie.

But there is a problem, it is impossible to access the data of another item from one HTTP agent item to substitute this value in the Header.

There is also a "Web script", it has another limitation, it does not allow you to get content for analysis and further saving. You can only check for the presence of the necessary variables on the pages or pass previously received variables between web script steps.

After thinking a little about these tasks, I decided to use macros that are perfectly visible in any part of the monitoring system: in templates, hosts, triggers or items. And you can update macros through the web interface API.

Zabbix has good and detailed API documentation. For data exchange via api, the Json data format is used. Details can be found in official documentation.

The sequence of actions for obtaining the data we need and recording them in a macro is shown in the diagram below.

Zabbix - expanding macro boundaries

Step 1

The very first step can consist of a single action or multiple actions. All the main logic is laid in the first steps, and the last 3 steps are the main ones.

In my example, the first step was to get authorization cookies on the PBX for the first task. For the second task, I got the number of the current version of the Mikrotik firmware.

URL of current versions of Mikrotik firmware

These addresses are accessed by the Mikrotik equipment itself when the latest available firmware version is received.

The first step is completely individual for each case and the logic of its work may be different. It all depends on your task.

When working with web scripting, keep track of which response method you need. Headlines HTTP response or self body response without headers?
If authorization cookies are needed, then set the response method Headlines as in the case of Asterisk.

If you need data, as in the case of the mikrotik server response, put Body response without headers.

Step 2

Let's move on to the second step. Getting an authorization session:

POST http://company.com/zabbix/api_jsonrpc.php HTTP/1.1
Content-Type: application/json-rpc

{
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
        "user": "Admin"
        "password": "zabbix"
    },
    "id": 1,
    "auth": null
}

jsonrpc is the version of the JSON-RPC protocol that is being used;
Zabbix implements JSON-RPC version 2.0;

  • method - the method that is called;
  • params - parameters that are passed by the method;
  • id is an arbitrary request identifier;
  • auth - user authentication key; since we don't have it yet, let's set it to null.

To work with the API, I created a separate account with limited rights. Firstly, you do not need to give access to where you do not need to. And secondly, before version 5.0, the password set through the macro could be read. Accordingly, if you use the Zabbix administrator password, the admin account is easy to steal.

This will be especially true when working with API through third-party scripts and storing credentials on the side.

Since version 5.0 there is an option to hide the password saved in the macro.

Zabbix - expanding macro boundaries

When creating a separate account for updating data via the API, be sure to check whether the data you need is available through the web interface and whether it is possible to update it. I did not check, and then for a long time I could not understand why the macro I needed was not visible in the API.

Zabbix - expanding macro boundaries

After we have received authorization in the API, we proceed to get a list of macros.

Step 3

The API does not allow you to update a host macro by name, you must first get the macro ID. Moreover, to get a list of macros for a specific host, you need to know the ID of this host, and this is an extra request. Use default macro {HOST ID} in the request is not allowed. I decided to bypass the restriction like this:

Zabbix - expanding macro boundaries

I created a local macro with this host's ID. Finding out the host ID is very easy from the web interface.

A response with a list of all macros on a given host can be filtered by a pattern:

regex:{"hostmacroid":"([0-9]+)"[A-z0-9,":]+"{$MIKROTIK_VERSION}"

Zabbix - expanding macro boundaries

Thus, we get the ID of the macro we need, where MIKROTIK_VERSION is the name of the macro we are looking for. In my case, the macro is searched MIKROTIK_VERSIONThe that was assigned to the host.

The request itself looks like this:

POST http://company.com/zabbix/api_jsonrpc.php HTTP/1.1
Content-Type: application/json-rpc

{
    "jsonrpc":"2.0",
    "method":"usermacro.get",
    "params":{
        "output":"extend",
        "hostids":"{$HOST_ID}"
    },
    "auth":"{sid}",
    "id":1
}

Variable {sid} obtained in the second step and will be used constantly, where you need to work with the API interface.

Final 4 STEP - updating the macro

Now we know the macro ID that needs to be updated, the authorization cookie or the firmware version of the router. You can update the macro itself.

POST http://company.com/zabbix/api_jsonrpc.php HTTP/1.1
Content-Type: application/json-rpc

{
    "jsonrpc":"2.0",
    "method":"usermacro.update",
    "params":{
        "hostmacroid":"{hostmacroid}",
        "value":"{mikrotik_version}"
    },
    "auth":"{sid}",
    "id":1
}

{mikrotik_version} is the value obtained in the first step. In my example, the version of the current mikrotik firmware
{hostmacroid} - the value was obtained in the third step - the id of the macro that we are updating.

Conclusions

The approach to solving the problem with standard functionality is much more complicated and longer. Especially if you know programming and can quickly add the necessary logic in the script.

The obvious advantage of this approach is the "portability" of the solution between different servers.

For me personally, it is strange that the HTTP agent cannot access the data of another item and substitute them in the request body or headers [ ZBXNEXT-5993].

The finished template can download on GitHub.

Source: habr.com

Add a comment