Monitoração Zabbix de Jobs e Processos do Bacula

Este é um fork de um projeto do GIT com algumas correções. Verifique possíveis atualizações: https://github.com/germanodlf/bacula-zabbix

Esse projeto consiste de um shell script que coleta informações do servidor do Bacula, envia para o servidor Zabbix através de seu cliente (Zabbix sender), e um template a ser instalado no servidor de monitoração.

Características

  • Monitoramento individual para cada Job de backup
  • Diferentes níveis de Job têm diferentes gravidades
  • Monitoramento dos processos do Diretor, Storage e Cliente do Bacula
  • Gráficos e dashboards
  • Funciona com Catálogos do Bacula em PostgreSQL e MySQL

Dados Coletados pelo Script

  • Status de término do Job (item OK)
  • Número de bytes transferidos (item Bytes)
  • Número de arquivos transferidos (item Files)
  • Duração (item Time)
  • Taxa de transferência (item Speed)
  • Taxa de compactação (item Compression)

Dados dos Processos do Bacula

  • Status do processo do Bacula Director. O nome do processo é definido pela variável {$BACULA.DIR} e tem seu valor padrão como ‘bacula-dir’. Este item precisa ser desabilitado em hosts que são apenas clientes do Bacula.
  • Status do Storage Daemon. O nome do processo é definido pela variável {$BACULA.SD} e tem seu valor padrão como ‘bacula-sd’. Este item precisa ser desabilitado em hosts que são apenas clientes do Bacula.
  • Status do File Daemon. O nome do processo é definido pela variável {$ BACULA.FD} e tem seu valor padrão como ‘bacula-fd’.

Gatilhos

  • O daemon do Bacula está DOWN em {HOST.NAME}: Inicia um alerta de gravidade do desastre quando o processo do Bacula está parado
  • Backup Full FAIL em {HOST.NAME}: inicia um alerta de alta gravidade quando uma tarefa de backup completo falha
  • Backup Diferencial FAIL em {HOST.NAME}: inicia um alerta de gravidade médio quando uma tarefa de backup diferencial falha
  • Backup Incremental FAIL em {HOST.NAME}: inicia um alerta de gravidade de aviso quando uma tarefa de backup incremental falha

Configuração

Template Zabbix

Faça o download do template xml (zip) e importe-o para o seu servidor Zabbix.

Prossiga com a instalação do script nas máquinas com Bacula à seguir. Posteriormente, o modelo do Zabbix deverá ser fornecido a cada um desses hosts. Cada host configurado no Zabbix com este modelo vinculado precisa ter seu nome igual ao nome configurado no recurso Cliente do Bacula. Caso contrário, os dados coletados pelo script bash não serão recebidos pelo servidor Zabbix.

Script Zabbix Servidor Bacula

Instale o Zabbix Sender e o Agent. Exemplo CentOS 7:

rpm -Uivh https://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-sender-3.0.22-1.el7.x86_64.rpm
rpm -Uivh https://repo.zabbix.com/zabbix/3.0/rhel/7/x86_64/zabbix-agent-3.0.22-1.el7.x86_64.rpm
systemctl enable zabbix-agent

Modifique as configurações do Agente Zabbix necessárias como endereço do Server, Porta e Hostname da máquina do agente, se necessário. Reinicie o serviço para aplicar as alterações:

vi /etc/zabbix/zabbix_agentd.conf
...
Server=192.168.0.50
ListenPort=10051
...
:x!

service zabbix-agent restart

Crie o arquivo de configuração /opt/bacula/etc/bacula-zabbix.conf com o seguinte conteúdo. Modifique com as informações de seu ambiente:

### BACULA CONFIG ###

# IP address or FQDN of database server
baculaDbAddr='127.0.0.1'

# TCP port of database server
baculaDbPort='5432'

# Name of the database used by Bacula
baculaDbName='bacula'

# User used by Bacula on it's database
baculaDbUser='bacula'

# Password used by Bacula on it's database
baculaDbPass=''

### ZABBIX CONFIG ###

# IP address or FQDN of Zabbix server
zabbixSrvAddr='192.168.37.200'

# TCP port of Zabbix server
zabbixSrvPort='10051'

# Path to zabbix_sender command
zabbixSender='/usr/bin/zabbix_sender'

Forneça permissões ao usuário Bacula ao arquivo .conf criado.

chown root:bacula /opt/bacula/etc/bacula-zabbix.conf
chmod 640 /opt/bacula/etc/bacula-zabbix.conf

Crie o arquivo de script bash /opt/bacula/scripts/bacula-zabbix.bash, com o conteúdo que segue. Para Catálogo PostgreSQL:

#!/bin/bash
#
# For PGSQL

# Import configuration file
source /opt/bacula/etc/bacula-zabbix.conf

