From aaf3c566efdd8a8e3e9c3b7cb37945491e70ac7c Mon Sep 17 00:00:00 2001 From: Dave Lane Date: Thu, 13 Feb 2020 15:44:12 +1300 Subject: [PATCH] initial commit of working script --- .gitignore | 1 + sqlite_backup | 246 ++++++++++++++++++++++++++++++++++++++ sqlite_backup-cron | 22 ++++ sqlite_backup.conf-sample | 18 +++ 4 files changed, 287 insertions(+) create mode 100644 .gitignore create mode 100755 sqlite_backup create mode 100644 sqlite_backup-cron create mode 100644 sqlite_backup.conf-sample diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fee9217 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.conf diff --git a/sqlite_backup b/sqlite_backup new file mode 100755 index 0000000..f0ca27f --- /dev/null +++ b/sqlite_backup @@ -0,0 +1,246 @@ +#!/bin/bash +# +# This script dumps an SQLite3 db stored on the filesystem +# using the selected command and pipes the results into an +# appropriately named/dated file... +# +# It also manages rolling out older backups to avoid filling +# your storage... +# +# Default retention +BU_TO_KEEP_HOURLY=24 +BU_TO_KEEP_DAILY=7 +BU_TO_KEEP_WEEKLY=4 +BU_TO_KEEP_MONTHLY=12 +BU_TO_KEEP_YEARLY=7 +# +BU_FROOT=default +BU_FROOT_HOURLY=hourly +BU_FROOT_DAILY=daily +BU_FROOT_WEEKLY=weekly +BU_FROOT_MONTHLY=monthly +BU_FROOT_YEARLY=yearly +# +# this can be overridden at invocation +BU_CONF=sqlite_backup.conf +# # output for debugging... +VERBOSE=1 +# +# the DB file to backup - specified in the conf +#DBDIR=/home/data/safe.lane.net.nz/data +#DBFILE=${DBDIR}/db.sqlite3 +#BUDIR=/home/data/safe.lane.net.nz/backups +# +# Stuff that should be universal for this install... +# where we can find this app... +MAIN_DIR=/home/dave/sqlite_backup +# determine today's date +DATE=`date '+%Y-%m-%d-%a'` +# determine today's date +TIME=`date '+%H-%M-%S'` +# temporary holding point for email +TMP_EMAIL=/tmp/tmp_sqlite_dbbackup_email.$DATE_$TIME +# log file +LOG=/var/log/sqlite_dbbackup.log +# +# Commands +# gzip command +GZIP=`which gzip` +# grep command +GREP=`which grep` +# email program +MAIL=`which mail` +# database dump utility +SQLITE=`which sqlite3` +# +# pattern for "ls" command to build list of +# pruneable backup files... +# -1t = 1 column, ordered by time of last mod +PRUNEABLES_CMD="ls -1t" +# function to direct a message... +message() { + # + # a timestamp for logging purposes + TIMESTAMP=`date '+%Y-%m-%d %H:%M.%S'` + echo "$0: $TIMESTAMP $@" >> $LOG + if test -f $TMP_EMAIL ; then + echo "$0: $TIMESTAMP $@" >> $TMP_EMAIL + fi + verbose "$TIMESTAMP $@" +} +# create the temporary email file +create_tmp_email() { + touch $TMP_EMAIL + if test -f $TMP_EMAIL ; then + message "created temporary email $TMP_EMAIL" + else + message "failed to create temporary email $TMP_EMAIL" + fi +} +# send the contents of the temporary file to the +# designated report recipient +send_email_report() { + if test -f $TMP_EMAIL ; then + message "sending email report to $EMAIL" + $MAIL -s "$EMAIL_SUBJ ($1)" $EMAIL < $TMP_EMAIL + rm $TMP_EMAIL + if test -f $TMP_EMAIL ; then + message "failed to remove temporary email $TMP_EMAIL" + else + message "successfully removed temporary email $TMP_EMAIL" + fi + message "email report successfully sent" + fi +} +# insert a blank line into the log and on the console +insert_blank() { + echo "" >> $LOG + verbose "" +} +# function to direct a message... +verbose() { + if test $VERBOSE = 1 ; then + echo "$@" + fi +} +# +# delete old backups +delete_old() { + # + verbose "deleting old files based on $1" + # pattern to search for to build the list... + PATTERN="$BU_DIR/$1-*.*" + # build the list, with the suffix... + PRUNEABLES=`$PRUNEABLES_CMD $PATTERN` + if test "$?" -eq "0" ; then + message "pruning older files based on $PATTERN" + BU_TO_KEEP=$2 + message "keeping last $BU_TO_KEEP backups" + # + # set counter + NUM=0 + # go through the list of files and remove those we don't want + for PRUNEABLE in $PRUNEABLES + do + NUM=$(($NUM + 1)) + if test $NUM -gt $BU_TO_KEEP ; then + message "deleting $PRUNEABLE" + rm $PRUNEABLE 2>&1 > /dev/null + else + message "keeping $PRUNEABLE" + fi + done + else + message "No files with $PATTERN to delete" + fi +} +# +# +do_backup() { + FILE=$1 + VER=`$SQLITE --version` + verbose "SQLite3 version $VER - echoing to backup: $FILE" + echo "--" > $FILE + echo "-- SQLite Version: $VER" >> $FILE + echo "-- Backup created by $0" >> $FILE + echo "--" >> $FILE + echo "" >> $FILE + CMD="$SQLITE $DB_DIR/$DB_FILE .dump" + verbose "doing database dump: $CMD" + $CMD >> $FILE +} +# +TASK= +# +# cycle through the command line options +while test $# -ne 0 ; do + case $1 in + --config|-c) + shift # shift from the flag to the value + verbose "setting configuration directory to $1" + BU_CONF=$1 + ;; + --hourly|-h) + verbose "running hourly backup" + TASK=HOURLY + ;; + --daily|-d) + verbose "running daily backup" + TASK=DAILY + ;; + --weekly|-w) + verbose "running weekly backup" + TASK=WEEKLY + ;; + --monthly|-m) + verbose "running monthly backup" + TASK=MONTHLY + ;; + --yearly|-y) + verbose "running yearly backup" + TASK=YEARLY + ;; + esac + shift +done +# +# we must have *some* task specified +if [[ $TASK == '' ]] ; then + message "No TASK specified! Pick --hourly, --daily, --weekly, --monthly, --yearly..." + exit 1 +fi +# +# +# create the blank email report +if ! [[ $TASK == 'HOURLY' ]] ; then + create_tmp_email +fi +# +if test -f $MAIN_DIR/$BU_CONF ; then + verbose "Reading default in $MAIN_DIR/$BU_CONF" + source $MAIN_DIR/$BU_CONF +else + message "ERROR: Couldn't find or read $MAIN_DIR/$BU_CONF" + exit 1 +fi +# +# run through the various tasks +verbose "using configuration file $BU_CONF" +# go to the Docker Compose directory where we need to be to run the +# docker-compose commands +verbose "going to $DC_DIR" +OLD_DIR=`pwd` +cd $DC_DIR +# +# a timestamp for logging purposes +STAMP=`date '+%Y-%m-%d_%H-%M-%S'` +# +# generate the filename +INC="BU_FROOT_$TASK" +FILEPART=$BU_FROOT-${!INC} +FILENAME=$FILEPART-$STAMP.sql +FILEPATH=$BU_DIR/$FILENAME +# +# delete stale backups +TO_KEEP="BU_TO_KEEP_$TASK" +delete_old $FILEPART ${!TO_KEEP} +# +message "backing up all the databases into $FILEPATH" +# dump the data into the file +# +do_backup $FILEPATH +# +message "completed backup" +# compress the backup +message "compressing $FILEPATH" +$GZIP $FILEPATH +# return to where you started from... +cd $OLD_DIR +# +# sent resulting email report +# +if ! [[ $TASK == 'HOURLY' ]] ; then + send_email_report $TASK +fi +exit 0 + diff --git a/sqlite_backup-cron b/sqlite_backup-cron new file mode 100644 index 0000000..67a80e8 --- /dev/null +++ b/sqlite_backup-cron @@ -0,0 +1,22 @@ +SHELL=/bin/sh +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +USER=root +DIR=/home/dave/sqlite_backups +SCRIPT=dbbackup +# +# run system backups +# +# hourly - at 5 minutes past mon-sat +05 * * * * $USER $DIR/$SCRIPT --hourly +# +# daily - at 7:30 pm, mon-sat +30 19 * * * $USER $DIR/$SCRIPT --daily +# +# weekly - at 7:30 pm, sun +30 19 * * sun $USER $DIR/$SCRIPT --weekly +# +# monthly - at 8:30 pm, on the first of the last of the month +30 20 1 * * $USER $DIR/$SCRIPT --monthly +# +# yearly - at 8:30 pm, on the first of January. +30 20 1 1 * $USER $DIR/$SCRIPT --yearly diff --git a/sqlite_backup.conf-sample b/sqlite_backup.conf-sample new file mode 100644 index 0000000..3cf7788 --- /dev/null +++ b/sqlite_backup.conf-sample @@ -0,0 +1,18 @@ +# +# SQL dump backup directory +# +# backup file details +BU_DIR=/path/to/directory/for/backups +# each backup will start with this basename +BU_FROOT=preferred-basename +# +# location of sqlite database +DB_DIR=/path/to/database/directory +DB_FILE=your-db.sqlite3 +# +# Reporting +# +# email address to send reports to, and subject +EMAIL=your@email.address +EMAIL_SUBJ="A suitably descriptive email subject" +