Skip to content

Commit 5c0131a

Browse files
authored
Merge pull request #22 from silinternational/backup-restore
Updated the Backup Restore Script
2 parents 3e7fd9b + af32d0b commit 5c0131a

File tree

1 file changed

+128
-28
lines changed

1 file changed

+128
-28
lines changed

application/restore.sh

+128-28
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,179 @@
11
#!/usr/bin/env sh
22

3+
# Initialize logging with timestamp
4+
log() {
5+
local level="$1"
6+
local message="$2"
7+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ${level}: ${message}"
8+
}
9+
10+
# Sentry reporting with validation and backwards compatibility
11+
error_to_sentry() {
12+
local error_message="$1"
13+
local db_name="$2"
14+
local status_code="$3"
15+
16+
# Check if SENTRY_DSN is configured - ensures restore continues
17+
if [ -z "${SENTRY_DSN:-}" ]; then
18+
log "DEBUG" "Sentry logging skipped - SENTRY_DSN not configured"
19+
return 0
20+
fi
21+
22+
# Validate SENTRY_DSN format
23+
echo "${SENTRY_DSN}" | grep -E "^https://[^@]+@[^/]+/[0-9]+$" >/dev/null 2>&1
24+
if [ $? -ne 0 ]; then
25+
log "WARN" "Invalid SENTRY_DSN format - Sentry logging will be skipped"
26+
return 0
27+
fi
28+
29+
# Attempt to send event to Sentry
30+
if sentry-cli send-event \
31+
--message "${error_message}" \
32+
--level error \
33+
--tag "database:${db_name}" \
34+
--tag "status:${status_code}"; then
35+
log "DEBUG" "Successfully sent error to Sentry - Message: ${error_message}, Database: ${db_name}, Status: ${status_code}"
36+
else
37+
log "WARN" "Failed to send error to Sentry, but continuing restore process"
38+
fi
39+
40+
return 0
41+
}
42+
343
MYNAME="postgresql-backup-restore"
444
STATUS=0
5-
6-
echo "${MYNAME}: restore: Started"
45+
log "INFO" "${MYNAME}: restore: Started"
746

847
# Ensure the database user exists.
9-
echo "${MYNAME}: checking for DB user ${DB_USER}"
48+
log "INFO" "${MYNAME}: checking for DB user ${DB_USER}"
1049
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --command='\du' | grep ${DB_USER})
1150
if [ -z "${result}" ]; then
1251
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --command="create role ${DB_USER} with login password '${DB_USERPASSWORD}' inherit;")
1352
if [ "${result}" != "CREATE ROLE" ]; then
14-
message="Create role command failed: ${result}"
15-
echo "${MYNAME}: FATAL: ${message}"
53+
error_message="Create role command failed: ${result}"
54+
log "ERROR" "${MYNAME}: FATAL: ${error_message}"
55+
error_to_sentry "${error_message}" "${DB_NAME}" "1"
1656
exit 1
1757
fi
1858
fi
1959

2060
# Delete database if it exists.
21-
echo "${MYNAME}: checking for DB ${DB_NAME}"
61+
log "INFO" "${MYNAME}: checking for DB ${DB_NAME}"
2262
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --list | grep ${DB_NAME})
2363
if [ -z "${result}" ]; then
24-
message="Database "${DB_NAME}" on host "${DB_HOST}" does not exist."
25-
echo "${MYNAME}: INFO: ${message}"
64+
log "INFO" "${MYNAME}: INFO: Database \"${DB_NAME}\" on host \"${DB_HOST}\" does not exist."
2665
else
27-
message="finding current owner of DB ${DB_NAME}"
28-
echo "${MYNAME}: ${message}"
66+
log "INFO" "${MYNAME}: finding current owner of DB ${DB_NAME}"
2967
db_owner=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --command='\list' | grep ${DB_NAME} | cut -d '|' -f 2 | sed -e 's/ *//g')
30-
message="Database owner is ${db_owner}"
31-
echo "${MYNAME}: INFO: ${message}"
68+
log "INFO" "${MYNAME}: INFO: Database owner is ${db_owner}"
3269