sql="/usr/bin/psql -qtAX -h$baculaDbAddr -p$baculaDbPort -U$baculaDbUser -d$baculaDbName -c"
# With Password
# sql="PGPASSWORD=$baculaDbPass /usr/bin/psql -qtAX -h$baculaDbAddr -p$baculaDbPort -U$baculaDbUser -d$baculaDbName -c"

# Get Job ID from parameter
baculaJobId="$1"
if [ -z $baculaJobId ] ; then exit 3 ; fi

# Test if zabbix_sender exists and execute permission is granted, if not, exit
if [ ! -x $zabbixSender ] ; then exit 5 ; fi

# Get Job type from database, then if it is a backup job, proceed, if not, exit
baculaJobType=$($sql "select Type from Job where JobId=$baculaJobId;" 2>/dev/null)
if [ "$baculaJobType" != "B" ] ; then exit 9 ; fi

# Get Job level from database and classify it as Full, Differential, or Incremental
baculaJobLevel=$($sql "select Level from Job where JobId=$baculaJobId;" 2>/dev/null)
case $baculaJobLevel in
  'F') level='full' ;;
  'D') level='diff' ;;
  'I') level='incr' ;;
  *)   exit 11 ;;
esac

# Get Job exit status from database and classify it as OK, OK with warnings, or Fail
baculaJobStatus=$($sql "select JobStatus from Job where JobId=$baculaJobId;" 2>/dev/null)
if [ -z $baculaJobStatus ] ; then exit 13 ; fi
case $baculaJobStatus in
  "T") status=0 ;;
  "W") status=1 ;;
  *)   status=2 ;;
esac

# Get client's name from database
baculaClientName=$($sql "select Client.Name from Client,Job where Job.ClientId=Client.ClientId and Job.JobId=$baculaJobId;" 2>/dev/null)
if [ -z $baculaClientName ] ; then exit 15 ; fi

# Initialize return as zero
return=0

# Send Job exit status to Zabbix server
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.status" -o $status >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+1)) ; fi

# Get from database the number of bytes transferred by the Job and send it to Zabbix server
baculaJobBytes=$($sql "select JobBytes from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.bytes" -o $baculaJobBytes >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+2)) ; fi

# Get from database the number of files transferred by the Job and send it to Zabbix server
baculaJobFiles=$($sql "select JobFiles from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.files" -o $baculaJobFiles >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+4)) ; fi

# Get from database the time spent by the Job and send it to Zabbix server
baculaJobTime=$($sql "select round(cast( float8 (EXTRACT(EPOCH FROM EndTime-StartTime)) as numeric)) from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.time" -o $baculaJobTime >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+8)) ; fi

# Get Job speed from database and send it to Zabbix server
baculaJobSpeed=$($sql "select case when EXTRACT(EPOCH FROM EndTime-StartTime) <= 0 then 0 else round(cast( float8 (JobBytes/EXTRACT(EPOCH FROM EndTime-StartTime)/1024) as numeric),2) end from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.speed" -o $baculaJobSpeed >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+16)) ; fi

# Get Job compression rate from database and send it to Zabbix server
baculaJobCompr=$($sql "select round(1-JobBytes/ReadBytes,2) from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.compr" -o $baculaJobCompr >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+32)) ; fi

# Exit with return status
exit $return

Para Catálogo MySQL:

#!/bin/bash
#
# For MYSQL

# Import configuration file
source /opt/bacula/etc/bacula-zabbix.conf

sql="/usr/bin/mysql -NB -h$baculaDbAddr -P$baculaDbPort -u$baculaDbUser -p$baculaDbPass -D$baculaDbName -e"

# Get Job type from database, then if it is a backup job, proceed, if not, exit
baculaJobType=$($sql "select Type from Job where JobId=$baculaJobId;" 2>/dev/null)
if [ "$baculaJobType" != "B" ] ; then exit 9 ; fi

# Get Job level from database and classify it as Full, Differential, or Incremental
baculaJobLevel=$($sql "select Level from Job where JobId=$baculaJobId;" 2>/dev/null)
case $baculaJobLevel in
  'F') level='full' ;;
  'D') level='diff' ;;
  'I') level='incr' ;;
  *)   exit 11 ;;
esac

# Get Job exit status from database and classify it as OK, OK with warnings, or Fail
baculaJobStatus=$($sql "select JobStatus from Job where JobId=$baculaJobId;" 2>/dev/null)
if [ -z $baculaJobStatus ] ; then exit 13 ; fi
case $baculaJobStatus in
  "T") status=0 ;;
  "W") status=1 ;;
  *)   status=2 ;;
esac

# Get client's name from database
baculaClientName=$($sql "select Client.Name from Client,Job where Job.ClientId=Client.ClientId and Job.JobId=$baculaJobId;" 2>/dev/null)
if [ -z $baculaClientName ] ; then exit 15 ; fi

# Initialize return as zero
return=0

