Simple Automated OffLine Backup Script


Recommended Posts

I have stitched together this script because I could not find any solution for my usecase.

Thx to @mgutt and his backup script I took some parts from

 

Goal:

  1. Connect hot-swap-able disk to unraid
  2. automatically mount the disk (can be disabled)
  3. automatically perform (multiple) mirror backup jobs which simply copy all changes from the SourceDir to the DestinationDir (including deletions)
  4. automatically unmount the disk once the backup(s) are done (can be disabled)
  5. safely remove the disk once everything is done thx to notifications that are sent for each step of the process

 

Required:

  1. some kind of hot-swap-able storage media
  2. Unassigned Devices Plugin

 

Setup:

  1. connect your backup storage media
  2. make sure it has a mount point
  3. click on the little "gear" icon
  4. paste the script below into the script window
  5. adjust the Backup Jobs configuration section
  6. save
  7. done
  8. click on mount to test if the script is working correctly
  9. if everything is working click on unmount

if you want to automate the entire process:

  1. click on the little "gear" icon again
  2. enable "automount"
  3. and set "unmount_after_backup to 1

 

Hope someone finds this helpful! :)

 

#!/bin/bash
PATH=/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin

########
# SIMPLE MIRROR BACKUP / V01 -  2022-07-14 / by cholzer 
# This script is meant to be used in the script area of a disk inside the Unassigned Devices plugin
########
# I stitched together this backup script as I could not find a solution for my Offline Backups which are done onto hot-swapable disks.
# With this script you can define multiple backup jobs - you get a notification for each important action.
#
# The whole backup process gets super easy if you choose to enable "automount" for the disk in Unassigned Devices and enable "unmount" in the config section below then .
# Just plug in the disk and the script starts the backup and unmounts the disk once it is done so that you can safely unplug the disk.
# 
########
# Do your modifications below
########

# Here you can setup all your backup jobs.
# The mountpoint of the disk you add this script to inside Unassigned Devices is automatically used as destination target. 
# You can set a subfolder per backup if you'd like to use one.
# Use Unraids new file manager to find the exact source path (available in Unraid 6.10 and later)
backup_jobs=(
# sourcePath                     # destinationPath-Subfolder (/ for none)               #jobName
"/mnt/user/documents"            "/Backup"                                              "Documents"
"/mnt/user/photos"               "/Backup"                                              "Photos"
)

# Unmount the backup disk - (Will only be done if the backup was successful)
unmount_after_backup=0

# Notifications:
# You can disable notifications if you really want to.
notifications=1

# rsync options which are used while creating the full and incremental backup
rsync_options=(
  --human-readable # output numbers in a human-readable format
  --delete # when a file was deleted in source directory it will be delete in the destination directory too
  --exclude="[Tt][Ee][Mm][Pp]/" # exclude dirs with the name "temp" or "Temp" or "TEMP"
  --exclude="[Tt][Mm][Pp]/" # exclude dirs with the name "tmp" or "Tmp" or "TMP"
  --exclude="Cache/" # exclude dirs with the name "Cache"
  --exclude=".Recycle.Bin/" # exclude dirs with the name ".Recycle.Bin"
)

####
# WARNING! DRAGONS BELOW! Do not change anything that comes next unless you know what you are doing!
####

## Available variables:
# ACTION     : if mounting, ADD; if unmounting, UNMOUNT; if unmounted, REMOVE; if error, ERROR_MOUNT, ERROR_UNMOUNT
# DEVICE     : partition device, e.g. /dev/sda1
# SERIAL     : disk serial number
# LABEL      : partition label
# LUKS       : if the device is encrypted, this is the partition device, e.g. /dev/sda1
# FSTYPE     : partition filesystem
# MOUNTPOINT : where the partition is mounted
# OWNER      : "udev" if executed by UDEV, otherwise "user"
# PROG_NAME  : program name of this script
# LOGFILE    : log file for this script

