Глава 8. Обработка внешних сценариев

Содержание

Глава 8. Обработка внешних сценариев
Внешние проверки
Размещение сценариев
Углубляясь во внешние проверки
Войдём вовнутрь сценария
Общие правила написания сценариев
Обсуждение внешних проверок
Параметр пользователя
Гибкий параметр пользователя
Обсуждение параметров пользователя
Отправка данных посредством zabbix_sender
Новый сценарий
Написание обёртывающего сценария для check_ora_sendtrap
За и против выделенного сервера сценариев
Работа с протоколами Zabbix
Протокол get Zabbix
Протокол sender Zabbix
Занимательная недокументированная функциональность
Применение свойств часов в элементах JSON
Протокол агента Zabbix
Некоторые наиболее вероятные отклики
Протокол обнаружения нижнего уровня
Взаимодействие с Zabbix
Реализация протокола Zabbix_sender в Java
Реализация протокола Zabbix_sender в Python
Некоторые рассуждения о разработке агента
Выводы

До сих пор мы изучали как работает большая часть компонентов сервера и как воздействовать на Zabbix для извлечения данных из различных внешних источников. Принимая это во внимание, настройте свою систему мониторинга в большой, гетерогенной и сложной инфраструктуре. Скорее всего вы обнаружите различные индивидуальные устройства, серверные приборы, а также проприетарное аппаратные средства. Обычно всё это оборудование имеет интерфейс для обработки запросов, однако, зачастую оказывается что большая часть этих измерений не выставляется через SNMP (Simple Network Management Protocol) или любой другой стандартный метод опроса.

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

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

  • Внешние проверки (серверная сторона)

  • UserParameter (сторона агента)

  • Zabbix_sender: Этот исполняемый файл может применяться как на стороне агента, так и на стороне сервера

  • Простой, эффективный и лёгкий в реализации протокол взаимодействия

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

В данной главе мы охватим следующие моменты:

  • Написание сценария и предоставления к нему доступа в качестве внешнего сценария

  • Преимущества и недостатки сценариев на серверной стороне и на стороне агента

  • Изучение альтернативных методов отправки данных на ваш сервер Zabbix

  • Подробная документация по протоколу Zabbix

  • Снабжённая комментариями обучающая реализация протокола sender Zabbix

 Внешние проверки

Zabbix предоставляет функции для обслуживания всех тех элементов, которые нельзя достичь при помощи стандартного агента. В реальной жизни может случиться так, что вы не будете иметь возможности установить стандартный агент на некоторый прибор, для которого вы хотите осуществлять мониторинг. Примером из практики может служить конкретный ИБП, все ваши сервера которые, по ряду причин, могут оказаться скомпрометированными после установки на них внешнего программного обеспечения, или другие устройства, которые не могут иметь устанавливаемого индивидуального программного обеспечения.

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

  Размещение сценариев

Местоположение сценариев Zabbix определяется в вашем файле настроек zabbix_server.conf. Начиная с версии 2.0 Zabbix местоположение по умолчанию было изменено на /usr/local/share/zabbix/externalscripts.

[Замечание]Замечание

Местоположение по умолчанию основывается во время компиляции на значении переменной datadir. В действительности ваше местоположение по умолчанию определено в ${datadir}/zabbix/externalscripts. Это правило верно как для компонентов прокси, так для компонентов сервера.

Первоначально оно было определено как /etc/zabbix/externalscripts; тем не менее, вы можете изменить его просто определив другое местоположение в zabbix_server.conf при помощи параметра ExternalScripts:


### Option: ExternalScripts
# Mandatory: no
# Default:
# ExternalScripts=${datadir}/zabbix/externalscripts
ExternalScripts=/usr/lib/zabbix/externalscripts
 	   

Существуют некоторые важные расширения во внешних проверках и сценариях, введённых начиная с версий Zabbix 2.2 и 2.4:

  • Синтаксис ключей теперь поддерживает множество параметров, разделяемых запятой

  • Существует поддержка макросов пользователя в командах сценария

  • Параметры пользователя, глобальные сценарии, а также внешние проверки теперь возвращают стандартную ошибку в вашем стандартном выводе - этим можно управлять в пределах машего запускающего механизма (триггера)

  • Существует поддержка множества значений

Теперь давайте рассмотрим в подробностях как же работают внешние проверки.

  Углубляясь во внешние проверки

Теперь самое время для практического примера. Это простой пример для понимания того, как работает внешний сценарий. В следующем примере мы будем подсчитывать число открытых файлов для определённого пользователя. Первая вещь, которую необходимо выполнить, это создать сценарий и расположить его в ExternalScripts. Этот сценарий будет называться lsof.sh и будет содержать следующий код:


#!/bin/bash
if grep -q $1 /etc/passwd
        then lsof -u $1 | tail -n +2 |wc -l
 else
        echo 0
fi
 	   

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

Теперь вам необходимо создать новый элемент с типом External check. В поле Key введите lsof.sh["postgres"], как это отображено на снимке экрана внизу:

 

Рисунок 1



Теперь, переместившись в Monitoring | Latest Data, можно будет увидеть те данные, которые получает ваш сценарий:

 

Рисунок 2



Внешний сценарий должен вернуться в разумные сроки; в противном случае данный элемент будет помечен как неподдерживаемый.

[Совет]Совет

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

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

В следующем примере мы будем осуществлять мониторинг определённого удалённого экземпляра Oracle. Существуют некоторые предварительные требования чтобы данная настроку оказалась полностью работающей: клиент Oracle устанавливается с рабочими sqlplus, tnsping а также учетной записью, настроенной на вашу целевую базу данных Oracle.

Самая последняя версия для данного программного обеспечения доступна для загрузки по адресу http://www.smartmarmot.com/product/check_ora.

Тем не менее, интересно посмотреть как она исполняется в версии 1.0. Версия 1.0 доступна для загрузки напрямую из форума Zabbix по адресу https://www.zabbix.com/forum/showthread.php?t=13666.

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

  1. Создать учётную запись пользователя во всех ваших базах данных, подлежащих мониторингу.

  2. Настроить своего клиента Oracle.

  3. Развернуть данный пакет в местоположении вашего внешнего сценария.

  4. Настроить учётную запись вашей базы данных в <EXTERNAL_SCRIP_LOCATION>/check_ora/credentials.

  5. Создать хост с тем же именем что и ваш экземпляр базы данных.

Последний пункт особенно важен и является определённым режимом применения Zabbix. Данный метод может повторно использоваться всякий раз, когда вам необходимо агрегировать метрики, которые не связываются с реальными хостами, а только с некоторой службой. Для выполнения примера из практики, допустим у вас имеется СУБД, которая может быть отказоустойчивой при поддержке другого сервера, вы просто можете создать обманный хост Zabbix который называется тем же именем, которое имеет ваша базаданных. Теперь, если данная служба выполняет действия по осуществлению отказоусточивости, у вас не будет прерывания в вашем сборе данных, так как процесс осуществления отказоустойчивости является прозрачным для сервера, который поддерживает эту службу. Данный метод применяется в нашем случае, поскольку клиент Oracle будет обрабатывать отказоустойчивость автоматически, в случае, когда он настроен надлежащим образом

