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):
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
Disponível em: Português (Portuguese (Brazil))EnglishEspañol (Spanish)