Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,41 @@ Just dive in and copy the files out of the snapshot:
cd /backup/hosts/example.com/.zfs/snapshot/ && \
rsync -aH --numeric-ids 2012-11-04-15:40:49-1352004049/d/ example.com:/restore-point/


## Retention Policies

Each backup has a TTL defined, after which the prune script will delete the
backup's snapshot. You can configure the retention/expiry of backups through
various configuration properties. Each of them defines the TTL by means of "fully days after
backup creation". A value of 0 defines "keep forever".

Once a backup is created you can't change the TTL anymore, as it is stored
within the read-only snapshot.

A specific expiry TTL given as last parameter to the backup script
overrules any of the other TTL configuration.

The default TTL configuration is set in the required property ``EXPIRY``. It gets
applied when none of the other option matches.

All other options apply until to the first complete/successful backup at a given day:

* ``EXPIRY_DAY``: TTL for daily backups
* ``EXPIRY_WEEK``: TTL for the backup on a Monday
* ``EXPIRY_MONTH``: TTL for backup on the first day of a month
* ``EXPIRY_QUARTER``: TTL for backup on the first day of a quarter
* ``EXPIRY_YEAR``: TTL: for backup on the first day of a year

If a given day matches multiple conditions, the expiry configuration for the longest
period that has a non-empty value gets selected. E.g when on January 1st ``EXPIRY_YEAR``
is not set, but ``EXPIRY_QUARTER`` and ``EXPIRY_DAY`` are, then
EXPRIY_QUARTER gets selected.

When a backup doesn't succeed completely (partial backups), then the configured TTL
gets also applied to the next attempt to do a backup at the same day. If all backups
at a given day (partially) fail, then you won't get a backup with the special TTL.
You then would have to trigger a manual backup with a TTL set explicitly.

## Status

This has been in production use for many years now and is stable.
Expand Down
23 changes: 21 additions & 2 deletions bin/backup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,23 @@ fi
sourceHostConfig $HOSTS_DIR $HOST

# Options Overridable by backup.conf (or command line)
EXPIRY=$(expr ${3-$EXPIRY} \* 24 \* 60 \* 60 + `date +%s`) # Convert expiry to unix epoc

if [ -z "${3}" ]; then
NUM_BACKUPS_TODAY=$(find ${HOSTS_DIR}${HOST}/.${POOL_TYPE}/snapshot -maxdepth 1 -mindepth 1 -name "@$(date +%F)*" | grep -v -e "-partial$" | wc -l)
if [ "${NUM_BACKUPS_TODAY}" -eq "0" ]; then
if [ -n "${EXPIRY_DAY}" ]; then EXPIRY=${EXPIRY_DAY}; fi
if [ -n "${EXPIRY_WEEK}" -a "$(date +%u)" == "1" ]; then EXPIRY=${EXPIRY_WEEK}; fi
if [ -n "${EXPIRY_MONTH}" -a "$(date +%-d)" == "1" ]; then EXPIRY=${EXPIRY_MONTH}; fi
if [ -n "${EXPIRY_QUARTER}" -a "$(date +%-d)" == "1" -a "$(expr $(date '+%-m') % 3)" == "1" ]; then EXPIRY=${EXPIRY_QUARTER}; fi
if [ -n "${EXPIRY_YEAR}" -a "$(date +%-j)" == "1" ]; then EXPIRY=${EXPIRY_YEAR}; fi
fi
else
EXPIRY=${3}
fi

if [ "${EXPIRY}" -gt "0" ]; then
EXPIRY=$(expr ${EXPIRY} \* 24 \* 60 \* 60 + `date +%s`) # Convert expiry to unix epoc
fi

# Check to see if the host backup is disabled.
if [ "${DISABLED}" == "true" ] && [ -z "$FORCE" ]; then
Expand Down Expand Up @@ -99,7 +115,10 @@ fi
(
rm -f ${LOGFILE} # delete logfile from host dir before we begin.
echo "inprogress" > $STATUSFILE
echo $EXPIRY > ${HOSTS_DIR}${HOST}/c/EXPIRY
rm -f ${HOSTS_DIR}${HOST}/c/EXPIRY
if [ "${EXPIRY}" -gt "0" ]; then
echo $EXPIRY > ${HOSTS_DIR}${HOST}/c/EXPIRY
fi
echo $ANNOTATION > ${HOSTS_DIR}${HOST}/c/ANNOTATION

STARTTIME=$(date +%s)
Expand Down
4 changes: 2 additions & 2 deletions bin/list-backups.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
CWD="$(dirname $0)/"

# Source Config
. ${CWD}../etc/backup.conf
. ${CWD}../etc/backup.conf

# Source Functions
. ${CWD}functions.sh;
Expand Down Expand Up @@ -35,7 +35,7 @@ for host in $HOSTS; do
EXPIRY=$(cat $snapshot/c/EXPIRY 2> /dev/null)
ANNOTATION=$(cat $snapshot/c/ANNOTATION 2> /dev/null)
STATUS=$(cat $snapshot/l/STATUS 2> /dev/null)
echo "$host $SNAPSHOT $EXPIRY $STATUS \"$ANNOTATION\""
echo "$host $SNAPSHOT ${EXPIRY:-0} $STATUS \"$ANNOTATION\""
done
fi
done
Expand Down
7 changes: 6 additions & 1 deletion etc/backup.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ RSYNC_ARGS='-a --numeric-ids --hard-links --compress --delete-after --delete-exc
SSH_USER='root'
EXCLUDE='/dev /proc /sys /tmp /var/tmp /var/run /selinux /cgroups lost+found'
BACKUP_PATHS='/'
EXPIRY='28' # Default backup expiry (in days)
EXPIRY=7 # Default backup expiry (in days)
EXPIRY_DAY=$(expr 7 \* 8) # 8 weeks (~2 month)
EXPIRY_WEEK=$(expr 7 \* 25) # twenty-five weeks (~6 month)
EXPIRY_MONTH=$(expr 2 \* 365) # two years
EXPIRY_QUARTER=$(expr 5 \* 365) # five years
EXPIRY_YEAR=0 # unlimited
SSH_KEY=~root/.ssh/id_rsa.pub
SNAPSHOT_ON_ERROR=false # Snapshot after rsync errors
PRUNE=true # Prune old expired backup snapshots
Expand Down