Теперь вы можете продвинуться вперёд и создать хост с тем же самым именем что и ваш SID, например, у вас имеется подлежащий мониторингу экземпляр Oracle, который определён как ORCL в tnsnames_ora; таким образом, ваш хост Zabbix будет именоваться ORCL.

[Совет]Совет

Вы можете создать хосты, связанные с именами соответствующей службы; это позволит вам абстрагировать данную службу от того хоста, который предоставляет такую службу.

Подробности настройки лиента Oracle выходят за рамки данной книги. Когда вы выполните эту настройку, вы сможете протестировать данный сценарий просто выполнив следующую команду:


check_ora.sh[-i <instance> -q <query>]
 	   

В предыдущей командной строке <instance> представляет имя вашего экземпляра, а <query> является вашим файлом запроса, который вы хотите выполнить. Существует великое множество файлов предварительно построенных запросов в вашем каталоге check_ora; вы можете проверить их все для своей базы данных.

[Совет]Совет

Применение SID Oracle или имени экземпляра Oracle в качестве имени хоста для Zabbix действительно очень полезно в данном случае. Оно может быть расширено применением макроса HOSTNAME, и таким образом вы просто можете создавать ключ такой как check_ora.sh [-i {HOSTNAME} –q query] в своём шаблоне и он будет расширяться на все ваши базы данных.

Теперь, на хосте Zabbix, вам необходимо создать свой элемент для получения своей внешней проверки, и такой ключ будет иметь следующий вид:


check_ora.sh[-i {HOSTNAME} –q <queryhere>]
 	   

Например:


key="check_ora.sh[-i {HOSTNAME} -q lio_block_changes]"
 	   

Данный шаблон доступен на форуме в том же самом месте. Отметим, что HOSTNAME расширяется именем хоста, которое, в нашем случае, в точности является именем экземпляра Oracle. Вы можете получить обобщённый шаблон при помощи макроса HOSTNAME, а его элементы распространяются по всем хостам ваших баз данных.

Теперь жизненный цикл этого элемента будет следующим:

  1. Zabbix вызывает данный сценарий.

  2. Этот сценарий выполняет следующее:

    • Регистрируется в вашей базе данных

    • Выполняет запрос и получает его значение

    • Возвращает это значение в ваш стандартный вывод; Zabbix получает это значение и, если оно допустимо, оно будет сохранено.

  Войдём вовнутрь сценария

Ядром функции check_ora.sh является execquery(). Эта функция такова:


execquery () {
start_time=$(date +%s)
# echo "Time duration: $((finish_time - start_time)) secs."
echo "BEGIN check_ora.sh $1 $2 `date`" >> /tmp/checkora.log
cd $SCRIPTDIR;
sqlplus -S $1 <<EOF | sed -e 's/^\ *//g'
set echo off;
set tab off;
set pagesize 0;
set feedback off;
set trimout on;
set heading off;
ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,';
@$2
EOF
finish_time=$(date +%s)
echo "END check_ora.sh $1 $2 `date`" >> /tmp/checkora.log
echo "check_ora.sh $1 $2 Time duration: $((finish_time - start_time))secs." >> /tmp/checkora.log
}
 	   

Эта функция начнёт производить информацию протокола в /tmp/checkora.log:


start_time=$(date +%s)
# echo "Time duration: $((finish_time - start_time)) secs."
echo "BEGIN check_ora.sh $1 $2 `date`" >> /tmp/checkora.log
 	   

Важно понимать какая внешняя проверка осуществляется и с какой базой данных. Дополнительно, вы найдёте в своём файле протокола пройденное время для всей операции:


finish_time=$(date +%s)
echo "END check_ora.sh $1 $2 `date`" >> /tmp/checkora.log
echo "check_ora.sh $1 $2 Time duration: $((finish_time - start_time))secs." >> /tmp/checkora.log
}
 	   

Так как этот файл используется совместно (всеми вашими процессами check_ora.sh), а вызовы вашего Zabbix не являются последовательными, важно отчитаться строкой вызова сценария дважды с тем, чтобы вы могли в точности идентифицировать какая начинающая строка соответствует какой завершающей. В нашем случае, чтобы избежать любые сомнения, вычисляется и выводится в завершающем сообщении пройденное время.

После нашего сценария вызовем sqlplus:


sqlplus -S $1 <<EOF | sed -e 's/^\ *//g'
 	   

Здесь sed вычищает пустые пробельные символы в начале нашего вывода. Это делается потому что возвращаемые данные являются числом которое не может начинаться с пробела; если это случится, элемент станет неподдерживаемым!

Следующая часть кода делает клиента Oracle менее подробным:


set echo off;
set tab off;
set pagesize 0;
set feedback off;
set trimout on;
set heading off;
 	   

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


ALTER SESSION SET NLS_NUMERIC_CHARACTERS = '.,';
 	   

Этот раздел важен, так как вы можете иметь базы данных, установленные по различным причинам с различными наборами символов. Кроме того, данный клиент может применять другой разделитель для десятичных значений. Вам необходимо избегать всех неуправляемых соглашений о наборах символов, причём это общее правило. Наконец, ваш сценарий выполняет файл запроса следующим образом:


@$2
EOF
 	   

Ваш вывод возвращается в стандартный поток ввывода и собирается Zabbix.

  Общие правила написания сценариев

Данный сценарий охватывает все критически важные моменты, которым вам необходимо уделять внимание:

  • Не вводите в свой вывод нежелательные символы

  • Будьте осведомлены о типе; таким образом, если ожидается численное значяение, удалите все ненужные символы (например, идущие в начале пробелы)

  • Избегайте локальных преобразований численных значений; случай точки и запятой является хорошим примером

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

  • Будьте в курсе о затрачиваемом сценарием времени от момента когда сценарий вызван вплоть до вывода, осуществляемого вашим сценарием

  • Данные сценарии, естественно, выполняются с правами пользователя сервера Zabbix, поэтому возможно вам необходимо позаботиться о правах файла и полномочиях sudo

[Совет]Совет

Начиная с Zabbix 2.4, поток стандартного вывода связан вместе с стандартным потоком ошибок внутри вашего сценария.

Помните что, если запрашиваемый сценарий не найден или не имеет достаточных полномочий для исполнения на сервере Zabbix, данный элемент становится неподдерживаемым. Кроме того, в случае таймаута в обоих предыдущих случаях будет отображено сообщение об ошибке и ответвлённый процесс для этого сценария будет уничтожен.

 

Обсуждение внешних проверок

В данном разделе вы увидели как может быть выполнена внешняя проверка и как ею обрабатывается сложная задача навроде мониторинга базы данных. Если у вас имеется для реализации несколько внешних проверок, это может стать возможным решением для получения замеров. Такой вид подхода с внешними проверками, к сожалению, не является решением для всех ваших проблем. С другой стороны, вам необходимо учитывать, что они действительно интенсивно используют ресурсы и некогда широко применялись. Так как внешние проверки располагаются на стороне сервера, будет лучше не перегружать ваш сервер Zabbix.

