├── README.md └── backup.sh /README.md: -------------------------------------------------------------------------------- 1 | # forge-database-backups 2 | -------------------------------------------------------------------------------- /backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eo pipefail 4 | 5 | BACKUP_STATUS=0 6 | BACKUP_TIMESTAMP=$(date +%Y%m%d%H%M%S) 7 | BACKUP_ARCHIVE_PATH="" 8 | BACKUP_ARCHIVES=() 9 | BACKUP_ARCHIVES_JSON="" 10 | 11 | trap 'cleanup $? $LINENO' EXIT 12 | 13 | cleanup() 14 | { 15 | echo "Cleaning up backup." 16 | 17 | # Handle Errors 18 | 19 | if [ $1 != 0 ]; then 20 | echo "Exit code $1 occurred on line $2" 21 | BACKUP_STATUS=1 22 | fi 23 | 24 | if [[ ${#BACKUP_ARCHIVES[@]} -gt 0 ]]; 25 | then 26 | BACKUP_ARCHIVES_JSON=$(echo "[$(printf '{\"%s\": %d},' ${BACKUP_ARCHIVES[@]} | sed '$s/,$//')]") 27 | fi 28 | 29 | curl -s --request POST \ 30 | --url "$FORGE_PING_CALLBACK" \ 31 | --data-urlencode "type=backup" \ 32 | --data-urlencode "backup_token=$BACKUP_TOKEN" \ 33 | --data-urlencode "streamed=true" \ 34 | --data-urlencode "status=$BACKUP_STATUS" \ 35 | --data-urlencode "backup_configuration_id=$BACKUP_ID" \ 36 | --data-urlencode "archives=$BACKUP_ARCHIVES_JSON" \ 37 | --data-urlencode "archive_path=$BACKUP_FULL_STORAGE_PATH$BACKUP_TIMESTAMP" \ 38 | --data-urlencode "started_at=$SCRIPT_STARTED_AT" \ 39 | --data-urlencode "uuid=$BACKUP_UUID" 40 | } 41 | 42 | echo "Streaming backups to storage..." 43 | 44 | for DATABASE in $BACKUP_DATABASES; do 45 | BACKUP_ARCHIVE_NAME="$DATABASE.sql.gz" 46 | BACKUP_ARCHIVE_PATH="$BACKUP_FULL_STORAGE_PATH$BACKUP_TIMESTAMP/$BACKUP_ARCHIVE_NAME" 47 | 48 | if [[ $SERVER_DATABASE_DRIVER == 'mysql' ]] 49 | then 50 | mysqldump \ 51 | --user=root \ 52 | --password=$SERVER_DATABASE_PASSWORD \ 53 | --single-transaction \ 54 | --skip-lock-tables \ 55 | --routines \ 56 | --hex-blob \ 57 | -B \ 58 | $DATABASE | \ 59 | gzip -c | aws s3 cp - "$BACKUP_ARCHIVE_PATH" \ 60 | --profile=$BACKUP_AWS_PROFILE_NAME \ 61 | ${BACKUP_AWS_ENDPOINT:+ --endpoint=$BACKUP_AWS_ENDPOINT} \ 62 | ${BACKUP_AWS_ENDPOINT:+ --endpoint-url=$BACKUP_AWS_ENDPOINT} 63 | 64 | RC=( "${PIPESTATUS[@]}" ) 65 | STATUS=${RC[0]} 66 | elif [[ $SERVER_DATABASE_DRIVER == 'mariadb' ]] 67 | then 68 | mariadb-dump \ 69 | --user=root \ 70 | --password=$SERVER_DATABASE_PASSWORD \ 71 | --single-transaction \ 72 | --skip-lock-tables \ 73 | --routines \ 74 | --hex-blob \ 75 | -B \ 76 | $DATABASE | \ 77 | gzip -c | aws s3 cp - "$BACKUP_ARCHIVE_PATH" \ 78 | --profile=$BACKUP_AWS_PROFILE_NAME \ 79 | ${BACKUP_AWS_ENDPOINT:+ --endpoint=$BACKUP_AWS_ENDPOINT} \ 80 | ${BACKUP_AWS_ENDPOINT:+ --endpoint-url=$BACKUP_AWS_ENDPOINT} 81 | 82 | RC=( "${PIPESTATUS[@]}" ) 83 | STATUS=${RC[0]} 84 | elif [[ $SERVER_DATABASE_DRIVER == 'pgsql' ]] 85 | then 86 | # The postgres user cannot access /root/.backups, so switch to /tmp 87 | 88 | cd /tmp 89 | 90 | sudo -u postgres pg_dump --clean --create -F p $DATABASE | \ 91 | gzip -c | aws s3 cp - "$BACKUP_ARCHIVE_PATH" \ 92 | --profile=$BACKUP_AWS_PROFILE_NAME \ 93 | ${BACKUP_AWS_ENDPOINT:+ --endpoint=$BACKUP_AWS_ENDPOINT} \ 94 | ${BACKUP_AWS_ENDPOINT:+ --endpoint-url=$BACKUP_AWS_ENDPOINT} 95 | 96 | RC=( "${PIPESTATUS[@]}" ) 97 | STATUS=${RC[0]} 98 | fi 99 | 100 | # Check Exit Code Of Backup 101 | 102 | if [[ $STATUS -gt 0 ]]; 103 | then 104 | BACKUP_STATUS=1 105 | 106 | echo "There was a problem during the backup process. Exit code: $STATUS" 107 | 108 | continue 109 | fi 110 | 111 | if [[ $BACKUP_STATUS -eq 0 ]]; 112 | then 113 | # Get The Size Of This File And Store It 114 | 115 | BACKUP_ARCHIVE_SIZE=$(aws s3 ls "$BACKUP_ARCHIVE_PATH" \ 116 | --profile=$BACKUP_AWS_PROFILE_NAME \ 117 | ${BACKUP_AWS_ENDPOINT:+ --endpoint=$BACKUP_AWS_ENDPOINT} \ 118 | ${BACKUP_AWS_ENDPOINT:+ --endpoint-url=$BACKUP_AWS_ENDPOINT} | \ 119 | awk '{print $3}') 120 | 121 | RC=( "${PIPESTATUS[@]}" ) 122 | STATUS=${RC[0]} 123 | fi 124 | 125 | BACKUP_ARCHIVES+=($BACKUP_ARCHIVE_NAME $BACKUP_ARCHIVE_SIZE) 126 | done 127 | 128 | exit $BACKUP_STATUS 129 | --------------------------------------------------------------------------------