У заббикса есть открытое API для доступа к функциям сервера мониторинга. К сожалению реализация библиотеки для доступа к API существует только для Ruby, PHP и Python. Пришлось изобретать велосипед самостоятельно. Доступ ко всем функциям идет через JSONRPC. Для примера запрос, ответ функции получения версии Zabbix API выглядит примерно так:
Подробное описание протокола JSON-RPC не входит в цель статьи, приступим к реализации:
Функция CallAPI выполняет вызов API функции. Принимает метод и его параметры (в виде объекта согласно документации Zabbix API). Примеры использования будут чуть ниже. Предназначение obj2json, и GetWebRequest думаю очевидно, добавлю лишь что запрос отправляется методом POST. Рассмотрим использование этой функции на примере авторизации на сервере. Для авторизации нам необходимо отправить запрос метода «user.authenticate» с параметрами user и password. Результатом будет auth_hash, который является полем каждого последующего запроса. Готовая функция для авторизации с учетом вышесказанного будет выглядеть примерно так:
Как видим логика до безобразия проста, описываем параметры, задаем имя метода, вызываем функцию. Если все прошло успешно и есть auth_hash, то сохраняем его в глобальном поле класса и возвращаяем положительный результат. Если пошло что то не так — отлавливаем ошибку и возвращаем ложь. Так же следует упомянуть о функции Update — она служит для уведомления основного приложения об изменениях в нашем классе. Итак, мы научились выполнять запрос и получать простые ответы от сервера. Но большая часть ответов от сервера представляют из себя массивы совершенно различных элементов. Для упращения добавления нового функционала был создан следующий обобщенный класс:
{ "jsonrpc":"2.0", "method":"apiinfo.version", "params":[], "auth":"a6e895b98fde40f4f7badf112fd983bf", "id":2 } <br>{ "jsonrpc":"2.0", "result":"1.3", "id":2 } * This source code was highlighted with Source Code Highlighter.
Подробное описание протокола JSON-RPC не входит в цель статьи, приступим к реализации:
private string GetWebRequest(string body)
{
WebRequest wb = WebRequest.Create(url);
wb.ContentType = @"application/json-rpc";
wb.Credentials = CredentialCache.DefaultCredentials;
ASCIIEncoding encoding = new ASCIIEncoding();
string postData = body;
byte[] data = encoding.GetBytes(postData);
wb.Method = "POST";
wb.ContentLength = data.Length;
Stream newStream = wb.GetRequestStream();
newStream.Write(data, 0, data.Length);
newStream.Close();
HttpWebResponse response = (HttpWebResponse)wb.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
return reader.ReadToEnd();
}
public string obj2json(object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
public string CallApi(string method, object param)
{
object Query = new
{
jsonrpc = "2.0",
auth = auth_hash,
id = id.ToString(),
method = method,
Params = param
};
String qr = obj2json(Query);
qr=qr.Replace("Params", "params");
id++;
string result = GetWebRequest(qr);
return result;
}
* This source code was highlighted with Source Code Highlighter.
Функция CallAPI выполняет вызов API функции. Принимает метод и его параметры (в виде объекта согласно документации Zabbix API). Примеры использования будут чуть ниже. Предназначение obj2json, и GetWebRequest думаю очевидно, добавлю лишь что запрос отправляется методом POST. Рассмотрим использование этой функции на примере авторизации на сервере. Для авторизации нам необходимо отправить запрос метода «user.authenticate» с параметрами user и password. Результатом будет auth_hash, который является полем каждого последующего запроса. Готовая функция для авторизации с учетом вышесказанного будет выглядеть примерно так:
public bool login()
{
bool res;
Update(new UpdateInfoMessage(this) { message = "Попытка авторизоваться", status = "LOGIN" });
try
{
var userinfo = new { user = _user, password = _password };
string result = CallApi("user.authenticate", userinfo);
auth_hash = (serializer.Deserialize<string>(result)).result;
res=true;
Update(new UpdateInfoMessage(this) { message = "Авторизация произошла успешно", status = "LOGIN" });
}
catch (Exception ex)
{
Update(new UpdateInfoMessage(this) { message = "Ошибка авторизации:" + ex.Message, status = "LOGIN" });
res= false;
}
return res;
}
* This source code was highlighted with Source Code Highlighter.
Как видим логика до безобразия проста, описываем параметры, задаем имя метода, вызываем функцию. Если все прошло успешно и есть auth_hash, то сохраняем его в глобальном поле класса и возвращаяем положительный результат. Если пошло что то не так — отлавливаем ошибку и возвращаем ложь. Так же следует упомянуть о функции Update — она служит для уведомления основного приложения об изменениях в нашем классе. Итак, мы научились выполнять запрос и получать простые ответы от сервера. Но большая часть ответов от сервера представляют из себя массивы совершенно различных элементов. Для упращения добавления нового функционала был создан следующий обобщенный класс:
public class Result:IEnumerable
{
// храниться результат выполнения запроса к серверу
public T[] result;
/// Активное соединение с сервером
public ZabbixConnection server;
// метод Из Zabbix API, например maps.get, triggers.update и т.д
protected string method;
// Объект с параметрами запроса к серверу
protected object Params;
// строковое значение ответа сервера, используется в основном для отладки
public string stringResult;
// Объект для синхронизации доступа из разных потоков.
public object SyncRoot;
// процедура для переопределения в Классах наследниках, используется для инициализации параметров запроса "method" и "Params"
protected virtual void init() { }
public Result(ZabbixConnection Server)
{
init();
server = Server;
SyncRoot = new object();
}
public Result()
{
init();
}
// Получение данных от сервера, результат заноситься в переменную result и collection
public virtual void get()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
lock (SyncRoot)
{
stringResult = (server.CallApi(method, Params));
result = serializer.Deserialize<Result>(stringResult).result;
if (result==null){result=new T[1];}
}
}
public T this[int index]
{
get
{
return result[index];
}
}
public IEnumerator GetEnumerator()
{
foreach (T item in result)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Это обобщенный класс, для использования создаем нужную структуру данных согласно описанию в Zabbix API. Наследуем класс с уже определенным типом , переопределяем метод Init, в котором задаем имя метода и параметры запроса к серверу. Рассмотрим конкретный вариант:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace Zabbix
{
public class Hosts:Result
{
protected override void init()
{
method = "host.get";
Params = new { output = "extend" };
}
public Hosts(ZabbixConnection Server) : base(Server) { }
}
public class Host
{
public string host;
public string hostid;
public string ip;
public override string ToString()
{
return host;
}
}
}
Думаю тут тоже все достаточно просто, аналогичным образом можно получить любые данные, будь то триггеры, группы хостов, события или данные графиков. Описания всех методов и параметров можно найти в разделе документации к Zabbix API. Чувствую топик и так получился не маленький, и пора закругляться. Я как можно короче описал способ использования Zabbix API в .NET приложениях. Более полный код библиотеки, а также пример клиента на WPF, можно скачать тут: https://github.com/p1nger/odzl