[Совет]Совет

Каждый сценарий ExternalScripts требует от вашего сервера Zabbix запустить ответвление процесса; выполнение большого числа сценариев может сильно уменьшить производительность Zabbix.

Сервер Zabbix является ключевой компонентой вашей инфраструктуры мониторинга, и вы не можете воровать ресурсы у этого сервера.

 Параметр пользователя

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

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


UserParameter=,<shell command>
 	   

Здесь key должен быть уникальным, а команда shell представлять вашу команду для выполнения. Команда может быть определена здесь внутри строки и нет необходимости создавать сценарий, как это показано в следующем примере:


UserParameter=process.number, ps -e |wc -l
 	   

В этом примере ключ process.number будет извлекать общее число процессов в вашем сервере.

Аналогичным образом вы можете проверять общее число пользователей, которые в настоящее время подключены, применив следующий код:


UserParameter=process.number, who |wc -l
 	   

  Гибкий параметр пользователя

Как легко понять, применяя данный метод вы собираетесь определить большое число элементов внутри файла настроек своего агента. Это не правильный подход, так как лучше поддерживать свой файл настроек простым.

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


UserParameter=key[*],<shell command>
 	   

В данном случае key всё ещё должен быть уникальным, а выражение [*] определяет, что данный ключ принимает определёные параметры. Содержимое между квадратными скобками разбиратеся и подставляется при помощи $1...$9; отметьте, пожалуйста, что $0 ссылается на саму команду. В качестве примера UserParameter можно представить:


UserParameter=oraping[*],tnsping $1 | tail -n1
 	   

Данная команда выполнит tnsping к вашему SID, передавая его в качестве $1. Вы можете применить тот же самый метод в своём процессе подсчёта определённых пользователей следующим образом:


UserParameter=process.number[*], ps -e |grep ^$1 | wc -l
 	   

Затем, если мы хотим переместиться на сторону агента для своего первого сценария, который возвращал общее число открытых файлов для определённого пользователя, настройка будет такой:


UserParameter=lsof.sh[*],/usr/local/bin/lsof.sh $1
 	   

Когда это добавлено, вам остаётся только перезапустить своего агента. На стороне сервера вам необходимо переключить Type своего элемента на Zabbix agent и сохранить это. Следующий снимок экрана рисует это обсуждение:

 

Рисунок 3



При помощи того же самого метода вы можете настроить сценарий check_ora.sh для проверки базы данных при помощи следующего кода:


UserParameter=check_ora.sk[*],check_ora.sh –i $1 –q $2
 	   

На стороне сервера Zabbix вам необходимо создать элемент с типом агента Zabbix или с типом (активного) агента Zabbix, а в его ключе вам необходимо определить:


check_ora.sk[<databasename> <query_to_execute>]
 	   
[Совет]Совет

Вы можете проверить UserParameter воспользовавшись командной строкой, как это описывалось ранее, или применив утилиту zabbix_get. Воспользовавшись zabbix_get, вам не понадобится дожидаться того чтобы увидеть данные между самыми последними, к тому же это самый простой способ отладки, который осуществляется на вашей стороне агента.

Существуют способы проверки того хорошо ли работает ваш UserParameter и способен ли ваш агент распознавать его. Первый состоит в zabbix_get; например, в случае losf.sh со стороны сервера Zabbix мы можем применить следующее:


# zabbix_get -s 127.0.0.1 -p 10050 -k lsof.sh["postgres"]
2116
 	   

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


#/usr/sbin/zabbix_agentd -t lsof.sh["postgres"]
lsof.sh[postgres][/usr/local/bin/lsof.sh postgres] [t|2201]
 	   

Опять же, это высветит ваш вывод и сам сценарий который вызывается.

  Обсуждение параметров пользователя

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

Параметры UserParameter действительно являются гибкими. Чтобы включить их на стороне агента, вам необходимо изменить его файл настройки и перезапустить этот агент. Кроме того, в этом случае вам необходимо быть уверенным, что возвращаемое значение установлено надлежащим образом; если это не так, оно будет отвергаться.

Теперь, помимо всех против, вам необходимо учесть эффект своего наблюдателя (обсуждавшийся в Главе 1, Развёртывание Zabbix) вносимый таким видом мониторинга. Вам необходимо оставлять вещи лёгкими по возможности, в особенности из- за того, что ваш агент выполняется на том же сервере, который предоставляет эту службу.

Применение UserParameter подразумевает что вам необходимо распространять ваши сценарии и относительные обновления по всем вашим серверам. В данном примере, когда вы хотите осуществлять мониторинг Oracle, вам необходимо рассматривать сколько различных версий операционных систем и программного обеспечения вам необходимо обрабатывать. Может оказаться, что вам потребуется обрабатывать мириады различных версий ваших сценариев и программного обеспечения. Такое несметное число сценариев, версий и тому подобного хранится в централизованном репозитории. Кроме того, вам необходимо учитывать добавляемую вашими сценариями рабочую нагрузку и, если они не обрабатывают все возможные исключительные ситуации должным образом, это может быть действительно сложным для управления сеансом.

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

Ниже приведены определённые очень важные моменты о внешних сценариях и UserParameter:

  • Все детали ввода передаются в качестве параметров в ваши сценарии и должны быть надлежащим образом очищаться в пределах сценария для предотвращения внедрения команд.

  • Все значения возвращаются через STDOUT и должны быть в формате ожидаемом для возвращаемого типа. Если не возвращается ничего, это вызывает то, что сервер Zabbix помечает данный элемент как неподдерживаемый.

  • Убедитесь, что все сценарии завершаются в короткий промежуток времени.

  • Во избежание условий конкуренции или некорректного взаимодействия со стороны испытывающих многократное исполнение сценариев, проверьте что они не используют совместно или блокируют какие- либо ресурсы, или имеют какой- либо побочный эффект.

 Отправка данных посредством zabbix_sender

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

Zabbix предоставляет утилиты разработанные для отправки данных на свой сервер. Такой утилитой является zabbix_sender, и при её помощи мы можем отсылать данные элемента на ваш сервер используя элементы Zabbix типа ловушек (trapper).

Чтобы проверить утилиту zabbix_sender, просто добавьте элемент ловушки Zabbix в существующий хост и выполните команду:


zabbix_sender -z <zabbixserver> -s <yourhostname> -k <item_key> -o <value>
 	   

Вы получите отклик, похожий на следующее:


Info from server: "Processed 1 Failed 0 Total 1 Seconds spent 0.0433214" sent: 1; skipped: 0; total: 1
 	   

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

  Новый сценарий

Теперь мы можем изменить свой сценарий, который мы применяли ранее в качестве внешней проверки и добавить UserParameter в новую версию, которая отправляет ловушки в ваш сервер Zabbix.

Центральной частью нашей программы будет следующее:


CONNECTION=$( grep $HOST\; $CONNFILE | cut -d\; -f2) || exit 3;
RESULT=$( execquery $CONNECTION $QUERY.sql);
if [ -z "$RESULT" ]; then
       send $HOST $KEY "none"
       exit 0;
