Detection + Zabbix API for Java

    As the project develops, the infrastructure serving this project grows. Over time, many network elements appear, the parameters of which are important to monitor in online mode. To solve this problem, network elements must be added to the monitoring system.
    There are several ways to add a new node to Zabbix:

    • manually through the Zabbix interface;
    • Using Zabbix Discovery;
    • using the Zabbix API.

    Adding many new nodes manually is a routine task, which takes a lot of time to solve. Well, if the new nodes will be 5 - 10. And if 50 - 100 or more? In this case, "Detection" will help you. By configuring discovery rules and actions for discovered nodes, Zabbix will create new discovered nodes, connect the necessary templates, move the created node to the desired group. This method has a drawback.



    This is how the discovered and created node looks. We see that the names of new nodes are affixed according to the IP of the node, as well as the connection method - by default, by IP. Discovery allows you to get rid of the routine and long work of adding new nodes, however, the names of the nodes do not carry any meaning. Also, the method for connecting via IP is inconvenient in that when changing IP servers you will have to change IP on all nodes again. The DNS connection method will solve the problem with changing IPs. What can be done with this? You can write a data update script directly in the Zabbix database, which is not very correct.

    But what if you rename the name of the nodes and change the connection parameters through the API? To work with the Zabbix API, libraries are written for different languages, which can be viewed here. I selected a library for Java, created a project in IDEA, connected the library, and began to study the documentation from the official site for Zabbix v.2.0.8 .
    What objects does the node consist of?



    As shown in the figure, the fields of interest to us belong to two objects: Host and Host interface. To solve the problem you need:

    • find the object of interest Host and Host interface;
    • change the value of their parameters to the ones we need.

    To the library for working with the Zabbix API for Java, an example of work is described, using it, we are trying to solve our problem.

    The first thing to do is establish a connection to the Zabbix server.

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

    Then log in to the Zabbix server as a user.

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

    Now you need to find the node ID, rename and reconfigure the agent connection. The documentation for the node search method provides an example query. Let’s figure out what it means.

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

    The result of this example will be to obtain Host objects with the technical names “Zabbix server” and “Linux server” and complete sets of properties of these nodes.

    Using this example, we form a request. In the downloaded library there is a query designer, to which you need to pass the method name and query parameters. In the example above, we see that the method needs to pass the parameter "host" with the current name of the node as the value of the parameter "filter".

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

    To call the generated method and get the answer, call the call () method .

    JSONObject response = zabbixApi.call(request);

    The resulting answer will look like this:

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

    To display the received answer on the screen, just pass the received answer to the println () method ;

    System.out.println(response);

    We get the node identifier from the received response:

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

    Node ID found. Using it, we can rename the node. To do this, call the "host.update" method with the parameters "hostid", "host", "name".

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

    What happened?



    Half of the task is completed. It remains to find the Host interface object and change its properties. To search for the Host interface object, use the found host identifier.

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

    To the found object we change the properties "dns", "useip".

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



    The task was completed for one node, but there are many more. To solve this problem, I wrote a small utility that reads a text file of the form:

    HOSTNAME
    localhost

    Gets IP and changes the properties of the node according to the algorithm described above. Listing below.

    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 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 
     	*/
    	public static Map readhostNameFromFile() throws Exception {
        	Map 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;
    	}
    }

    I removed most error and condition handlers from the listing to show the implementation of the task. The described method can help solve an existing problem with the name of the detected nodes.

    Someone may say that it would be easier, using the API, to immediately create nodes with all the necessary parameters. And I will agree. By slightly modifying the above listing, you can rewrite the code not to change properties, but to create nodes with the necessary parameters without using Zabbix “discovery”. So I will do in the future.

    Also popular now: