Этот пост ответит на два вопроса:
- Как отобразить тот же элемент, например Загрузка процессора для нескольких хостов на одном графике
- Как избежать сумасшествия от всех медленных нажатий в пользовательском интерфейсе Zabbix с помощью его API
Я укажу, как это можно сделать с помощью простого HTTP POST, а затем покажу решение, использующее библиотеку Python для доступа к API Zabix.
Проблема, которую мы хотим решить, состоит в том, чтобы создать график, который отображает один и тот же элемент для ряда хостов, которые все относятся к одной группе хостов, но не все хосты в группе должны быть включены.
Zabbix API
Zabbix API — это REST API, представленный в 1.8, который позволяет управлять ресурсами Zabbix, такими как элементы, триггеры и графики. Ресурсы связаны друг с другом с помощью идентификаторов, поэтому обычно вам нужно получить ресурс по его имени, извлечь его идентификатор и использовать его для получения связанных ресурсов.
Документация по API в v1.8 … отсутствует, поэтому я обычно читаю документацию v2.2, затем проверяю соответствующую страницу и пример в 1.8 и как это будет работать. Документация иногда содержит ошибки, поэтому не верьте ей. (F.ex. item.get «s фильтр должен быть массив , но на самом деле является объектом.) Кроме того , не ясно, для ГЭТ, когда поля Ored и когда операция AND и можете ли вы сделать что — нибудь об этом.
Для Zabbix API есть несколько библиотек, я выбрал Python, потому что он мне нравится, и zabbix_api.py, потому что он, похоже, поддерживается и развивается. У меня была проблема с авторизацией, но мне удалось обойти ее.
Использование API
Аутентификация и авторизация
Обычно вы сначала авторизуетесь с помощью Zabbix и используете токен аутентификации, который вы получаете от него, во всех последующих вызовах.
Поймать : Zabbix API должен быть включен для пользователя
Пользователь Zabbix, используемый для связи с API, должен быть авторизован для использования API (для этого есть флажок в администрировании Zabbix). В нашей конфигурации это отключено по умолчанию, и в нашем случае пользователи должны быть добавлены в группу Zabbix api.
Если у вас нет доступа, вы сможете пройти аутентификацию с помощью API, но другие запросы не будут выполнены с «Нет доступа к API».
Общие атрибуты получения
Запросы get имеют некоторые общие атрибуты, такие как
- output = (extended | Shortten | Refer |…) — сколько включить в вывод (см. => только идентификаторы, удлинить => как можно больше)
- фильтр — мы увидим это ниже
Реализация
Создание графа с HTTP POST
Вы общаетесь с API, публикуя JSON. Задача easiset — выполнить:
curl -i -n -X POST --header "Content-Type: application/json" -d@- https://zabbix.example.com/api_jsonrpc.php
и вставьте туда JSON, добавьте новую строку и нажмите Control-D, чтобы завершить ввод.
Аутентифицироваться с Zabbix:
curl -i -n -X POST --header "Content-Type: application/json" -d@- https://zabbix.example.com/api_jsonrpc.php { "jsonrpc": "2.0", "method": "user.authenticate", "params": { "user": "my zabbix username", "password": "my precious" }, "auth": null, "id": 0 } => {"jsonrpc":"2.0","result":"2dddea29e1d37b9f90069dd129d7a66d","id":0}
- Я считаю, что значение id не важно, но вы должны предоставить некоторые, чтобы получить разумный ответ; 0, 1, 2 работают нормально.
Получите все элементы в группе Host Analytics, используя токен авторизации:
{ "jsonrpc":"2.0", "method":"item.get", "params":{ "output":"shorten", "filter": {"description": "Processor load15"}, "group": "Analytics production", "select_hosts": "extend", "limit": 10 }, "auth":"2dddea29e1d37b9f90069dd129d7a66d", "id":2 } => [{"itemid":"40002","hosts":[{"maintenances":[..],"hostid":"10242","proxy_hostid":"10381","host":"my-server.example.com","dns":"my-server.example.com",...}]},{"itemid":"40003",...
Что ж, мы пропустим все остальное и перейдем к настоящему веселью — Python API.
Создание графа с помощью zabbix_api.py
Некоторые заметки:
- У меня были проблемы с авторизацией, мне приходилось указывать имя пользователя и пароль как в конструкторе (для http-заголовков auth. Http), так и вызывать метод login, чтобы он работал; в теории, только один из этих двух должен быть необходим. (Я мог где-то ошибиться.)
- По сравнению с curl есть некоторые преимущества, такие как отсутствие необходимости указывать неважные атрибуты, такие как идентификатор запроса, и автоматическое отображение между списками / dicts Python и JSON.
Прежде чем мы покажем код, давайте посмотрим, как его использовать:
bash$ ipython In [1]: %run create_graph.py In [2]: g = ZabbixGrapher(user="my zabbix user", passwd="my precious") 20: url: https://zabbix.example.com/api_jsonrpc.php 20: HTTP Auth enabled 20: Sending: {"params": {"password": "my precious", "user": "my zabbix user"}, "jsonrpc": "2.0", "method": "user.authenticate", "auth": "", "id": 0} 20: Response Code: 200 Logged in, auth: c417623c2d72e0f14ddab044429b80e7 In [3]: g.create_graph("CPU iowait on data nodes(avg1)", item_key="system.cpu.util[,iowait,avg1]", item_descr = None, host_group = "Analytics staging", hostname_filter_fn = lambda dns: "-data" in dns)
Длинный, страшный код сам по себе:
import logging import sys from zabbix_api import ZabbixAPI, ZabbixAPIException BOLD = "\033[1m" RESET = "\033[0;0m" class Palette: last_idx = 0 colors = ["C04000", "800000", "191970", "3EB489", "FFDB58", "000080", "CC7722", "808000", "FF7F00", "002147", "AEC6CF", "836953", "CFCFC4", "77DD77", "F49AC2", "FFB347", "FFD1DC", "B39EB5", "FF6961", "CB99C9", "FDFD96", "FFE5B4", "D1E231", "8E4585", "FF5A36", "701C1C", "FF7518", "69359C", "E30B5D", "826644", "FF0000", "414833", "65000B", "002366", "E0115F", "B7410E", "FF6700", "F4C430", "FF8C69", "C2B280", "967117", "ECD540", "082567"] def next(self): self.last_idx = (self.last_idx + 1) % len(self.colors) return self.colors[self.last_idx] class ZabbixGrapher: def __init__(self, user, passwd, log_level=logging.INFO): try: # I had to spec. user+psw here to use Basic http auth to be able # to log in even though I supply them to login below; # otherwise the call failed with 'Error: HTTP Error 401: Authorization Required' self.zapi = ZabbixAPI( server="https://zabbix.example.com", path="/api_jsonrpc.php", user=user, passwd=passwd, log_level=log_level) # or DEBUG # BEWARE: The user must have access to the Zabxi API enabled (be # in the Zabbix API user group) self.zapi.login(user, passwd) print "Logged in, auth: " + self.zapi.auth except ZabbixAPIException as e: msg = None if "" in str(e): msg = "Connection to Zabbix timed out, it's likely having temporary problems, retry now or later'" else: msg = "Error communicating with Zabbix. Please check your authentication, Zabbix availability. Err: " + str(e) print BOLD + "\n" + msg + RESET raise ZabbixAPIException, ZabbixAPIException(msg), sys.exc_info()[2] def create_graph(self, graph_name="CPU Loads All Data Nodes", item_descr="Processor load15", item_key=None, host_group="Analytics production", hostname_filter_fn=lambda dns: "-analytics-prod-data" in dns and ("-analytics-prod-data01" in dns or dns >= "aewa-analytics-prod-data15"), #show_legend = True - has no effect (old Z. version?) ): palette = Palette() try: items = self.get_items(item_descr = item_descr, item_key = item_key, host_group = host_group) if not items: raise Exception("No items with (descr=" + str(item_descr) + ", key=" + str(item_key) + ") in the group '" + host_group + "' found") # Transform into a list of {'host':.., 'itemid':..} pairs, # filter out unwanted hosts and sort by host to have a defined order item_maps = self.to_host_itemid_pairs(items, hostname_filter_fn) item_maps = sorted( filter(lambda it: hostname_filter_fn(it['host']), item_maps), key = lambda it: it['host']) if not item_maps: raise Exception("All retrieved items filtered out by the filter function; orig. items: " + str(item_maps)) # The graph will be created on the 1st item's host: graph_host = item_maps[0]['host'] ## CREATE GRAPH # See https://www.zabbix.com/documentation/2.0/manual/appendix/api/graph/definitions graph_items = [] for idx, item in enumerate(item_maps): graph_items.append({ "itemid": item['itemid'], "color": palette.next(), "sortorder": idx }) graph = self.zapi.graph.create({ "gitems": graph_items, "name": graph_name, "width":900, "height":200 #,"show_legend": str(int(show_legend)) }) print "DONE. The graph %s has been created on the node %s: %s." % (graph_name, graph_host, str(graph)) except Exception as e: msg = None if "No API access while sending" in str(e): msg = "The user isn't allowed to access the Zabbix API; go to Zabbix administration and enable it (f.ex. add the group API access to the user)'" else: msg = "Error communicating with Zabbix. Please check your request and whether Zabbix is available. Err: " + str(e) print BOLD + "\n" + msg + RESET raise type(e), type(e)(msg), sys.exc_info()[2] def get_items(self, item_descr = None, item_key = None, host_group = None): if not item_descr and not item_key: raise ValueError("Either item_key or item_descr must be provided") ## GET ITEMS to include in the graph # See (Zabbix 2.0 so not 100% relevant but better doc) # https://www.zabbix.com/documentation/2.0/manual/appendix/api/item/get filters = {} if item_descr: filters["description"] = item_descr if item_key: filters["key_"] = item_key return self.zapi.item.get({ "output":"shorten", "filter": filters, "group": host_group, "select_hosts": "extend" }) @staticmethod def to_host_itemid_pairs(items, hostname_filter_fn): # List of (host, itemid) pairs sorted by host items_by_host = [] for item in items: itemid = item['itemid'] dns = item['hosts'][0]['dns'] if hostname_filter_fn(dns): items_by_host.append({"host": dns, "itemid": itemid}) return items_by_host
Другие способы
Как отметил мой коллега Маркус Крюгер:
Вы также можете использовать автоматическую регистрацию или автоматическое обнаружение, чтобы добавить хосты в группы, а затем извлечь агрегированные данные по всем хостам в группе хостов. (Конечно, это работает, только если вы хотите получить данные со
всех хостов в группе — но если вы не хотите получать данные, не добавляйте хост в эту группу.) Таким образом, не требуется никакой ручной работы для добавления мониторинга и построение графиков между несколькими экземплярами, мигающими в и из существования.
Некоторые ссылки:
Автоматическая регистрация (2.0 документа, но должна быть достаточно точной и для 1.8.3)
Тем не менее, с Zabbix все еще довольно неудобно работать.
Это позволяет получить совокупные метрики, такие как avg, max, min, сумма метрики для всей группы хостов. Использование автоматического обнаружения и автоматической регистрации позволяет автоматически назначать хосты группам.
Вывод
Использовать API легко и быстро, особенно с Python. Работа с интерфейсом настолько медленная и мучительная, что я действительно рекомендую использовать API.