Этот пост ответит на два вопроса:
- Как отобразить тот же элемент, например Загрузка процессора для нескольких хостов на одном графике
- Как избежать сумасшествия от всех медленных нажатий в пользовательском интерфейсе 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.