Zabbix мониторинг состояния заданий в MS SQL Agent Jobs

Требования

Для мониторинга состояния заданий потребуется:

  1. установить ms sql client для Linux на сервер zabbix (скачать можно с сайта MS, там-же есть инструкция по его установке);
  2. создать скрипт для внешней проверки;
  3. создать элемент данных типа внешняя проверка и указать созданный скрипт с параметрами

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

Пример установки ms sql client

  1. Скачиваем архив msodbcsql-11.0.2270.0.tar.gz и распаковываем его например в /opt/msodbcsql-11.0.2270.0
  2. Скачиваем unixODBC нужной версии (wget http://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.0.tar.gz) и распаковываем его например в /opt/unixODBC-2.3.0
  3. Собираем и устанавливаем unixODBC-2.3.0 в отдельное место:
    cd /opt/unixODBC-2.3.0
    mkdir -p /opt/microsoft/msodbcsql
    CPPFLAGS="-DSIZEOF_LONG_INT=8"
    export CPPFLAGS
    ./configure --enable-gui=no \
                --enable-drivers=no \
                --enable-iconv \
                --with-iconv-char-enc=UTF8 \
                --with-iconv-ucode-enc=UTF16LE \
                --prefix=/opt/microsoft/msodbcsql \
                --libdir=/opt/microsoft/msodbcsql/lib64 \
                --sysconfdir=/opt/microsoft/msodbcsql/etc
    make
    make install
  4. Устанавливаем msodbcsql в отдельное место:
    cd /opt/msodbcsql-11.0.2270.0
    mkdir -p /opt/microsoft/msodbcsql/usr/bin
    export PATH=/opt/microsoft/msodbcsql/bin:$PATH
    export LD_LIBRARY_PATH=/opt/microsoft/msodbcsql/lib64
    ./install.sh install --bin-dir=/opt/microsoft/msodbcsql/usr/bin \
                         --lib-dir=/opt/microsoft/msodbcsql/lib64 \
                         --force
  5. Создаем пользователя в MS SQL и даем ему права на чтение базы msdb
  6. Создать скрипт запуска sqlcmd (см. ниже)

Скрипт запуска sqlcmd (mssql_query.sh):

Положить в /etc/zabbix/externalscripts

#!/bin/bash
pid=$$
export PATH=/opt/microsoft/msodbcsql/bin:$PATH
export LD_LIBRARY_PATH=/opt/microsoft/msodbcsql/lib64
debug=0
 
USERPW=${1%@*}
SERVERDB=${1#*@}
SERVER=${SERVERDB%/*}
DB=${SERVERDB#*/}
PW=${USERPW#*\%}
USER=${USERPW%\%*}
err="ERROR"
 
QUERY="SET NOCOUNT ON; $2"
SQLCMD=/opt/microsoft/msodbcsql/bin/sqlcmd-11.0.2270.0
LOG=/var/log/zabbix/sqlcmd.log
test $debug -eq 1 && echo -e "\n$1 $2" | awk '{print "'"$(date)"', '$pid': "$0}'>>$LOG
var=$((($SQLCMD -S "$SERVER" -d "$DB" -U "$USER" -P "$PW" -Q "$QUERY" -h-1 -W -r $3 1>&3 || echo "$err" 1>&3 ) 2>&1 | awk '{ print "'"$(date)"', '$pid': Query: '"$0"' '"$1"' '"$2"'"; print "'"$(date)"', '$pid': "$0 }'>>$LOG) 3>&1)
if [ -n "$var" -a "$var" != "NULL" ]; then
	echo "$var"
else
	echo 0
fi

Пример запроса:

./mssql_query.sh User%Password@ServerName/DBName "SELECT * FROM DBName.TestTable WHERE Status=1 group by Status;"

Если используется нестандартный порт, то указать строку соединения так:

./mssql_query.sh User%Password@ServerName,Port/DBName "SELECT * FROM DBName.TestTable WHERE Status=1 group by Status;"

Кроме того в процессе тестирования выявилось наличие ограничения в длине запроса, у меня получилось около 1000 символов, поэтому слишком длинные запросы не стоит задавать…

Пример создания скрипта внешней проверки (mssql_query_agent.sh):

Положить в /etc/zabbix/externalscripts

#!/bin/bash
mssql_query=/etc/zabbix/externalscripts/mssql_query.sh
 
step_count="select MAX(sjs.step_id) as max_step_id from dbo.sysjobsteps sjs inner join dbo.sysjobs sj on sjs.job_id = sj.job_id where sj.name = '$2'"
 
stepid="select sj.start_step_id from dbo.sysjobs sj where sj.name='$2' and sj.enabled=1"
 
query="select MAX(sjh.run_date),MAX(sjh.run_time),sjh.run_duration,sjh.run_status,sjs.step_id
from dbo.sysjobhistory sjh
inner join dbo.sysjobs sj on sjh.job_id=sj.job_id
inner join dbo.sysjobsteps sjs on sj.job_id=sjs.job_id and sjh.step_id=sjs.step_id
where sj.name='$2' and sj.enabled=1
and sjh.run_date>=(select MAX(last_run_date) from dbo.sysjobsteps sjs inner join dbo.sysjobs sj on sjs.job_id=sj.job_id where sj.name='$2' and step_id in ($stepid))
and sjh.run_time>=(select MAX(last_run_time) from dbo.sysjobsteps sjs inner join dbo.sysjobs sj on sjs.job_id=sj.job_id where sj.name='$2' and step_id in ($stepid))
group by sjh.run_duration,sjh.run_status,sjs.step_id
order by MAX(sjh.run_date),sjs.step_id"
 
errlistquery="SELECT sj.name, sjsr.last_run_date, sjsr.last_run_time, sjsr.last_run_outcome
FROM dbo.sysjobservers sjsr
inner join dbo.sysjobs sj on sj.job_id = sjsr.job_id
inner join dbo.sysjobschedules sjsc on sjsc.job_id = sjsr.job_id
where sjsr.last_run_outcome<>1 and sjsr.last_run_outcome<>3 and sj.enabled=1 and sjsr.last_run_date > 0 and sjsc.next_run_date > 0
order by sj.name"
 
MSDB="$1"
 
query_str() {
	$mssql_query "$MSDB" "$query"
}
query_errlist() {
	$mssql_query "$MSDB" "$errlistquery" "-s," | sort -u
}
query_stepcount() {
	$mssql_query "$MSDB" "$step_count"
}
 
jobhistory(){
	case $3 in
		status) query_str | awk 'BEGIN{status=0;count=0} {if(and(status==0,count==2)) {exit} else {status=$4; count=$5}} END{print status}';;
		lastdate) date -d "$(query_str  | awk 'BEGIN{status=0;count=0;date=0;time=0} {if(or(and(status==0,count==2),status==1)) {exit} else {status=$4; count=$5}; date=$1; time=$2} END{print date" "time}' | sed -r -e 's/([0-9]{0,2})([0-9]{2})([0-9]{2})$/\1:\2:\3/' -e 's/([[:space:]])(:[0-9])/\10\2/')" +%s;;
		stepcount) query_stepcount;;
		laststepcount) query_str | awk 'BEGIN{status=0;count=0} {if(and(status==0,count==2)) {exit} else {status=$4; count=$5}} END{print count}';;
		errlist) query_errlist ;;
		*) query_str | awk '{print $0}';;
	esac
}
 
