По мере развития проекта разрастается и инфраструктура, обслуживающая этот проект. Со временем появляется множество элементов сети, параметры которых важно отслеживать в онлайн-режиме. Для решения этой задачи элементы сети необходимо добавить в систему мониторинга.
Добавить новый узел в Zabbix можно несколькими способами:

  • вручную через интерфейс Zabbix;
  • используя «Обнаружение» Zabbix;
  • используя API Zabbix.

Добавление множества новых узлов вручную – рутинная задача, на решение которой уходит уйма времени. Хорошо, если новых узлов будет 5 – 10. А если 50 – 100 и больше? В этом случае вам поможет «Обнаружение». Настроив правила обнаружения и действия для обнаруженных узлов, Zabbix сам создаст новые обнаруженные узлы, подключит необходимые шаблоны, переместит созданный узел в нужную группу. Данный способ имеет недостаток.



Так выглядит обнаруженный и созданный узел. Мы видим, что имена новым узлам проставляются в соответствии с IP узла, как и способ подключения – по умолчанию по IP. Обнаружение позволяет избавиться от рутиной и долгой работы по добавлению новых узлов, однако наименования узлов не несут никакой смысловой нагрузки. Также способ по подключению через IP неудобен тем, что при смене IP серверов вам придётся снова на всех узлах менять IP. Способ подключения по DNS решит проблему с изменяющимися IP. Что же с этим можно сделать? Можно написать скрипт обновления данных напрямую в базе Zabbix, что не очень правильно.

А что если переименовать название узлов и изменить параметры подключения через API? Для работы с Zabbix API написаны библиотеки под разные языки, которые можно посмотреть здесь. Я выбрал библиотеку под Java, создал проект в IDEA, подключил библиотеку и начал изучать документацию с официального сайта для Zabbix v.2.0.8.
Из каких объектов состоит узел?



Как показано на рисунке, интересующие нас поля принадлежат двум объектам: Host и Host interface. Для решения задачи нужно:

  • найти интересующий объект Host и Host interface;
  • изменить значение их параметров на нужные нам.

К библиотеке для работы с Zabbix API под Java описан пример работы, пользуясь им, пробуем решить нашу задачу.

Первое, что необходимо сделать – это организовать подключение к серверу Zabbix.

String url = "http://ZabbixServer/zabbix/api_jsonrpc.php";
 zabbixApi = new DefaultZabbixApi(url);
 zabbixApi.init();

Затем авторизоваться на сервере Zabbix под пользователем.

boolean login = zabbixApi.login("login", "password");

Теперь нужно найти идентификатор узла, переименовать и перенастроить подключение агента. В документации для метода поиска узла приведен пример запроса. Разберем, что он значит.

{
    "jsonrpc": "2.0",
    "method": "host.get",                       //вызываемый метод API
    "params": {                                           // параметры метода
        "output": "extend",                         // параметр определяет, какие данные будут возвращены
                                                                    // в этом примере метод вернет результат со всеми                        свойствами найденного узла
        "filter": {                                            // параметр определяет, какие данные вернуть
            "host": [                                         // свойство объекта Host: техническое обозначение узла
                "Zabbix server",                        //значение свойства искомого узла
                "Linux server"
            ]
        }
    },
    "auth": "038e1d7b1735c6a5436ee9eae095879e",
    "id": 1
}

Результатом этого примера станет получение объектов Host с техническими названиями «Zabbix server» и «Linux server» и полными наборами свойств этих узлов.

Используя этот пример, формируем запрос. В скаченной библиотеке есть конструктор запросов, которому нужно передать название метода и параметры запроса. В примере выше видим, что методу нужно передать параметр «host» c текущем названием узла в качестве значения параметра «filter».

JSONObject filter = new JSONObject();
filter.put("host", “127.0.0.1”);
Request request = RequestBuilder.newBuilder()
        .method("host.get")
        .paramEntry("filter", filter)
        .build();

Чтобы вызвать сформированный метод и получить ответ вызываем  метод call().

JSONObject response = zabbixApi.call(request);

Полученный ответ будет выглядеть так:

{
 "id":2,
 "jsonrpc":"2.0",
 "result":[
		   {
		     "hostid":"10503"
		   }
             ]
}

Чтобы вывести полученный ответ на экран, достаточно передать полученный ответ в метод println();

System.out.println(response);

Получаем идентификатор узла из полученного ответа:

String hostid = response.getJSONArray("result").getJSONObject(0).getString("hostid");

Идентификатор узла найден. Используя его, можем переименовать узел. Для этого нужно вызвать метод «host.update» с параметрами " hostid "," host"," name".

request = RequestBuilder.newBuilder()
                    .method("host.update")
                    .paramEntry("hostid", hostid)
                    .paramEntry("host", "localhost")
                    .paramEntry("name", "localhost")
                    .build();
response = zabbixApi.call(request);

Что получилось?



Половина задачи выполнено. Осталось найти объект Host interface и изменить его свойства. Для поиска объекта Host interface используем найденный идентификатор узла.

request = RequestBuilder.newBuilder()
        .method("hostinterface.get")
        .paramEntry("hostids", new String [] {hostid})
        .build();
response = zabbixApi.call(request);