fi
send $HOST $QUERY "$RESULT"
exit 0;
 	   

Код выполняет следующие этапы:

  1. Извлекает строку соединения из файла:

    
    CONNECTION=$( grep $HOST\; $CONNFILE | cut -d\; -f2) || exit 3;
     	   
  2. Выполняет запрос, определённый в вашем файле $QUER.sql:

    
    RESULT=$( execquery $CONNECTION $QUERY.sql);
     	   
  3. Проверяет полученный результат данного запроса и если он не пустой, отсылает полученное значение Zabbix; в противном случае полученное значение замещается "none":

    
    if [ -z "$RESULT" ]; then
             send $HOST $KEY "none"
             exit 0;
    fi
    send $HOST $KEY "$RESULT"
     	   

В этом коде в игре присутствуют две основные функции: одной является функция execquery(), которая обычно не изменяется, и другая функция, send(). Функция send() играет ключевую роль в доставке данных в сервер Zabbix:


send () {
   MYHOST="$1"
   MYKEY="$2"
   MYMSG="$3"
   zabbix_sender -z $ZBX_SERVER -p $ZBX_PORT -s $MYHOST -k $MYKEY -o "$MYMSG";
}
 	   

Эта функция отправляет полученные значения с использованием командной строки в точности как это уже делалось при проверке утилиты zabbix_sender. Отправляемое на сторону сервера значение будет иметь соответствующий элемент вида улавливателя (trapper), а Zabbix будет получать ваши данные и сохранять их.

Теперь, чтобы автоматизировать весь процесс проверки, вам необходимо обернуть этот опрос между всеми вашими настроенными экземплярами Oracle, извлечение полученных данных, а также отправку их в Zabbix. Оболочка получает список ваших баз данных, а также относительные учётные данные для регистрации в системе из файла настройки, а вам необходимо осуществить рекурсивный вызов вашего сценария check_ora_sendtrap.sh.

  Написание обёртывающего сценария для check_ora_sendtrap

Поскольку данный сценарий будет выполняться из crontab, в качестве первой вещи следует соответственно наладить вашу среду на источник файла настройки:


source /etc/zabbix/externalscripts/check_ora/globalcfg
 	   

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


cd /etc/zabbix/externalscripts
 	   

Затем он начинает выполнять все свои запросы ко всем вашим базам данных:


for host in $HOSTS; do
  for qery in $QUERIES; do
         ./check_ora_sendtrap.sh -r -i $host -q ${query%.sql} &
         sleep 5
  done;
  ./check_ora_sendtrap.sh -r -i $host -t &
  sleep 5
  ./check_ora_sendtrap.sh -r -i $host -s &
done;
 	   

Отметим, что данный сценарий выполняет все свои запросы, а также извлекает времена tnsping и соединения для каждой базы данных. Существуют две переменные среды, которые используются для исполнения цикле по хостам и запросам; они наполняются двумя функциями:


HOSTS=$(gethosts)
QUERIES=$(getqueries)
 	   

Функция gethost извлекает имя вашей базы данных из файла настроек:


/etc/zabbix/externalscripts/check_ora/credentials
gethosts () {
   cd /etc/zabbix/externalscripts/check_ora
   cat credentials | grep -v '^#' | cut -d';' -f 1
}
 	   

Функция getquery проходит вниз по дереву каталога, извлекая все имеющиеся файлы ваших запросов:


getqueries () {
   cd /etc/zabbix/externalscripts/check_ora
   ls *.sql
}
 	   

Теперь вам необходимо только составить расписание для сценария оболочки (wrapper) в crontab, добавив в свой crontab следующий элемент:


*/5 * * * * /etc/zabbix/externalscripts/check_ora_cron.sh 	   

Ваш сервер Zabbix сохранит данные и отобразит график.

[Совет]Совет

Всё обсуждающееся здесь программное обеспечение доступно в SourceForge по ссылке https://sourceforge.net/projects/checkora, выпущенной в GPLv3, а также по адресу http://www.smartmarmot.com/ .

  За и против выделенного сервера сценариев

При данном подходе у нас имеется выделенный сервер для извлечения данных. Это означает, что вы не перегружаете свой сервер, который предоставляет вам службу или свой сервер Zabbix, и это действительно хороший момент.

К сожалению, данный подход страдает гибкостью, и в данном определённом случае все ваши элементы обновляются каждые 5 минут. С другой стороны, при ваших внешних проверках или с использованием UserParameter частота обновлений может меняться и быть персонально настраиваемой для элемента.

В данном определённом случае, при котором вовлечён сервер базы данных, присутствует эффект наблюдателя, вносимый нашим сценарием. Наш запрос может быть настолько легковесен, насколько мы пожелаем, однако для извлечения элемента sqlplus будет запрашивать Oracle для соединения. Такое соединение будет использоваться всего несколько секунд (время, необходимое для извлечения нашего элемента), после чего данное соединение будет закрыто. Все эти рабочие нагрузки обычно нуждаются в объединённом в пул подключении. Применяя пул подключений вы можете ощутимо сократить эффект наблюдателя в своей базе данных.

[Замечание]Замечание

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

Сбор соединений в пул всегда хорошая вещь, которой следует придерживаться в общем случае. Чтобы лучше понять преимущества такой методологии, вы можете рассмотреть сложную сетевую среду с путём, который пересекает различные межсетевые экраны и правила, прежде чем достигнет получателя; наличие постоянного соединения является явным преимуществом. Наличие пула постоянных соединений, поддерживаемых действующими пакетаами keep-alive уменьшает значение латентности для извлечения необходимого элемента из вашей базы данных и, в общем случае, нагрузку на сетевую среду в целом. Создание нового соединения включает процесс подтверждения всех пересекаемых межсетевых экранов. Кроме того, вам необходимо иметь в виду, что если вы используете Oracle, первый запрос на соединение выполняется к приёмнику (listener), который потребует обратной связи при приёме и тому подобного. К сожалению, пулы соединений не могут быть реализованы при помощи компонентов оболочки. Существуют различные реализации пулов соединений, однако, прежде чем мы окунёмся глубже в суть стороны программирования, самое время посмотреть на то, как работают протоколы Zabbix.

 Работа с протоколами Zabbix

Протокол Zabbix совершенно прост; это сильный момент, поскольку просто реализовать вашего собственного индивидуального агента или программу которая отправляет данные Zabbix.

Zabbix поддерживает различные версии протоколов. Мы можем разделить эти протоколы на три семейства:

  • Zabbix get

  • Zabbix sender

  • Zabbix agent

  Протокол get Zabbix

Протокол Zabbix get действительно очень простой и лёгкий в реализации. Практически вам необходимо всего лишь отослать данные на свой сервер Zabbix на порт 10050.

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


[root@zabbixserver]# telnet 127.0.0.1 10050
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
agent.version
ZBXD2.0.6Connection closed by foreign host.
 	   

Этот пример показывает как извлекать версию агента просто воспользовавшись telnet. Отметьте, пожалуйста, что ваши данные возвращаются с заголовком, которым является ZBXD, вслед за которым непосредственно следуют данные, представляющие реальный отклик 2.0.6.

Данный простой протокол полезен для извлечения данных из конкретного агента установленного на нашем сервере и ис пользуемого в сценарии оболочки.

Этот протокол полезен для идентификации версии агента без регистрации на вашем сервере и для проверки всех экземпляров UserParameter, определённых для некоторого агента.

  Протокол sender Zabbix

Протокол Zabbix sender является протоколом JSON. Сообщение составляется следующим образом:


<HEADER><DATA_LENGTH><DATA>
 	   

Раздел <HEADER> составляет 5 байт и представляется в виде ZBXD\x01. В действительности только первые 4 байта являются заголовком, следующий байт используется для определения версии протокола. В настоящее время поддерживается только версия 1 (0x 01 HEX).

Раздел <DATA_LENGTH> является 8 байтами в длину в шестнадцатеричном представлении. Таким образом, например, 1 выражается как 01/00/00/00/00/00/00/00, 8-байтовым (64- битным) числом в шестнадцатеричном формате.

За ним следует <DATA>. Этот раздел представляется в формате JSON.

[Замечание]Замечание

Начиная с версии 2.0.3 Zabbix может принимать только 128МБ данных для предотвращения переполнения оперативной памяти. Этот предел был добавлен для защиты вашего сервера от разрушений, вызываемых большими объёмами входных данных.

Для отправки своих значений сообщение JSON должно быть представлено в следующем виде:


<HEADER><DATA_LENGTH>{
  "request":"sender data",
  "data":[
  {
    "host":"Host name 1",
    "key":"item_key",
    "value":"XXX",
    "clock":unix_time_format
  },
  {
    "host":"Host name 2",
    "key":"item_key",
    "value":"YYY"
  }
],
"clock":unix_time_format
}
 	   

В предыдущем примере, как вы можете увидеть, множество элементов стоят в очереди в одном и том же сообщении если они поступают из различных хостов или относятся к различным ключам элемента.

[Замечание]Замечание

Элемент "clock" является не обязательным в данном протоколе и может быть опущен в вашем объекте JSON, также как и в самом конце текущего раздела данных.

Когда все элементы приняты, ваш сервер отсылает обратно свой отклик. Этот отклик имеет следующую структуру:


<HEADER><DATA_LENGTH>{
  "response":"success",
  "info":"Processed 6 Failed 1 Total 7 Seconds spent 0.000283"
}
 	   

Этот пример представляет сообщение отклика; ниже приведены некоторые соображения:

  • Отклик имеет состояние, которое может быть представлено в виде success|failure] и относится ко всей передаче вашего списка элементов в сервер Zabbix.

  • Может оказаться, как это отображено в данном примере, что некоторые из ваших элементов были неудачными. Вы просто получаете уведомление и не можете с ним больше ничего, кроме как отметить и записать это состояние в файле журнала.

    [Совет]Совет

    Важно сохранять отслеживание времени затраченного на отсылку вашего списка элементов, так как если это значение становится высоким или имеет ощутимые изменения, это означает, что наш сервер Zabbix испытывает нагрузку при получении элементов.

К сожалению, данный протокол не даёт вам обратной связи по тому, какие именно элементы потерпели неудачу и причине такого отказа. На время написания данного текста существует два запроса на функциональность, которые всё ещё находятся в рассмотрении:

  • По получению более читаемого вывода, посетите https://support.zabbix.com/browse/ZBXNEXT-935 {Прим. пер.: На момент перевода закрыт после внесения некоторых изменений в порядок обработки ошибок во входном потоке.}

  • По определению отказавших элементов, обсуждение идёт по ссылке https://support.zabbix.com/browse/ZBXNEXT-246 {Прим. пер.: на момент перевода обсуждение объединено с https://support.zabbix.com/browse/ZBXNEXT-38, находящемся в открытом состоянии.}

Теперь мы знаем как работает протокол sender Zabbix в версии 1.8 и старше.

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

К счастью, данная функциональность теперь принята во внимание и команда разработчиков работает над версией SSL, или даже ещё лучшей TLS.

Для получения дополнительной информации вы можете взглянуть на билет по ссылке https://support.zabbix.com/browse/ZBXNEXT-1263 {Прим. пер.: на момент перевода в версии 3.0 реализован TLS, см. спецификацию https://www.zabbix.org/wiki/Docs/specs/ZBXNEXT-1263.}

 

Занимательная недокументированная функциональность

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

Затем, взглянув в код zabbix_sender вы можете обнаружить следующий раздел, в котором реализуется протокол:


zbx_json_addobject(&sentdval_args.json, NULL);
zbx_json_addstring(&sentdval_args.json, ZBX_PROTO_TAG_HOST, hostname, ZBX_JSON_TYPE_STRING);
zbx_json_addstring(&sentdval_args.json, ZBX_PROTO_TAG_KEY, key, ZBX_JSON_TYPE_STRING);
zbx_json_addstring(&sentdval_args.json, ZBX_PROTO_TAG_VALUE, key_value, ZBX_JSON_TYPE_STRING);
 	   

Предыдущая часть кода реализует протокол JSON Zabbix и, в частности, этот раздел:


"host":"Host name 1",
"key":"item_key",
"value":"XXX",
 	   

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


if (1 == WITH_TIMESTAMPS)
  zbx_json_adduint64(&sentdval_args.json, ZBX_PROTO_TAG_CLOCK, atoi(clock));
 	   

В этом месте внутри вашего элемента предоставляется временной штамп и добавляется в качестве свойства объекта JSON, после чего данный элемент закрывается следующим образом:


zbx_json_close(&sentdval_args.json);
 	   
[Замечание]Замечание

Часы определяются как переменная int64 без знака.

.

Это действительно важное свойство, так как если вы пишите свой собственный zabbix_sender, вы можете определять временной штамп того, когда данный элемент был извлечён.

Существенным моментом является то, что при тестировании данного раздела Zabbix сохраняет значение времени часов, показывающих когда был извлечён данный элемент из вашей базы данных.

 

Применение свойств часов в элементах JSON

Знание этого совйтсва может быть применено для оптимизации вашего sender. Zabbix поддерживает 128МБ для отдельного соединения. Конечно, лучше избегать этого предела, так как если мы достигнем его, это будет означать, что наша реализация не будет выполнена надлежащим образом.

Свойство часов может применяться в двух сценариях:

  • Если необходима буферизация отправляемых элементов и если они отправляются внутри отдельных пакетов соединения

  • Если ваш сервер не доступен, вы можете выполнить кеширование и отправить этот элемент позже

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

Второй вариант делает возможным реализацию надёжного sender, который может обрабатывать время простоя сервера Zabbix и предохранять элементы в кеше в состоянии готовности к отправке до того момента, когда сервер вернётся в строй и заработает. Будьте любезны не наводнять свой сервер если он не доступен в течение длительного периода времени. Управляйте своим соединением путём отправки разумного числа элементов вместо длинного хвоста элементов.

  Протокол агента Zabbix

Этот протокол слегка сложнее, так как он включает в себя больше этапов и его диалоги являются более членораздельными. При запуске активного агента, первое что он выполняет это соединяется со своим сервером и запрашивает некую задачу для выполнения, в частности, какой элемент должен быть извлечён и его относительное время.

