Easy Backups for Concerto Digital Signage

If you have read any of my earlier posts you know that I am running the pre built VM of Concerto.  You should still backup your instance, otherwise, you may find yourself having to rebuild the whole setup, including all your screens and content, should something go horribly wrong.  I decided I would back up the Concerto VM twice a month at 6:00 AM, once on the first of the month and once on the fifteenth of the month.

Luckily, Virtualbox has a handy export tool that makes it super simple to take a snapshot of your VM that can easily be imported back into Virtualbox if the need arose.  I have a script that I wrote that is probably a little over kill (that’s how I roll, LOL) but it gracefully stops the VM and creates a backup snapshot of the VM in a date stamped directory, it logs everything and send the log file to me after it verifies that the Concerto VM is back up and running.  I would definitely recommend implementing the systemd service for Concerto which I covered here, otherwise this script won’t work for you.  You just need to change the global variables in the script to fit your installation.

I have the script run via a cron job in my crontab.  I also have a script that runs after this backup script to delete the oldest backup I have (I keep 3) in order to save hard drive space.  I will cover that script in another post. You will need the ssmtp package in order to send an email and you will need to setup the “systemctl” command to run with no password for sudoers (post coming on that but you can easily google that for now).

Here is the script to backup Concerto, modify it to suit your needs, and don’t forget to enter your email address where needed (you could use this script to backup ANY VM, not just Concerto –I use it for several installations that I run via Virtualbox):

#!/bin/bash
# EXPORT .OVA OF VIRTUALBOX VIRTUAL MACHINE v5
# Author: Rob Flemen    Email: 
# REQUIRES: ssmtp package. Need systemctl and ssmtp set for sudoers with no password.

# Global variables
service_name="mdss-vm.service"
vm_name="mdss"
time_stamp=$(date +%m-%d-%Y-%H-%M-%S)
backup_path="/home/pi/Backups/mdss"
log_file_name="/home/pi/Backups/logs/concerto_backup.log"
email_recipient="address@example.com"

# Function to send email. Args: (1)log file name, (2)email address
function email_log () {
        cat $1 | sudo ssmtp $2
}

# Check if a command executed. Args: (1)result code, (2)log file name, (3)email address
function check_for_success () {
        if [ $1 == 0 ]; then
                echo "SUCCESS! Command successfully executed!" >> $2
        else
                echo "Something went wrong!" >> $2
                email_log $2 $3
                exit 1
        fi
}

# Verify service state. Args: (1)service, (2)log file, (3)email address, (4) process ID
function verify_service_state () {
        current_status=$(systemctl status $1 | grep -oe running -oe failed -oe dead)
        if [[ "$current_status" == "running" ]]; then
                echo "${service_name} process ID: ${4} is ACTIVE." >> $2
        elif  [[ "$current_status" == "failed" || "$current_status" == "dead" ]]; then
                echo "${service_name} process ID: ${4} is DEAD" >> $2
        else
                echo "Well shoot, something went HORRIBLY wrong!!!" >> $2
                email_log $2 $3
                exit 1
        fi
}

# Header for the logfile
echo >> "${log_file_name}"
date >> "${log_file_name}"
echo >> "${log_file_name}"
echo "PROD ${vm_name} VM Backup Script" >> "${log_file_name}"
echo "************************************" >> "${log_file_name}"

# Create a folder with a date/time stamp for a name
echo >> "${log_file_name}"
echo "...creating date stamped directory..." >> "${log_file_name}"
mkdir -p "${backup_path}/${time_stamp}"
check_for_success $? "${log_file_name}" "${email_recipient}"

# Stop the service & verify state
echo >> "${log_file_name}"
process_id=$(ps -ef | grep "[V]BoxHeadless -s ${vm_name}" | tr -s ' ' | cut -d ' ' -f2)
echo "...stopping process ID: ${process_id} - ${service_name}..." >> "${log_file_name}"
sudo systemctl stop "${service_name}" >> "${log_file_name}" 2>&1
check_for_success $? "${log_file_name}" "${email_recipient}"
sleep 5
verify_service_state "${service_name}" "${log_file_name}" "${email_recipient}" "${process_id}"

#Export a copy of the vm to a .ova file
echo >> "${log_file_name}"
echo "...exporting vm to an .ova file..." >> "${log_file_name}"
VBoxManage export "${vm_name}" -o "${backup_path}/${time_stamp}/${vm_name}.ova" >> "${log_file_name}" 2>&1

# Start the service & verify state
echo >> "${log_file_name}"
echo "...starting ${service_name}..." >> "${log_file_name}"
sudo systemctl start "${service_name}" >> "${log_file_name}" 2>&1
check_for_success $? "${log_file_name}" "${email_recipient}"
sleep 40
process_id=$(ps -ef | grep "[V]BoxHeadless -s ${vm_name}" | tr -s ' ' | cut -d ' ' -f2)
verify_service_state "${service_name}" "${log_file_name}" "${email_recipient}" "${process_id}"

# Send a copy of the logfile to interested parties
email_log "${log_file_name}" "${email_recipient}"

As I mentioned, I run this via cron job and my crontab looks like this (I have a second job there as well but pay attention to first entry – “mdss-backup.sh”):

# Edit this file to introduce tasks to be run by cron.
# 
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# 
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# 
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# 
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# 
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# 
# For more information see the manual pages of crontab(5) and cron(8)
# 
# m h  dom mon dow   command
0 6 1,15 * * /home/pi/mdss_backup.sh
0 7 1,15 * * /home/pi/rm_oldest_dir.sh

This setup has worked extremely well for me, when the Concerto production log filled up the hard drive and caused the application to crash, I was able to restore the VM from the most recent backup and implement the log maintenance needed to prevent that from happening again.  I was only down for maybe 15 minutes once I started working on it.  This also makes it trivial to move the VM to new hardware if needed.  I highly recommend running Concerto in this setup if you are going to run it.  Thanks and stay tuned for more content!

Thanks,
Rob

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *