Skip to content

Instantly share code, notes, and snippets.

@adamfranco
Last active February 17, 2026 17:46
Show Gist options
  • Select an option

  • Save adamfranco/d2b47f7914d9ba3026b4c4582d588239 to your computer and use it in GitHub Desktop.

Select an option

Save adamfranco/d2b47f7914d9ba3026b4c4582d588239 to your computer and use it in GitHub Desktop.
Script for downloading the latest backups from Pantheon. Triggered by a cron job that runs every few hours
#!/bin/bash
usage() {
echo "Download the latest backups from all Pantheon sites to the directory specified."
echo ""
echo "Usage: "
echo " $0 [-hld:] <backup-directory>"
echo ""
echo " -h Show this help"
echo " -s Log to syslog."
echo " -d <num> Delete backups older than this number of days."
echo " -e <emails> Email addresses (comma separated) to mail when errors occur."
echo " -t Test run. Print out the command if args are valid but don't download."
echo ""
echo "Examples:"
echo ""
echo "* Download backups to /home/myusername/pantheon_backups, deleting any"
echo " old backups that are older than 1 week:"
echo " $0 -d 7 /home/myusername/pantheon_backups"
echo ""
echo "* Email users when backups fail:"
echo " $0 -d 7 -e my-team@example.edu,other-team@example.edu /home/myusername/pantheon_backups"
exit 1
}
COMMAND="$0 $*"
LOG_TO_SYSLOG=false
TEST_RUN=false
while getopts "hstd:e:" arg; do
case $arg in
h)
usage
;;
s)
LOG_TO_SYSLOG=true
;;
t)
TEST_RUN=true
;;
d)
DELETE_DAYS=$OPTARG
if [[ "$DELETE_DAYS" < 1 ]]; then
echo "Error: -d <num> must be 1 or more"
usage
fi
;;
e)
MAIL_ON_ERROR=$OPTARG
;;
esac
done
shift $(($OPTIND - 1))
if [ "$LOG_TO_SYSLOG" = true ]; then
exec 1> >(logger -s -t $(basename $0)) 2>&1
fi
if ! command -v terminus &> /dev/null
then
echo "terminus command could not be found. Please install."
echo " https://docs.pantheon.io/terminus/install"
exit 1
fi
# Check our arguments.
BACKUP_DIR=$1
if [ ! -w "$BACKUP_DIR" ]; then
echo "$BACKUP_DIR does not exist or is not writeable"
echo ""
usage
fi
if [ "$2" != "" ]; then
echo "Extra unknown argument $2"
echo ""
usage
fi
if [ "$TEST_RUN" = true ]; then
echo "Test-run -- would run the following without the -t option:"
echo "$COMMAND"
exit 0
fi
EXIT_CODE=0
ERRORS=()
# Delete backup files older than our specified period.
if [[ ! -z "$DELETE_DAYS" ]]; then
echo "Deleting backups older than $DELETE_DAYS days."
find "$BACKUP_DIR" -name "*_files.tar.gz" -mtime $DELETE_DAYS -exec echo "Deleting old backup: {}" \; -exec rm {} \;
find "$BACKUP_DIR" -name "*_code.tar.gz" -mtime $DELETE_DAYS -exec echo "Deleting old backup: {}" \; -exec rm {} \;
find "$BACKUP_DIR" -name "*_database.sql.gz" -mtime $DELETE_DAYS -exec echo "Deleting old backup: {}" \; -exec rm {} \;
fi
# Get our list of sites.
SITES=( $(terminus org:site:list --fields name,plan_name middlebury --format=tsv | grep -vi Sandbox | awk '{print $1}' | sort) )
echo "Downloading backups from ${#SITES[@]} sites: ${SITES[@]}" 2>&1
if [[ "${#SITES[@]}" < 1 ]]; then
ERRORS+=("'terminus org:site:list' returned no results. No backups were downloaded.")
fi
# Download backups for each site.
for SITE in "${SITES[@]}"
do
# Ensure we have a directory for our site.
if [ ! -d "$BACKUP_DIR/$SITE" ]; then
mkdir "$BACKUP_DIR/$SITE"
fi
if [ ! -w "$BACKUP_DIR/$SITE" ]; then
echo "$BACKUP_DIR/$SITE is not writeable"
ERRORS+=("Download failed for $BACKUP_DIR/$SITE/$FILE""'$BACKUP_DIR/$SITE' is not writeable.")
EXIT_CODE=2
fi
# Download the latest backup file of each type, re-downloading if the file
# was corrupted.
FILE=$(terminus backup:info $SITE.live --element code --field file)
if [ -f "$BACKUP_DIR/$SITE/$FILE" ]; then
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Removing corrupted backup file $BACKUP_DIR/$SITE/$FILE"
rm "$BACKUP_DIR/$SITE/$FILE"
fi
fi
if [ ! -f "$BACKUP_DIR/$SITE/$FILE" ]; then
terminus backup:get $SITE.live --element code --to "$BACKUP_DIR/$SITE/"
echo "Downloaded backup to $BACKUP_DIR/$SITE/$FILE"
# Check the downloaded file.
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Download failed for $BACKUP_DIR/$SITE/$FILE"
ERRORS+=("Download failed for $BACKUP_DIR/$SITE/$FILE")
fi
fi
FILE=$(terminus backup:info $SITE.live --element database --field file)
if [ -f "$BACKUP_DIR/$SITE/$FILE" ]; then
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Removing corrupted backup file $BACKUP_DIR/$SITE/$FILE"
rm "$BACKUP_DIR/$SITE/$FILE"
fi
fi
if [ ! -f "$BACKUP_DIR/$SITE/$FILE" ]; then
terminus backup:get $SITE.live --element database --to "$BACKUP_DIR/$SITE/"
echo "Downloaded backup to $BACKUP_DIR/$SITE/$FILE"
# Check the downloaded file.
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Download failed for $BACKUP_DIR/$SITE/$FILE"
ERRORS+=("Download failed for $BACKUP_DIR/$SITE/$FILE")
fi
fi
FILE=$(terminus backup:info $SITE.live --element files --field file)
if [ -f "$BACKUP_DIR/$SITE/$FILE" ]; then
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Removing corrupted backup file $BACKUP_DIR/$SITE/$FILE"
rm "$BACKUP_DIR/$SITE/$FILE"
fi
fi
if [ ! -f "$BACKUP_DIR/$SITE/$FILE" ]; then
terminus backup:get $SITE.live --element files --to "$BACKUP_DIR/$SITE/"
echo "Downloaded backup to $BACKUP_DIR/$SITE/$FILE"
# Check the downloaded file.
if ! gzip -t "$BACKUP_DIR/$SITE/$FILE"; then
echo "Download failed for $BACKUP_DIR/$SITE/$FILE"
ERRORS+=("Download failed for $BACKUP_DIR/$SITE/$FILE")
fi
fi
done
if [[ "${#ERRORS[@]}" -ne 0 ]]; then
BODY=$(
printf '%s\n' "Errors occurred while downloading backups:"
printf ' * %s\n' "${ERRORS[@]}"
)
echo ""
echo "$BODY"
if [ ! -z $MAIL_ON_ERROR ]; then
echo "$BODY" | mail -s "Errors downloading Pantheon backups" "$MAIL_ON_ERROR"
fi
else
echo "Successfully completed downloading backups from Pantheon."
fi
exit $EXIT_CODE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment