#!/bin/bash show_help() { cat << end_of_help USAGE: $(basename $0) [-h | --help] <[--force] domain1 domain2...> $(basename $0) -- Applies Backup Rotation and Retention Policy. - Checks backups lifecyle based on MAX_BACKUPS_PER_CHAIN, triggering its archiving when reaches that number of checkpoints - Applies retention policy, based on LOCAL|RSYNC_BACKUP_CHAINS_TO_KEEP, keeping as many (and most recent) backup chains on each endpoint, deleting the older ones. - When '--force'is passed as the first argument, overrides MAX_BACKUPS_PER_CHAIN and triggers its immediate archiving. end_of_help } if [[ $1 == "-h" || $1 == "--help" ]]; then # Show help and exit: show_help exit elif [[ $1 == "--force" ]]; then # Force the end of lifecycle: retention_mode="Forced" shift elif [[ -n $MAX_BACKUPS_PER_CHAIN && $MAX_BACKUPS_PER_CHAIN -gt 0 ]]; then # Run normal checks and apply retention policy: retention_mode="Normal" fi # Load common functions: source /usr/local/bin/vm-functions # Processes initial backups list from VMs (passed as arguments): retention_list=($@) if [[ -n ${retention_list[@]} ]]; then for domain in ${retention_list[@]}; do # (Re)Initialize boolean variables: local_backup_not_found="" end_of_lifecycle="" # Display screen divider when processing several backup chains: [[ ${#retention_list[@]} -gt 1 ]] \ && screen_header "-" if [[ -d $LOCAL_BACKUP_PATH/$domain \ && -n $(ls -A $LOCAL_BACKUP_PATH/$domain) \ && -n $(list_extensions $LOCAL_BACKUP_PATH/$domain | grep -iv log) ]]; then echo "$domain: Checking backup chain lifecycle..." # Backup path exists, is not empty and has something aside logs. Proceed with check: # Retention policy is set (at least, partially) by the user. Retrieve the number of existing checkpoints in the backup chain: num_of_backup_checkpoints=$(backup_checkpoints_num $LOCAL_BACKUP_PATH/$domain) case $retention_mode in Normal) # Will check how many checkpoints will have, marking the end of its lifecycle if cannot be used if [[ $num_of_backup_checkpoints -eq 0 ]]; then # '0' checkpoints means it's a 'copy' backup: end_of_lifecycle=true echo "$domain: Chainless backup made using 'copy' mode. It cannot be used to store incremental backups" elif [[ $num_of_backup_checkpoints -ge $MAX_BACKUPS_PER_CHAIN ]]; then end_of_lifecycle=true echo "$domain: Backup chain has reached the end of its lifecycle and must be rotated ($num_of_backup_checkpoints of $MAX_BACKUPS_PER_CHAIN allowed checkpoints)" else end_of_lifecycle=false echo "$domain: Backup chain currently contains $num_of_backup_checkpoints of $MAX_BACKUPS_PER_CHAIN allowed checkpoints" fi ;; Forced) # No checks will be performed. Directly end its lifecycle echo "$domain: Backup chain has been forcibly set to end its lifecycle and must be rotated ($num_of_backup_checkpoints of $MAX_BACKUPS_PER_CHAIN allowed checkpoints)" end_of_lifecycle=true ;; *) # MAX_BACKUPS_PER_CHAIN is not set, or value is 0: echo "WARNING: $domain: Data retention policy is disabled ($num_of_backup_checkpoints) checkpoints so far)" ;; esac if [[ $end_of_lifecycle == true ]]; then # Process local backup chain if it has reached its lifecycle (for whatever reason): archive_backup $LOCAL_BACKUP_PATH/$domain $LOCAL_BACKUP_CHAINS_TO_KEEP fi else echo "$domain: No backup found at $LOCAL_BACKUP_PATH" # Mark local backup as 'not found' (to perform tasks below): local_backup_not_found=true fi if [[ -n $RSYNC_BACKUP_PATH ]] && [[ $end_of_lifecycle == true || $local_backup_not_found == true ]]; then # Process rsync mirror, discerning if located at local or remote (SSH) path: [[ $RSYNC_BACKUP_PATH == *@*:/* ]] && archive_command="archive_remote_backup" || archive_command="archive_backup" # Also discerning if local backup was not found in first instance, # in which case any remote mirror that exists will be archived, but no retention policy applied with old backup chains: [[ $local_backup_not_found == true ]] && rsync_retention="" || rsync_retention=$RSYNC_BACKUP_CHAINS_TO_KEEP # In order to archive and apply (or not) retention policy on the mirror: $archive_command $RSYNC_BACKUP_PATH/$domain $rsync_retention fi done # When multiple backups chains were processed, display that the script has finished: [[ ${#retention_list[@]} -gt 1 ]] \ && echo -e "\n$(basename $0): Finished\n" else echo -e "No flags and/or domain(s) passed as arguments to check backup lifecycle or apply data retention policy\n\nUSAGE: $(basename $0) [-h |--help] <[--force] domain1 domain2...>\n" fi