jobhistory "$1" "$2" "$3"

Пример запроса:

./mssql_query_agent.sh User%Password@ServerName/msdb TestAgentJob status

Скрипт принимает параметры:

  • status (статус выполнения задания, описание статусов можно взять на страничке sp_help_jobhistory на сайте МS, коротко скажу что 1 — это все хорошо),
  • lastdate (дата последнего запуска),
  • stepcount (всего шагов в задании),
  • laststepcount (счетчик шагов, которые были выполнены в последний запуск задания),
  • errlist (общий список заданий с ошибками) выводит в виде строки, например:
    JobName1,LastStartDate1,LastStartTime1,LastStatus1;JobName2,LastStartDate2,LastStartTime2,LastStatus2;....

Создать новый элемент данных и установить:

Тип: Внешняя проверка

Ключ: mssql_query_agent.sh[«{$MSDB}», «{$QUERY_JOB_NAME}», «status»]
или: mssql_query_agent.sh[«{$MSDB}», «», «errlist»]

  • {$MSDB} — макрос прописать для узла сети: User%Password@ServerName/msdb
  • {$QUERY_JOB_NAME} — макрос прописать для узла сети: TestAgentJob
  • status — показать статус, можно указать другие параметры для запроса см. выше

Тип информации: числовой (целое), а для errlist — текст

Тип данных: десятичный

Единица измерения: для параметра lastdate установить unixtime, а для остальных пусто.

Отображение значения: для status можно настроить преобразование согласно списка значений (см. описание sp_help_jobhistory на сайте МS).

Вот и все, осталось все проверить, настроить триггеры и радоваться ))

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

Для создания правила, можно модернизировать скрипт (mssql_query_agent_list.sh):

#!/bin/bash
mssql_query=/etc/zabbix/externalscripts/mssql_query.sh
 
listquery="SELECT sj.name
FROM dbo.sysjobservers sjsr
inner join dbo.sysjobs sj on sj.job_id = sjsr.job_id
inner join dbo.sysjobschedules sjsc on sjsc.job_id = sjsr.job_id
where sj.enabled=1
order by sj.name"
 
MSDB="$1"
 
query_list() {
	$mssql_query "$MSDB" "$listquery" "-s," | sort -u
}
 
jobhistory(){
	case $2 in
		list) query_list | awk '{print $0}';;
		*) query_list | awk 'BEGIN{ s="{\n\t\"data\": [" } { s=s"\n\t{ \"{#SJNAME}\":\""$0"\" }," } END { sub(/,$/,"",s); print s"\n\t]\n}" }' ;; 
	esac
}
 
jobhistory "$1" "$2" "$3"

который будет выыводить список заданий в формате JSON.

Пример:

./mssql_query_agent_list.sh "user%password@server,port/msdb"
{
	"data": [
	{ "{#SJNAME}":"Backup.Subplan_1" },
	{ "{#SJNAME}":"Job1" },
	{ "{#SJNAME}":"Job2 Test" },
	{ "{#SJNAME}":"Test 3 Job" }
	]
}

Использовать данные в формате JSON для настройки правил обнаружения в zabbix

А дальше, как использовать эти данные в формате JSON для настройки правил обнаружения в zabbix, можно прочесть в https://www.zabbix.com/documentation/2.4/ru/manual/discovery/low_level_discovery

Обсуждение закрыто.