case $ACTION in
  'ADD' )
    if [ "$OWNER" = "udev" ]; then
        # do your hotplug stuff here
		sleep 1
    else
        # do your user initiated stuff here
		
    # sync the file system to commit all writes to disk
    sync -f "$MOUNTPOINT"
	# notification
	if [ "$notifications" == 1 ]; then
    /usr/local/emhttp/webGui/scripts/notify -e "Unraid Server Notice" -s "Unassigned Devices" -d "Device mounted" -i "normal"
	fi
	
	######## Lets run the Backup Job(s)
	# remove the trailing slash from the source and destination path should there be one
	remove_trailing_slash() { [[ "${1%?}" ]] && [[ "${1: -1}" == "/" ]] && echo "${1%?}" || echo "$1"; }
	# now lets loop through each individual backup job
	for i in "${!backup_jobs[@]}"; do
    case $(($i % 3)) in
        0) src_path="${backup_jobs[i]}"; continue ;;
        1) dst_path="$MOUNTPOINT${backup_jobs[i]}"; continue ;;
        2) job_name="${backup_jobs[i]}" ;;
    esac
				
		# check user settings
		src_path=$(remove_trailing_slash "$src_path")
		dst_path=$(remove_trailing_slash "$dst_path")
                echo "Source Path is $src_path" "Destination Path is $dst_path"
		
		# Notification Backup Started
		if [ "$notifications" == 1 ]; then
		/usr/local/emhttp/webGui/scripts/notify -s "`hostname` Backup Job: "$job_name" started" -d "Sync started. `date`"
	    fi

		# first we need to make sure that the log directory does exists, if it doesn't, create it
		if [ ! -d "$MOUNTPOINT"/rsync-logs/"$job_name"/ ]; then
		mkdir -p "$MOUNTPOINT"/rsync-logs/"$job_name"/;
		fi
	
		# Now lets run the actual backup job. 
		# It does a mirror, which means that all changes including deletions are pushed from the source directory to the destination directory.
		# Folders named '.Recycle.Bin' are excluded
		rsync -av --log-file="$MOUNTPOINT"/rsync-logs/"$job_name"/log.`date '+%Y_%m_%d__%H_%M_%S'`.log --progress "${rsync_options[@]}" "$src_path" "$dst_path"

		# Notifications sync complete or error
		if [ "$notifications" == 1 ]; then
			latestRsyncLog=$(ls -tr "$MOUNTPOINT"/rsync-logs/"$job_name"/ |tail -1)
			if [ $? -eq 0 ]
			then
			/usr/local/emhttp/webGui/scripts/notify -s "`hostname` Backup Job: "$job_name" completed" -d "Sync okay! `date`"
			else
			/usr/local/emhttp/webGui/scripts/notify -s "`hostname` Backup Job: "$job_name"  FAILED" -i "alert" -d "Sync ERROR! `date`" -m "`tail -5 "$MOUNTPOINT"/rsync-logs/"$job_name"/"$latestRsyncLog"`"
			fi
		fi
	done
    sleep 1
		
    fi
	
	# unmount the backup disk once the rsync backup finished
	if [ "$unmount_after_backup" == 1 ]; then
	/usr/local/sbin/rc.unassigned umount $DEVICE
    fi
  ;;

  'UNMOUNT' )
    # do your stuff here
	# since we also get notified once the disk was unmounted, I commented this notification out
    # /usr/local/emhttp/webGui/scripts/notify -e "Unraid Server Notice" -s "Unassigned Devices" -d "Device unmounting" -i "normal"
  ;;

  'REMOVE' )
    # do your stuff here
	# notification
	if [ "$notifications" == 1 ]; then
    /usr/local/emhttp/webGui/scripts/notify -e "Unraid Server Notice" -s "Unassigned Devices" -d "Device unmounted" -i "normal"
	fi
  ;;

  'ERROR_MOUNT' )
    # do your stuff here
	# notification
	if [ "$notifications" == 1 ]; then
    /usr/local/emhttp/webGui/scripts/notify -e "Unraid Server Notice" -s "Unassigned Devices" -d "Error mounting device" -i "alert"
	fi
  ;;

  'ERROR_UNMOUNT' )
    # do your stuff here
	# notification
	if [ "$notifications" == 1 ]; then
    /usr/local/emhttp/webGui/scripts/notify -e "Unraid Server Notice" -s "Unassigned Devices" -d "Error unmounting device" -i "alert"
	fi
  ;;
esac

 

 

Edited by cholzer
  • Thanks 1
Link to comment
  • 2 months later...
On 7/14/2022 at 8:58 PM, cholzer said:

it's a nice starting point but lacks much of what I wanted (compare the scripts).  😉

Mate! I just wanted to say THANKYOU SO SO MUCH for this script!!!

 

I'm a noob at scripts/unraid and I've been pulling my hair out all day trying to get other scripts to fit my use case, which is exactly like yours. 

 

Thanks once again

Edited by wacko37
  • Thanks 1
Link to comment

Hi cholzer, as mentioned above your script is fulfilling my requirements, thank you,.

 

I am however having a problem with how the script is executed. The problem arises when not utilizing the auto features of the script, and when trying to mount & view the contents of the device without triggering the script, as when the mount button is pressed it forces the script to run.

 

After posting on the main UD to help resole the issue (see link below) it would seem the script is incorrect on how the manual trigger should be implemented, as one should be able to mount the device without trigger the script and then later manually trigger the script via the "lightning icon"

 

Now I know you wrote the script to be automated and your use case was never built around the manually trigger, but you have mentioned in your description that all auto features can be disabled if required, which they can, but are resulting in a negative way. 

 

Sadly this is way above my skill set and understanding of scripting (which is copy & paste...lol) I hope maybe you can shed some light/expertise on how to best to rectify this, thanks

 

Also help has been offered by @dlandon to help with any questions you may have   (see in forum below)

 

 

 

 

Edited by wacko37
trying to work out how to do @username....lol I got it
Link to comment

There are two lines in the script that can be removed.

  • The PATH= is not needed.  Unraid handles passing in the proper $PATH to the script.
  • The sync command is not needed as it does nothing where it is.  UD handles device sync when it is unmounted.  You got old code from UD that has been changed.

The issue is this section of code:

  'ADD' )
    if [ "$OWNER" = "udev" ]; then
        # do your hotplug stuff here
        sleep 1
    else
        # do your user initiated stuff here
        sleep 1
    fi

If $OWNER = "udev", the script is initiated by a hotplug event or the lightning icon is clicked to start the script when the device is mounted.

 

If $OWNER = "user", the "Mount" button has been clicked to mount the device.  If the user doesn't want to execute the script when the device is manually mounted, just exit the script.

 

If the script is exited when the "Mount" button is pressed, the operation would then be:

  • Hotplug the device - the device mounts if auto mount is set and the script executes.
  • If the disk is unmounted, clicking the "Mount" button will mount the device and not execute the script.
  • If the disk is mounted, clicking the lightning icon will execute the script.

This is what @wacko37 is looking for.

  • Like 1
  • Thanks 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.