Cacti data queries

в 16:51, , рубрики: cacti, системное администрирование, скрипт, метки: , ,

Немногим больше года назад потребовалось решать задачу получения и отображения множества однотипных показателей с нескольких серверов, при этом количество серверов и количество снимаемых с них показателей с течением времени могло меняться. На узлы был установлен zabbix_agent, настроены пользовательские параметры, сделаны шаблоны, данные успешно попадали в Zabbix. Для второй системы — Cacti, на скорую руку был переделан найденный где-то скрипт, который собирал данные zabbix_get и использовал Data Queries. Но что-то в этом скрипте скоро сломалось и в качестве единственной рабочего решения был оставлен Zabbix.

Понять что же такое Data Queries и как сделать так чтобы всё заработало, нашлось время только на новогодних каникулах.

Повторю расхожее выражение про ленность сисадминов, которым хочется чтобы всё работало само по себе. В моём случае, чтобы для каждого контролируемого узла можно было сразу добавить все необходимые графики и при изменении количества снимаемых показателей нужная информация добавлялась, если не автоматически, то максимально просто. Хотелось иметь механизм который не только получает и обрабатывает данные, но и знает какие данные можно получить. Именно так и работает метод Data Queries, позволяющий собирать значения как Data Input и дополнительно возвращать список всех возможных параметров.

В Cacti такой подход встроен, что называется, из коробки. Для узлов использующих шаблон Generic SNMP можно видеть список всех сетевых интерфейсов, выбрать нужные и строить по ним необходимые графики связанным с ним Data Queries SNMP — Interface Statistics. Казалось бы, что проще, посмотреть как это устроено, почитать документацию здесь и здесь и переделать под себя. Но уж больно, на мой взгляд, неудачный и сложный пример скрипта выбран для описания, в котором я разобрался уже после того как всё сделал. Хотя пользовательская составляющая, куда что нажать в интерфейсе чтобы заработало вопросов не вызывает.

Итак, Data Queries представлен тремя разновидностями: Get SNMP Data, Get Script Server Data, Get Script Data

  1. Get SNMP Data представлен только XML шаблоном, задающим какие параметры снимать и откуда, конечно, используя протокол SNMP;
  2. Методы Get Script Server Data и Get Script Data, определяются XML шаблоном и связанным с ним скриптом. Только в случае Get Script Server Data была произведена оптимизация скорости выполнения, за счёт использования общего PHP процесса, что требует использовать PHP. Get Script Data самый общий подход, далее будем рассматривать только его.

Со стороны Cacti это выглядит так. Из XML шаблона считываются параметры работы скрипта и аргументы которые надо будет отображать. После привязки Data Queries к узлу, у скрипта будет запрошен и запомнен список всех возможных элементов (индексов) для которых он будет возвращать значения. Если данные поменяются, необходимо заново их перечитать выполнив из интерфейса Reload Data Query для привязанного метода. Во время очередного опроса, тот же скрипт должен будет вернуть запрашиваемые данные для указанного индекса и аргумента. Каждый раз это будет разный вызов скрипта, по всем запомненным индексам и каждому из отображаемых аргументов. После этого сохранить в Data Source и нарисовать на графике.

Задача которую надо решить — забрать с подконтрольных серверов результаты опроса fping, где в качестве параметра указывается удалённый узел, например, ya.ru или habrahabr.ru. А ответ это значения задержек и потерь. Соответственно с каждого сервера мы можем пинговать много других узлов. Список узлов должны получать автоматически.

Сначала сформируем XML шаблон

Общие параметры

<name> и <description> — что это и для чего предназначено, чтобы не запутаться:

<name>Get fping stats</name>
<description>Remote monitoring fping statistics</description>

<script_path> — полный путь до файла скрипта, можно использовать переменную |path_cacti|:

<script_path>|path_cacti|/scripts/query-fping-stat.sh</script_path>

<arg_index>, <arg_num_indexes>, <arg_query>, <arg_get> — значения параметров передаваемых скрипту, которые определят режим его работы и какие значение он вернёт. Всего четыре режима, ничего сложного не выдумываем:

<arg_index>index</arg_index>
<arg_num_indexes>num_indexes</arg_num_indexes>
<arg_query>query</arg_query>
<arg_get>get</arg_get>

<arg_prepend> — параметры которые будут переданы в командной строке скрипта первыми. Автоматически в скрипт не будут переданы ни какие другие параметры, кроме тех которые определяют режим его работы, то есть мы не знаем для какого сервера мы выполняем наши действия. Необходимые дополнительные аргументы определяются здесь. Также разрешено использовать переменные:

<arg_prepend>|host_hostname|</arg_prepend>

<output_delimeter> — символ разделитель в возвращаемых значениях. Тоже ничего замысловатого — используем двоеточие:

<output_delimeter>:</output_delimeter>

Для нас этого хватит, параметров не так много, вот то что осталось.

Поля данных

Здесь описываем какие данные необходимо получить на выходе. Значения разделены на два типа Input и Output.

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

Кроме того формируются переменные |query_имя_поля|, которые можно использовать в подписи графиков и их значения будут отображаться в общем списке элементов при вызове Create Graphs for this Host как отдельные столбцы.

Тип Output – поля, данные которых будут строиться на графиках.

Непосредственно поле определяется очень просто:

<name> — имя, <query_name> — значение которое будет передано скрипту и <direction> — тип Input или Output.

У нас одно Input поле, возвращающее имя узла. Переменная которая будет создана |query_host|:

<host>
     <name>host</name>
     <direction>input</direction>
     <query_name>host</query_name>
</host>

И четыре Output поля, максимальная, минимальная, средняя задержка отклика и проценты потери пакетов:

<avg>
    <name>avg</name>
    <direction>output</direction>
    <query_name>avg</query_name>
</avg>
<max>
    <name>max</name>
    <direction>output</direction>
    <query_name>max</query_name>
</max>
<min>
    <name>min</name>
    <direction>output</direction>
    <query_name>min</query_name>
</min>
<loss>
    <name>loss</name>
    <direction>output</direction>
     <query_name>loss</query_name>
</loss>

XML шаблон целиком

<interface>
	<name>Get fping stats</name>
	<description>Remote monitoring fping statistics</description>
	<script_path>|path_cacti|/scripts/query-fping-stat.sh</script_path>
	<arg_index>index</arg_index>
	<arg_query>query</arg_query>
	<arg_get>get</arg_get>
	<arg_num_indexes>num_indexes</arg_num_indexes>
	<arg_prepend>|host_hostname|</arg_prepend>
	<output_delimeter>:</output_delimeter>
	<fields>
                <host>
                        <name>host</name>
                        <direction>input</direction>
                        <query_name>host</query_name>
                </host>
                <avg>
                        <name>avg</name>
                        <direction>output</direction>
                        <query_name>avg</query_name>
                </avg>
                <max>
                        <name>max</name>
                        <direction>output</direction>
                        <query_name>max</query_name>
                </max>
                <min>
                        <name>min</name>
                        <direction>output</direction>
                        <query_name>min</query_name>
                </min>
                <loss>
                        <name>loss</name>
                        <direction>output</direction>
                        <query_name>loss</query_name>
                </loss>
        </fields>
</interface>

Скрипт

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

Index

<script_path> <arg_prepend> <arg_index>

Вывод всех возможных значений индексов, каждый с новой строки. Для решаемой задачи это список всех возможных удалённых узлов которые наблюдаются на подконтрольном сервере. Все серверы выдают одинаковый набор данных, поэтому определим их непосредственно в скрипте, это единственное место где надо будет что-то менять. Конечно набор данных может быть разным и его можно забирать непосредственно с сервера, при необходимости. Для какого сервера мы должны вернуть список узнаём из первого параметра, который, напомню, в шаблоне задан как |host_hostname|:

hosts="ya.ru habrahabr.ru"
zabbix="/usr/local/bin/zabbix_get -s $1"
case $2 in
        index)
                for host in $hosts; do echo $host; done
        ;;
esac

Num_indexes

<script_path> <arg_prepend> <arg_num_indexes>

