Zabbix Bacula Jobs and Processes Monitoring

This is a fork of a GIT project with some corrections. Check for possible updates: https://github.com/germanodlf/bacula-zabbix

This project consists of a shell script that collects information from the Bacula server, sends it to the Zabbix server through its client (Zabbix sender), and a template to be installed on the monitoring server.

Features

  • Individual monitoring for each Backup Job
  • Different levels of Job have different severities
  • Monitoring Bacula’s Director, Storage and Customer processes
  • Graphics and dashboards
  • Works with Bacula Catalogs in PostgreSQL and MySQL

Data Collected by Script

  • Job Termination Status (OK item)
  • Number of bytes transferred (Bytes item)
  • Number of files transferred (Files item)
  • Duration (Time item)
  • Transfer rate (Speed item)
  • Compression ratio (Compression item)

Bacula Process Data

  • Bacula Director process status. The process name is defined by the variable {$BACULA.DIR} and has its default value as ‘bacula-dir’. This item needs to be disabled on hosts that are only Bacula customers.
  • Storage Daemon status. The process name is defined by the variable {$BACULA.SD} and has its default value as ‘bacula-sd’. This item needs to be disabled on hosts that are only Bacula customers.
  • File Daemon status. The process name is defined by the variable {$BACULA.FD} and has its default value as ‘bacula-fd’.

Triggers

  • The Bacula daemon is DOWN on {HOST.NAME}: Starts a disaster severity alert when the Bacula process is stopped
  • Full FAIL Backup at {HOST.NAME}: Starts a high severity alert when a full backup Job fails
  • Backup Differential FAIL on {HOST.NAME}: Starts an average gravity alert when a differential backup Job fails
  • Incremental FAIL Backup in {HOST.NAME}: Starts a warning severity alert when an incremental backup Job fails

Configuration

Zabbix Template

Download the xml (zip) template and import it to your Zabbix server.

Proceed with the installation of the script on the machines with Bacula to follow. Subsequently, the Zabbix model should be provided to each of these hosts. Each host configured in Zabbix with this linked model must have its name equal to the name configured in the Bacula Client resource. Otherwise, the data collected by the bash script will not be received by the Zabbix server.

Bacula Server Zabbix Script

Install the Zabbix Sender and the Agent. CentOS 7 example:

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

Modify the Zabbix Agent settings required as Server, Port, and Hostname of the agent machine, if necessary. Restart the service to apply the changes:

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

service zabbix-agent restart

Create the /opt/bacula/etc/bacula-zabbix.conf configuration file with the following content. Modify with your environment information:

### 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'

Provide permissions to the Bacula user to the created .conf file.

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

Create the bash /opt/bacula/scripts/bacula-zabbix.bash script file, with the following content. For PostgreSQL Catalog:

#!/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

For MySQL Catalog:

#!/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

Restart the Director service.

service bacula-dir restart

Bacula Client Monitoring

Edit your backed up hosts to use the Zabbix template. Do not forget to disable in the hosts that are only Bacula clients the items that check Bacula Director and Storage processes, and to use the Host name in the Zabbix console equal to the name of the Bacula configured clients, as in the example (Client Name BKP01-fd):

Zabbix Bacula Jobs and Processes Monitoring 1

You can run the script manually by entering a JobId to pass the information (eg 99) to test the scripts.

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

You can run the script manually by entering a JobId to pass the information (eg 99) to test the scripts.

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

Add in Bacula’s JobDefs a configuration to always run the clients after every finished Backup Job, passing the job’s JobId:

ClientRunAfterJob=/opt/bacula/scripts/bacula-zabbix.bash %i

Screenshots

Zabbix Bacula Jobs and Processes Monitoring 2 Zabbix Bacula Jobs and Processes Monitoring 3 Zabbix Bacula Jobs and Processes Monitoring 4

 

Disponível em: pt-brPortuguês (Portuguese (Brazil))enEnglishesEspañol (Spanish)

Leave a Reply