33-
echo "${MYNAME}: deleting database ${DB_NAME}"
70+
log "INFO" "${MYNAME}: deleting database ${DB_NAME}"
3471
result=$(psql --host=${DB_HOST} --dbname=postgres --username=${db_owner} --command="DROP DATABASE ${DB_NAME};")
3572
if [ "${result}" != "DROP DATABASE" ]; then
36-
message="Drop database command failed: ${result}"
37-
echo "${MYNAME}: FATAL: ${message}"
73+
error_message="Drop database command failed: ${result}"
74+
log "ERROR" "${MYNAME}: FATAL: ${error_message}"
75+
error_to_sentry "${error_message}" "${DB_NAME}" "1"
3876
exit 1
3977
fi
4078
fi
4179

42-
echo "${MYNAME}: copying database ${DB_NAME} backup from ${S3_BUCKET}"
80+
# Download the backup and checksum files
81+
log "INFO" "${MYNAME}: copying database ${DB_NAME} backup and checksum from ${S3_BUCKET}"
4382
start=$(date +%s)
83+
84+
# Download database backup
4485
s3cmd get -f ${S3_BUCKET}/${DB_NAME}.sql.gz /tmp/${DB_NAME}.sql.gz || STATUS=$?
45-
end=$(date +%s)
86+
if [ $STATUS -ne 0 ]; then
87+
error_message="${MYNAME}: FATAL: Copy backup of ${DB_NAME} from ${S3_BUCKET} returned non-zero status ($STATUS) in $(expr $(date +%s) - ${start}) seconds."
88+
log "ERROR" "${error_message}"
89+
error_to_sentry "${error_message}" "${DB_NAME}" "${STATUS}"
90+
exit $STATUS
91+
fi
4692

93+
# Download checksum file
94+
s3cmd get -f ${S3_BUCKET}/${DB_NAME}.sql.sha256.gz /tmp/${DB_NAME}.sql.sha256.gz || STATUS=$?
95+
end=$(date +%s)
4796
if [ $STATUS -ne 0 ]; then
48-
echo "${MYNAME}: FATAL: Copy backup of ${DB_NAME} from ${S3_BUCKET} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
97+
error_message="${MYNAME}: FATAL: Copy checksum of ${DB_NAME} from ${S3_BUCKET} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
98+
log "ERROR" "${error_message}"
99+
error_to_sentry "${error_message}" "${DB_NAME}" "${STATUS}"
49100
exit $STATUS
50101
else
51-
echo "${MYNAME}: Copy backup of ${DB_NAME} from ${S3_BUCKET} completed in $(expr ${end} - ${start}) seconds."
102+
log "INFO" "${MYNAME}: Copy backup and checksum of ${DB_NAME} from ${S3_BUCKET} completed in $(expr ${end} - ${start}) seconds."
52103
fi
53104

54-
echo "${MYNAME}: decompressing backup of ${DB_NAME}"
105+
# Decompress both files
106+
log "INFO" "${MYNAME}: decompressing backup and checksum of ${DB_NAME}"
55107
start=$(date +%s)
108+
109+
# Decompress backup file
56110
gunzip -f /tmp/${DB_NAME}.sql.gz || STATUS=$?
57-
end=$(date +%s)
111+
if [ $STATUS -ne 0 ]; then
112+
error_message="${MYNAME}: FATAL: Decompressing backup of ${DB_NAME} returned non-zero status ($STATUS) in $(expr $(date +%s) - ${start}) seconds."
113+
log "ERROR" "${error_message}"
114+
error_to_sentry "${error_message}" "${DB_NAME}" "${STATUS}"
115+
exit $STATUS
116+
fi
58117