interfaceid = response.getJSONArray("result")
            .getJSONObject(0).getString("interfaceid");

Найденному объекту изменяем свойства «dns», «useip».

request = RequestBuilder.newBuilder()
        .method("hostinterface.update")
        .paramEntry("interfaceid", interfaceid)
        .paramEntry("dns", "localhost")
        .paramEntry("useip", 0)
        .build();

response = zabbixApi.call(request);



Задача выполнена для одного узла, но их намного больше. Для решения этой задачи я написал небольшую утилиту, которая читает текстовый файл вида:

HOSTNAME
localhost

Получает IP и меняет свойства узла по описанному выше алгоритму. Ниже приведен листинг.

import com.alibaba.fastjson.JSONObject;
import io.github.hengyunabc.zabbix.api.DefaultZabbixApi;
import io.github.hengyunabc.zabbix.api.Request;
import io.github.hengyunabc.zabbix.api.RequestBuilder;

import java.io.File;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main {

	public static String EXECUTION_DIR = new File("").getAbsolutePath();
	public static String fileHostParams = EXECUTION_DIR + "/HostName.txt";
	public static DefaultZabbixApi zabbixApi;

	/*Поиск Хоста и обновление параметров */
	public static void main(String[] args) throws Exception {
    	String url = "http://ZabbixServer/zabbix/api_jsonrpc.php";

    	try {
        	zabbixApi = new DefaultZabbixApi(url);
        	zabbixApi.init();
    	} catch (Exception e) {
        	e.printStackTrace();
    	}

    	boolean login = zabbixApi.login("login", "password");

    	Map<String, String> params = readhostNameFromFile();
    	String hostid = "";
    	String interfaceid = "";

    	for (Map.Entry hostParam : params.entrySet()) {
        	String hostName = hostParam.getKey().toString();
        	String ip = hostParam.getValue().toString();

        	//Проверка существования хоста
        	Request request = RequestBuilder.newBuilder()
                    .method("host.exists")
                    .paramEntry("host", ip)
                    .build();
        	JSONObject response = zabbixApi.call(request);
        	boolean hostexist =  response.getBooleanValue("result");

       if (hostexist) {
	// Поиск Узла
	JSONObject filter = new JSONObject();
	filter.put("host", ip);
	request = RequestBuilder.newBuilder()
        	.method("host.get")
                .paramEntry("filter", filter)
        	.build();
	System.out.println(request);
	response = zabbixApi.call(request);

	hostid = response.getJSONArray("result").getJSONObject(0).getString("hostid");

	//переименование хоста
	request = RequestBuilder.newBuilder()
            .method("host.update")
	        .paramEntry("hostid", hostid)
        	.paramEntry("host", hostName)
        	.paramEntry("name", hostName)
        	.build();

	zabbixApi.call(request);

	//Поиск интерфейса узла
	request = RequestBuilder.newBuilder()
       	 .method("hostinterface.get")
            .paramEntry("output", new String[]{"interfaceid"})
            .paramEntry("hostids", hostid)
            .build();

	response = zabbixApi.call(request);

	interfaceid = response.getJSONArray("result").getJSONObject(0).getString("interfaceid");

	//Изменение интерфейса Хоста
	request = RequestBuilder.newBuilder()
            .method("hostinterface.update")
                .paramEntry("interfaceid", interfaceid)
         	.paramEntry("dns", hostName.toLowerCase())
                .paramEntry("useip", 0)
        	.build();

	zabbixApi.call(request);

	} else {
	System.out.println("Host with name - " + ip + " not found;");
      }

    	}
	}

	/**
 	* Читает из файла DNS узлов
 	* @return maping <hostName, IP>
 	*/
	public static Map<String, String> readhostNameFromFile() throws Exception {
    	Map<String, String> hostParams = new HashMap<>();

    	File file = new File(fileHostParams);
    	Scanner sc = new Scanner(file);

	    //Ignor header from file
    	sc.nextLine();

    	while (sc.hasNext()) {
        	String[] line = sc.nextLine();
        	hostParams.put(line[0], getIPbyHostName(line[0]));
    	}

    	return hostParams;
	}

	/**
     * Return IP address by dns host name
 	* @param hostName
 	* @return IP
 	*/
	public static String getIPbyHostName(String hostName) {
    	String ipAddr = "";
    	try {
        	InetAddress inetAddr = InetAddress.getByName(hostName);
        	byte[] addr = inetAddr.getAddress();

        	for (int i = 0; i < addr.length; i++) {
            	if (i > 0) {
                	ipAddr += ".";
            	}
            	ipAddr += addr[i] & 0xFF;
        	}

    	} catch (UnknownHostException e) {
        	System.out.println("Host not found: " + e.getMessage());
    	}
    	return ipAddr;
	}

}

Из листинга я убрал большинство обработчиков ошибок и условий, чтобы показать реализацию задачи. Описанный метод может помочь решить уже существующую проблему с наименованием обнаруженных узлов.

Кто-то может сказать, что было бы проще, используя API, сразу создавать узлы со всеми нужными параметрами. И я соглашусь. Немного модифицировав приведенный листинг, можно переписать код не на изменение свойств, а на создание узлов с нужными параметрами без использования «обнаружения» Zabbix. Так я и сделаю в будущем.

Комментарии (13)