# Send Job exit status to Zabbix server
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.status" -o $status >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+1)) ; fi

# Get from database the number of bytes transferred by the Job and send it to Zabbix server
baculaJobBytes=$($sql "select JobBytes from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.bytes" -o $baculaJobBytes >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+2)) ; fi

# Get from database the number of files transferred by the Job and send it to Zabbix server
baculaJobFiles=$($sql "select JobFiles from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.files" -o $baculaJobFiles >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+4)) ; fi

# Get from database the time spent by the Job and send it to Zabbix server
baculaJobTime=$($sql "select timestampdiff(second,StartTime,EndTime) from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.time" -o $baculaJobTime >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+8)) ; fi

# Get Job speed from database and send it to Zabbix server
baculaJobSpeed=$($sql "select round(JobBytes/timestampdiff(second,StartTime,EndTime)/1024,2) from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.speed" -o $baculaJobSpeed >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+16)) ; fi

# Get Job compression rate from database and send it to Zabbix server
baculaJobCompr=$($sql "select round(1-JobBytes/ReadBytes,2) from Job where JobId=$baculaJobId;" 2>/dev/null)
$zabbixSender -z $zabbixSrvAddr -p $zabbixSrvPort -s $baculaClientName -k "bacula.$level.job.compr" -o $baculaJobCompr >/dev/null 2>&1
if [ $? -ne 0 ] ; then return=$(($return+32)) ; fi

# Exit with return status
exit $return

Reinicie o serviço do Director.

service bacula-dir restart

Monitoração dos Clientes Bacula

Edite seus hosts que configuraram tarefas de backup para usar o template do Zabbix. Não esqueça desabilitar nos hosts que são apenas clientes do Bacula os itens que checam os processos do Bacula Director e Storage, e de usar o nome do Host na console do Zabbix igual ao nome dos Clientes configurados no Bacula, como no exemplo (Client Name BKP01-fd):

Monitoração Zabbix de Jobs e Processos do Bacula 1

Você pode executar o script manualmente inforomando um JobId para passar as informações (ex.: 99) para testar os scripts.

/opt/bacula/scripts/bacula-zabbix.bash 99

Em caso de problemas, você pode executar com a opção sh -x para depurar as consultas ao Catálogo do Bacula.

sh -x /opt/bacula/scripts/bacula-zabbix.bash 110

# Queries will appear. Try one.

/usr/bin/zabbix_sender -z 192.168.0.50 -p 10051 -s BKP01-fd -k bacula.diff.job.speed -o 137.89
info from server: "processed: 1; failed: 0; total: 1; seconds spent: 0.000070"
sent: 1; skipped: 0; total: 1

Adicione no JobDefs do Bacula uma configuração para sempre executar os clientes após todo Job de backup terminado, passando o JobId  do mesmo:

RunAfterJob="/opt/bacula/scripts/bacula-zabbix.bash %i"

Screenshots

Monitoração Zabbix de Jobs e Processos do Bacula 2 Monitoração Zabbix de Jobs e Processos do Bacula 3 Monitoração Zabbix de Jobs e Processos do Bacula 4

Disponível em: pt-brPortuguêsenEnglish (Inglês)esEspañol (Espanhol)

Este post tem 2 comentários

  1. Rodrigo Araujo

    Boa tarde,

    Estou tentando executar o procedimento no bacula 9.0.9, porem tenho essa saída:

    [root@prod-bacula scripts]# sh -x /etc/bacula/scripts/bacula-zabbix.bash 669
    + source /etc/bacula/bacula-zabbix.conf
    ++ baculaDbSgdb=M
    ++ baculaDbAddr=intranet.aaaaaaaaaaaaaaaa.amazonaws.com
    ++ baculaDbPort=xxxx
    ++ baculaDbName=xxxx
    ++ baculaDbUser=bacula
    ++ baculaDbPass=’aaaaaaaaaaaaaaaaaaa’
    ++ zabbixSrvAddr=noc
    ++ zabbixSrvPort=10051
    ++ zabbixSender=/bin/zabbix_sender
    + sql=’/usr/bin/mysql -hintranet.aaaaaaaaaaaaaaaa.amazonaws.com -uxxxx -paaaaaaaaaaaaaaaaaaa -Dbacula -e’
    + baculaJobId=669
    + ‘[‘ -z 669 ‘]’
    ++ /usr/bin/mysql -hintranet.aaaaaaaaaaaaaaaa.amazonaws.com -uxxxx ‘-paaaaaaaaaaaaaaaaaaa’ -Dbacula -e ‘select Type from Job where JobId=669;’
    + baculaJobType=’Type
    B’
    + ‘[‘ ‘Type
    B’ ‘!=’ B ‘]’
    + exit 9

    1. hfaria

      Olá. Teste no Shell ou no console SQL a consulta que termina em erro.

Deixe uma resposta