Помимо всего прочего, в приводимом ниже коде, сама форма протокола остаётся прежней в сравнении с применявшейся ранее:


<HEADER><DATA_LENGTH><DATA>
 	   

Теги <HEADER>, <DATA_LENGTH> и <DATA> объяснялись в предыдущем разделе.

Диалог начинается, когда агент отправляет следующий запрос серверу:


<HEADER><DATA_LENGTH>{
  "request":"active checks",
  "host":"<hostname>"
}
 	   

При данном виде запроса наш агент собирается узнать определённое для хоста имя в своём активном списке опроса (checklist). Ответ сервера, например, может быть следующим:


<HEADER><DATA_LENGTH>{
  "response":"success",
  "data":[{
    "key":"log[\/var\/log\/localmessages,@errors]",
    "delay":1,
    "lastlogsize":12189,
    "mtime":0
  },
  {
    "key":"agent.version",
    "delay":"900"
  }]
  "regexp":[
  {
    "name":"errors",
    "expression":"error",
    "expression_type":0,
    "exp_delimiter":",",
    "case_sensitive":1
  }]
}
 	   

Сервер Zabbix должен ответить success, после чего идёт перечень элементов и относительных задержек.

[Замечание]Замечание

В случае элементов log или logrt, наш сервер должен ответить значением lastlogsize. Агенту необходимо знать этот параметр для продолжения своей работы. Кроме того, для всех ваших элементов logrt необходимы mtime.

"regexp", который в данном примере является ответом нашему агенту, присутствует только если вы определили глобальные или регулярные выражения. Отметим, что если используются макросы пользователя, раскрывается ваш ключ параметра и в качестве key_orig отправляется первоначальный ключ. Первоначальный ключ является именем макроса вашего пользователя.

Когда получен отклик, ваш агент закрывает своё соединение TCP и осуществляет его разбор. Теперь этот агент запускает сбор всех элементов в отведённый ему период времени. Будучи собранными, эти элементы будут возвращены назад на ваш сервер:


<HEADER><DATA_LENGTH>{
  "request":"agent data",
  "data":[
      {
           "host":"HOSTNAME",
           "key":"log[\/var\/log\/localmessages]",
           "value":"Sep 16 18:26:44 linux-h5fr dhcpcd[3732]: eth0: adding default route via 192.168.1.1 metric 0",
           "lastlogsize":4315,
           "clock":1360314499,
           "ns":699351525
      },
      {
           "host":"",
           "key":"agent.version",
           "value":"2.0.1",
           "clock":1252926015
      }
  ],
  "clock":1252926016
}
 	   
[Замечание]Замечание

При реализации данного протокола убедитесь что вы возвращаете назад lastlogsize для всех своих элементов типа log и mtime для всех элементов logrt.

Сервер отвечает следующим:


{
  "response":"success",
  "info":"Processed 2 Failed 0 Total 2 Seconds spent 0.000110"
}
 	   

Кроме того, существует вероятность, что некоторые элементы не должны приниматься, однако, в настоящий момент не существует способа знать что это за элементы.

 

Некоторые наиболее вероятные отклики

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

  • Когда для хоста не осуществляется мониторинг

  • Когда хост не существует

  • Когда хост над хостом выполняется активный мониторинг, однако не существует активных элементов

В первом случае, когда для хоста не выполняется мониторинг, ваш агент получит следующий отклик от своего сервера:


<HEADER><DATA_LENGTH>{
  "response":"failed",
  "info":"host [Host name] not monitored"
}
 	   

Во втором случае, когда данный хост не существует, ваш агент получит следующий ответ:


<HEADER><DATA_LENGTH>{
  "response":"failed",
  "info":"host [Host name] not found"
}
 	   

В последнем случае, когда для данного хоста осуществляется {активный} мониторинг, однако отсутствуют активные элементы, ваш агент


<HEADER><DATA_LENGTH>{
  "response":"success",
  "data":[]
}
 	   

 Протокол обнаружения нижнего уровня

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

Давайте рассмотрим каким образом можно использовать ваш вывод для низкоуровневого обнаружения элемента, например, vfs.fs.discovery. Для просмотра этого вывода мы можем просто выполнить следующую команду:


$ zabbix_get –s 127.0.0.1 –k vfs.fs.discovery
{"data":[
{"{#FSNAME}":"/","{#FSTYPE}":"rootfs"},
{"{#FSNAME}":"/proc","{#FSTYPE}":"proc"},
{"{#FSNAME}":"/sys","{#FSTYPE}":"sysfs"}
…
]}]
 	   

В данном случае мы сократили вывод; тем не менее, как мы можем увидеть, данный вывод легко понять. Прежде всего, это форматированный в виде JSON вывод, причём в основном в формате ключ- значение.

Далее, как мы уже видели в Главе 7, Управление шаблонами, чтобы мы могли создавать все свои сценарии, нам необходимо надлежащим образом автоматизировать обнаружение подлежащих мониторингу сущностей.

Конечно, каждый сценарий стороны агента должен быть зарегистрирован в качестве UserParameter в zabbix_agent.conf. В противном случае, если это глобальный сценарий стороны сервера, он должен быть развёрнут в ExternalScriptspath, который вы настроили в zabbix_server.conf.

Давайте рассмотрим другой пример сценария обнаружения низкого уровня который может повторно применяться и будет полезен для помечивания всех ваших портов во всей вашей сетевой среде. Как уже обсуждалось в Главе 7, Управление шаблонами, нам следует иметь вывод в формате JSON со всеми открытыми портами и их относительным протоколом. Для сбора этой информации мы можем воспользоваться nmap. Чтобы установить nmap в Red Hat, вам необходимо выполнить следующую команду от имении root:


$ yum install nmap
 	   

Она установит только все необходимые нам внешние компоненты. Теперь, чтобы пометить все наши открытые порты на сервере, наилучшим вариантом будет выполнить сценарий на нашем сервере Zabbix, так как, вероятно, что эти порты открыты локально, но скрыты за межсетевым экраном и не доступны с нашего сервера Zabbix. Следовательно, если мы не можем их достичь, мы не можем даже осуществлять их мониторинг. Команда для выполнения быстрого сканирования портов применяет параметр –T<0-5>, который устанавливает ваш временной шаблон (наибольшее значение означает самый быстрый шаблон). В данном сценарии применяется параметр –T4, за которым следует опция –F (fast mode):


#!/bin/sh
#Start with JSON Header
echo '{'
echo ' "data":['
PORTS=( $(nmap -T4 -F ${1} | grep 'open' | cut -d" " -f1 ) )
COUNTER=${#PORTS[@]}
for PORT in "${PORTS[@]}"; do
        COUNTER=$(( COUNTER - 1))
        if [ $COUNTER -ne 0 ]; then
                echo ' { "{#PORT}":"'$(echo $PORT| cut -d/ -f1)}'", "{#PROTO}":"'$(echo $PORT| cut -d/ -f2)'" },'
        else