118+
# Decompress checksum file
119+
gunzip -f /tmp/${DB_NAME}.sql.sha256.gz || STATUS=$?
120+
end=$(date +%s)
59121
if [ $STATUS -ne 0 ]; then
60-
echo "${MYNAME}: FATAL: Decompressing backup of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
122+
error_message="${MYNAME}: FATAL: Decompressing checksum of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
123+
log "ERROR" "${error_message}"
124+
error_to_sentry "${error_message}" "${DB_NAME}" "${STATUS}"
61125
exit $STATUS
62126
else
63-
echo "${MYNAME}: Decompressing backup of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
127+
log "INFO" "${MYNAME}: Decompressing backup and checksum of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
64128
fi
65129

66-
echo "${MYNAME}: restoring ${DB_NAME}"
130+
# Validate the checksum
131+
log "INFO" "${MYNAME}: Validating backup integrity with checksum"
132+
cd /tmp || {
133+
error_message="${MYNAME}: FATAL: Failed to change directory to /tmp"
134+
log "ERROR" "${error_message}"
135+
error_to_sentry "${error_message}" "${DB_NAME}" "1"
136+
exit 1
137+
}
138+
139+
sha256sum -c "${DB_NAME}.sql.sha256" || {
140+
error_message="${MYNAME}: FATAL: Checksum validation failed for backup of ${DB_NAME}. The backup may be corrupted or tampered with."
141+
log "ERROR" "${error_message}"
142+
error_to_sentry "${error_message}" "${DB_NAME}" "1"
143+
exit 1
144+
}
145+
log "INFO" "${MYNAME}: Checksum validation successful - backup integrity confirmed"
146+
147+
# Restore the database
148+
log "INFO" "${MYNAME}: restoring ${DB_NAME}"
67149
start=$(date +%s)
68-
psql --host=${DB_HOST} --username=${DB_ROOTUSER} --dbname=postgres ${DB_OPTIONS} < /tmp/${DB_NAME}.sql || STATUS=$?
150+
psql --host=${DB_HOST} --username=${DB_ROOTUSER} --dbname=postgres ${DB_OPTIONS} < /tmp/${DB_NAME}.sql || STATUS=$?
69151
end=$(date +%s)
70152

71153
if [ $STATUS -ne 0 ]; then
72-
echo "${MYNAME}: FATAL: Restore of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
154+
error_message="${MYNAME}: FATAL: Restore of ${DB_NAME} returned non-zero status ($STATUS) in $(expr ${end} - ${start}) seconds."
155+
log "ERROR" "${error_message}"
156+
error_to_sentry "${error_message}" "${DB_NAME}" "${STATUS}"
73157
exit $STATUS
74158
else
75-
echo "${MYNAME}: Restore of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
159+
log "INFO" "${MYNAME}: Restore of ${DB_NAME} completed in $(expr ${end} - ${start}) seconds."
76160
fi
77161

78-
echo "${MYNAME}: restore: Completed"
162+
# Verify database restore success
163+
log "INFO" "${MYNAME}: Verifying database restore success"
164+
result=$(psql --host=${DB_HOST} --username=${DB_ROOTUSER} --list | grep ${DB_NAME})
165+
if [ -z "${result}" ]; then
166+
error_message="${MYNAME}: FATAL: Database ${DB_NAME} not found after restore attempt."
167+
log "ERROR" "${error_message}"
168+
error_to_sentry "${error_message}" "${DB_NAME}" "1"
169+
exit 1
170+
else
171+
log "INFO" "${MYNAME}: Database ${DB_NAME} successfully restored and verified."
172+
fi
173+
174+
# Clean up temporary files
175+
rm -f "/tmp/${DB_NAME}.sql" "/tmp/${DB_NAME}.sql.sha256"
176+
log "INFO" "${MYNAME}: Temporary files cleaned up"
177+
178+
log "INFO" "${MYNAME}: restore: Completed"
79179
exit $STATUS

0 commit comments

Comments
 (0)