Количество индексов из первого режима:

numhosts=`echo $hosts | wc -w`
case $2 in
        num_indexes)
                echo $numhosts
        ;;
esac

Query

<script_path> <arg_prepend> <arg_query> <query_name>

Выполняется для всех полей данных определённых как Input. На выходе должны получить <index><output_delimeter><значение> для каждого индекса и указанного поля данных, каждое с новой строки. Так как в шаблоне определено только одно значение, а индекс у нас является легко читаемым, поэтому используем его же в качестве результата:

case $2 in
        query)
                for host in $hosts
                        do case $3 in
                            host) echo $host:$host
                        ;;
                        esac
                done
        ;;
esac

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

Get

<script_path> <arg_prepend> <arg_get> <query_name> <index>

Вызывается для всех полей данных определённых как Output. На выходе должны получить <значение> для указанного поля и индекса. Что проще чем в Data Input, где надо выдавать значения в форматируемой строке, здесь всё уже определено в шаблоне:

zabbix="/usr/local/bin/zabbix_get -s $1"
get_ping () {

    res=`$zabbix -k ping[$1,$2]`
    if [ -z $res ]
    then
        res=-1
    fi

    echo $res
}
case $2 in
        get)
            echo $(get_ping $4 $3)
        ;;
esac

Весь код

#!/bin/sh

hosts="ya.ru habrahabr.ru"
numhosts=`echo $hosts | wc -w`

zabbix="/usr/local/bin/zabbix_get -s $1"

get_ping () {
    res=`$zabbix -k ping[$1,$2]`
    if [ -z $res ]
    then
        res=-1
    fi
    echo $res
}

case $2 in
        index)
                for host in $hosts; do echo $host; done
        ;;
        num_indexes)
                echo $numhosts
        ;;
        query)
                for host in $hosts
                        do case $3 in
                            host) echo $host:$host
                        ;;
                        esac
                done
        ;;
        get)
            echo $(get_ping $4 $3)
        ;;
esac
exit 0

Осталось проверить — создаём Data Queries привязываем его к узлу и выполняем отладочный запуск Verbose Query.

Шаблон без ошибок:

+ Found data query XML file at '/usr/local/cacti/resource/script_queries/fping-stat.xml'
+ XML file parsed ok.

Режим Num_indexes, количество элементов:

+ Executing script for num of indexes '/usr/local/cacti/scripts/query-fping-stat.sh server num_indexes'
+ Found number of indexes: 2

Режим Index, cписок всех элементов:

+ Executing script for list of indexes '/usr/local/cacti/scripts/query-fping-stat.sh server index' Index Count: 2
+ Found index: ya.ru
+ Found index: habrahabr.ru

Режим Query, значения Output всех аргументов для всех элементов:

+ Executing script query '/usr/local/cacti/scripts/query-fping-stat.sh server query host'
+ Found item [host='ya.ru'] index: ya.ru
+ Found item [host='habrahabr.ru'] index: habrahabr.ru

Если всё работает, тогда поступаем также как и всегда в Cacti, формируем шаблон данных, шаблоны графиков. Связываем вместе, это надо сделать непосредственно в созданном Data Queries. После этого мы должны получать список доступных параметров автоматически при использовании Create Graphs for this Host.

Теперь создаём график, после этого в Poller для каждого аргумента Input, каждого индекса и каждого узла добавляется вызов скрипта. При просмотре Poller Cache видно, в том числе, и с какими параметрами вызывается скрипт:

Script: /usr/local/cacti/scripts/query-fping-stat.sh server get avg ya.ru

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

P.S. Удалось починить что было сломано?

Когда текст уже полностью был готов, взглянув на графики я понял что даже изрядно переделанный прошлогодний вариант не устраняет проблему. На многих других графиках, которые используют стандартные Data Queries Script, через некоторое время после повторного внедрения описанного решения, несколько раз за сутки не происходит снятие и отображение данных. Возможно особенность используемой инфраструктуры, или ошибки конфигурации. В любом случае это не отменяет удобства Data Queries, а причину...: «Будем искать» (с)

Автор: Loiqig

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js