#it's the last element.
#To have valid JSON We don't add a trailing comma
                echo ' { "{#PORT}":"'$(echo $PORT| cut -d/ -f1)}'", "{#PROTO}":"'$(echo $PORT| cut -d/ -f2)'" }'
        fi
done
#End with JSON footer
echo ' ]'
echo '}'
 	   

Этот сценарий выполняет сканирование портов по указанному IP адресу, определяя все извлекаемые открытые порты которые не закрыты межесетвым экраном и соответствующий протокол. Вывод, осуществляемый данным сценарием таков:


# ports_ldd.sh 192.168.1.1
{
 "data":[
  { "{#PORT}":"22}", "{#PROTO}":"tcp" },
  { "{#PORT}":"25}", "{#PROTO}":"tcp" },
  { "{#PORT}":"53}", "{#PROTO}":"tcp" },
  { "{#PORT}":"80}", "{#PROTO}":"tcp" },
  { "{#PORT}":"111}", "{#PROTO}":"tcp" },
  { "{#PORT}":"631}", "{#PROTO}":"tcp" },
  { "{#PORT}":"3306}", "{#PROTO}":"tcp" },
  { "{#PORT}":"5432}", "{#PROTO}":"tcp" }
 ]
}
 	   

Это тот вид вывода, который мы ожидали и, как вы можете увидеть, он готов к применению. Конечно, данный сценарий должен быть размещён в местоположении ExternalScripts. Затем мы можем запустить создание новой закладки Discovery rule, как это отображено на следующем снимке экрана:

 

Рисунок 4



Это сделает две переменные {#PORT} и {#PROTO} готовыми к использованию внутри прототипов. Давайте создадим прототип нашего Элемента со следующими свойствами:

  • Name: Status of port {#PORT}/{#PROTO}

  • Type: Simple check

  • Key: net.tcp.service[{#PROTO},,{#PORT}]

  • Type of information: Numeric (unsigned)

  • Data type: Boolean

Это отображено на следующем снимке экрана:

 

Рисунок 5



Затем нам необходимо создать свой относительный прототип триггера со следующей информацией:

  • Name: {#PROTO} port {#PORT}

  • Expression: {Template_network:net.tcp.service[{#PROTO},,{#PORT}].last(0)}=0

При таком виде настройки наше обнаружение выолнит все свои задания для вас, найдёт все ваши открытые порты, которые можно достичь на сервере, и создаст конкретный элемент и относящийся к нему запускающий механизм (триггер), который будет будет запускаться если порт становится недоступным.

[Совет]Совет

В данном случае мы рассматриваем тот вариант, что вы хотите осуществлять мониторинг всех своих служб, доступных на некотором сервере и последующий запускающий механизм отправки вам сигнала тревоги в случае, если порт становится недоступным. Важно рассмотреть и другой случай, при котором вы находитесь в зоне DMZ и вы хотите иметь запускающий механизм если, по какой- либо причине, служба является доступной. Одним из типичных примеров является порт прослушивания (listener) вашей базы данных, который должен быть доступен только в пределах вашей DMZ, а не с внешней стороны её.

Это просто один пример автоматизации, причём достаточно простой, однако мы можем продвинуть автоматизацию дальше. Мы можем рассмотреть сетевую среду, в которой у вас имеется чётко определённый домен служб, и вы знаете используется ли демон или где, по крайней мере, не изменён титул демона для сокрытия идентичности данной службы. В данном случае полезная персонализация обнаружения отыщет все те порты и, если за ними идентифицированы определённые службы, применит соответствующий шаблон к подлежащему мониторингу серверу. Например, мы можем полагать, что если порт 80 открыт, то за ним находится служба Apache, и затем применить шаблон Apache выполненный индивидуально для данного хоста. Это, безусловно, автоматизирует и снизит стоимость и время начального запуска.

 Взаимодействие с Zabbix

Теперь вы знаете как работает протокол Zabbix, поэтому настало время рассмотреть некий код, который реализует данный протокол. Чтобы оставить вещи простыми, мы должны объяснить пример протокола zabbix_sender - самого простого способа отправки данных Zabbix.

Zabbix применяет JSON для описания объекта содержащего данные. Существует множество эффективных библиотек JSON которые можно применять, однако, чтобы сделать здесь вещи более простыми, такие библиотеки не будут использоваться.

  Реализация протокола Zabbix_sender в Java

Здесь мы увидим действительно простой пример реализации протокола zabbix_sender который, как вы знаете является самым простым способом отсылать ловушки Zabbix.

Часть приводимого ниже кода была сохранена настолько простой, насколько это возможно, а его цель состоит в предоставлении примера, отталкиваясь от которого вы можете начинать развивать свой собственный компонент мониторинга Zabbix:


private String buildJSonString(String host, String item,Long
timestamp, String value){
  return "{"
    + "\"request\":\"sender data\",\n"
    + "\"data\":[\n"
    +          "{\n"
      +         "\"host\":\"" + host + "\",\n"
      +         "\"key\":\"" + item + "\",\n"
      +         "\"value\":\"" + value.replace("\\", "\\\\") + "\",\n"
      +         "\"clock\":" + timestamp.toString()
      +       "}]}\n" ;
  }
 	   

Эта часть кода просто возвращает определённое сообщение JSON для его отправки в качестве тела. Вам только необходимо предоставить свой хост и элемент или, ещё лучше, определённый ключ элемента, значение и временной штамп для включения в данное сообщение, а он вернёт объект в виде строки в формате JSON.

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


String data = buildJSonString( host,item,value);
  zabbix = new Socket(zabbixServer, zabbixPort);
  zabbix.setSoTimeout(TIMEOUT);
  out = new OutputStreamWriter(zabbix.getOutputStream());
  int length = data.length;
 	   

Как вы видите, в данном коде программа открывает сокет, определяет таймаут и извлекает длину сообщения, теперь она готова к отправке этого сообщения. Пожалуйста, помните, что сообщение составляется в виде <HEADER><DATA_LENGTH><DATA>. Самый простой способ отослать наши заголовок и длину данных такой:


out.write(new byte[] {
  'Z', 'B', 'X', 'D',
  '\1',
  (byte)(length & 0xFF),
  (byte)((length >> 8) & 0x00FF),
  (byte)((length >> 16) & 0x0000FF),
  (byte)((length >> 24) & 0x000000FF), '\0','\0','\0','\0'});
 	   

Эта часть кода записывает сообщение в наш сокет, который действительно содержит значения хоста, элемента и величины:


out.write(data);
 	   

Не забудьте сбросить эти данные, закрыть свой сокет и завершить доставку следующим образом:


out.flush();
out.close();
 	   

Теперь нам нужно увидеть что наш сервер Zabbix ответит о нашем элементе:


in = zabbix.getInputStream();
final int read = in.read(response);
String respStatus = (String) getValue(response);
if (read !=2 || respStatus.equals(ZBX_SUCCESS)) {
  in.close();
}
 	   

Если этот отклик успешен, вы можете закрыть InputStream.

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

Когда вы извлекаете свои элементы, важно сохранять отслеживание их временных шатмпов. Для этой цели вы можете добавлять временной штамп в свой элемент и знать когда в действительности был извлечён данный замер.

В нашем предыдущем примере такой временной штамп не отсылался, так как это является необязательным, однако на практике хорошо его добавлять, в особенности если вы осуществляете буферизацию элемента; когда вы его отошлёте, элементы будут иметь правильный временной штамп.

  Реализация протокола Zabbix_sender в Python

В наши дни на Python написано большое число приложений, а он является языком программирования, который широко распространён и известен. По данной причине, это пример фундаментального вызова, который может стать отправной точкой для вашего персонального zabbix_sender на Python. Эта часть кода может быть расширена и интегрирована напрямую в вашу программу. Наличие функциональности интегрированной в ваше приложение может быть действительно интересным, так как такое приложение само по себе может отправлять состояние о своей жизнеспособности в ваш сервер Zabbix. Теперь самое время взглянуть на эту часть кода и то, как она работает.

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


import simplejson as smplj
items_data = []
 	   

Теперь извлекаем имеющийся временной штамп из наших элементов; если он null, мы получаем текущий временной штамп:


clock = zbxit.clock or time.time()
 	   

Сейчас вы можете начать создавать свой объект JSON для его включения в ваше сообщение Zabbix:


items_data.append(('\t\t{\n'
                   '\t\t\t"host":%s,\n'
                   '\t\t\t"key":%s,\n'
                   '\t\t\t"value":%s,\n'
                   '\t\t\t"clock":%s}') % (smplj.dump(zbxit.host), smplj.dump(zbxit.key), smplj.dump(zbxit.value), clock))
 	   

Теперь, когда ваш элемент был преобразован в объект JSON, самое время для его заголовка:


json_items = ('{\n'
              '\t"request":"sender data",\n'
              '\t"data":[\n%s]\n'
              '}') % (',\n'.join(items_data))
 	   

Следующий шаг состоит в извлечении значения длины нашего сообщения и добавления его в наш заголовок:


data_len = struct.pack('<Q', len(json_items))
 	   

Как уже обсуждалось ранее, в нашем случае сообщение помещается в виде <HEADER>+<DATA_LENGTH>+<JSON ITEM> следующим образом:


packet = 'ZBXD\1' + data_len + json_items
 	   

Затем наш сокет открывается и пакет будет отправлен:


zabbix = socket.socket()
zabbix.connect((zabbix_host, zabbix_port))
zabbix.sendall(packet)
 	   

Когда пакет отослан, настало время для получения отклика от нашего сервера Zabbix:


resp_hdr = _recv_all(zabbix, 13)
 	   

Далее мы проверяем его правильность:


if not resp_hdr.startswith('ZBXD\1') or len(resp_hdr) != 13:
    return False
resp_body_size = struct.unpack('<Q', resp_hdr[5:])[0]
resp_body = zabbix.recv(resp_body_size)
zabbix.close()
resp = smplj.loads(resp_body)
  if resp.get('response') != 'success':
    return False
return True
 	   

Эта порция кода является хорошим начальным моментом для разработки вашего протокола sender Zabbix на Python.

  Некоторые рассуждения о разработке агента

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

На данный момент у вас было два примера и вы легко можете начать отправку уловленного серверу Zabbix даже если это пока не полностью сконструированные компоненты.

В качестве первого момента важно понимать действительно ли будет необходимо отправлять эти данные в Zabbix в определённое расписанием время, которое не управляется с вашего сервера Zabbix. Эти две части реализуют код вашего протокола sender Zabbix, однако значение частоты с которой данные элементы должны извлекаться и отправляться не могут определяться с вашего сервера Zabbix. Здесь важно иметь в виду, кто будет управлять вашей программой. Будет ли это сервер Zabbix или ваша программа? Чтобы включить Zabbix для управления частотой дискретизации, необходимо реализовать пртокол вашего агента Zabbix. Протокол агента является слегка более составным и слегка более сложным в реализации. Тем не менее, эти два предлагаемых примера имеют все компоненты, необходимые для надлежащей обработки соответствующего протокола агента.

Существует ещё один подлежащий рассмотрению момент. Обычно разработчики имеют свои собственные предпочтения для языка программирования. В нашем случае важно применять правильный инструмент для решения данной проблемы. Пример из практики будет осуществлять мониторинг вашей базы данных Oracle. Поэтому ваша программа должна взаимодействовать с коммерческим программным обеспечением; самый простой и логичный выбор состоит в применении Java. Тепрь все поклонники Python зажмут свои носы! В данном случае важно иметь в виду, что вместо собственных предпочтений лучше придерживаться собственной сущности объекта мониторинга.

Oracle и базы данных обычно производят стандартные разработанные на промышленном уровне драйверы для Java чтобы взаимодействовать с ними. Большая часть разработчиков этой базы данных производят и, что более важно, обновляют, исправляют и разрабатывают собственные драйверы JDBC на непрерывной основе. Будет лучше доверить часть работы производителям. Кроме того, они знают собственные продукты лучше и вы можете получить по ним содействие.

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

  • Обработку минимального и максимального числа соединений

  • Проверки такого соединения перед его использованием вашей программой

  • Отправку пакета keep-alive (что очень полезно во избежание проблем с межсетевыми экранами)

  • Обработку в реальном масштабе времени, удалении всех ваших простаивающих соединений (уменьшение общего числа соединений на подлежащем мониторингу сервере)

Это только несколько моментов, покрываемых JDBC. Все эти мометны помогут вам сохранять ваш мониторинг легковесным и эффективным.

[Замечание]Замечание

Примером программы сделанной для мониторинга баз данных в общем является DBforBIX, доступная по ссылкам http://sourceforge.net/projects/dbforbix/ или http://www.smartmarmot.com/product/dbforbix/.

 Выводы

В этой главе мы ввели вас во все возможные способы которые могут помочь вам взаимодействовать со своим сервером, тем самым делая возможным Zabbix доставать элементы и замеры, которые в противном случае не поддерживаются. В данной главе мы увидели шаги, необходимые для перемещения сценариев мониторинга Oracle со стороны сервера на сторону клиента, а затем на их окончательное место назначения - выделенный сервер. Здесь мы изучили как простой сценарий растёт пока не становится сложным внешним программным обеспечением. На каждом этапе вы видели прогресс и анализировали все за и против каждого местоположения, которое проходит данный сценарий. Это не означает что вам необходим выделенный сервер для всех ваших проверок, однако если ваш мониторинг сценария широко и интенсивно применяется, тогда это будет хорошей практикой. Для каждого пройденного местоположения вы увидели положительные и отрицательные стороны этого конкретного местоположения. Теперь у вас имеется глобальное видение того, что может быть сделано и гдк будет правильно его размещать или прикреплять для действия. Теперь протоколы Zabbix больше не имеют секретов и вы можете расширять Zabbix идеально без каких- либо ограничений.

В нашей следующей главе вы изучите как взаимодействовать с Zabbix с использованием API. Следующая глава объяснит как вы можете получать преимущества от API Zabbix для массивных развёртываний хостов и пользователей, а также массовых и повторяющихся операций в целом.