You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
3.0 KiB
86 lines
3.0 KiB
#!/bin/bash
|
|
set -Eeuo pipefail
|
|
|
|
MATRIX_URL="http://127.0.0.1:${TUWUNEL_PORT:-6167}"
|
|
BACKUP_RETENTION="${MATRIX_BACKUP_RETENTION:-7}"
|
|
ADMIN_ACCESS_TOKEN="${MATRIX_BACKUP_ACCESS_TOKEN}"
|
|
ADMIN_ROOM_ID="${MATRIX_BACKUP_ROOM_ID}"
|
|
BACKUP_TIMEOUT="${MATRIX_BACKUP_TIMEOUT:-300}"
|
|
BACKUP_CHECK_INTERVAL="${MATRIX_BACKUP_CHECK_INTERVAL:-30}"
|
|
|
|
MARKER="$(mktemp)"
|
|
STAGING="$(mktemp -d)"
|
|
trap 'rm -rf "$MARKER" "$STAGING"' EXIT
|
|
|
|
echo "Triggering Tuwunel online database backup..."
|
|
|
|
# Send '!admin server backup-database' to the admin room via the Matrix API
|
|
TXN_ID="backup-$(date +%s)"
|
|
curl -sSf -o /dev/null -X PUT \
|
|
-H "Authorization: Bearer ${ADMIN_ACCESS_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"msgtype":"m.text","body":"!admin server backup-database"}' \
|
|
"${MATRIX_URL}/_matrix/client/v3/rooms/${ADMIN_ROOM_ID}/send/m.room.message/${TXN_ID}"
|
|
|
|
echo "Backup command sent. Waiting for Tuwunel to complete it..."
|
|
|
|
# Wait for new/updated files to appear under the backup source (max 5 minutes)
|
|
TIMEOUT="${BACKUP_TIMEOUT}"
|
|
ELAPSED=0
|
|
INTERVAL="${BACKUP_CHECK_INTERVAL}"
|
|
while [ "$ELAPSED" -lt "$TIMEOUT" ]; do
|
|
if find "${BACKUP_SOURCE}" -newer "${MARKER}" -type f 2>/dev/null | grep -q .; then
|
|
echo "Backup files detected after ${ELAPSED}s."
|
|
break
|
|
fi
|
|
sleep "$INTERVAL"
|
|
ELAPSED=$((ELAPSED + INTERVAL))
|
|
done
|
|
|
|
if [ "$ELAPSED" -ge "$TIMEOUT" ]; then
|
|
echo "ERROR: Timed out waiting for backup after ${TIMEOUT}s." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Find the latest numbered backup directory created by RocksDB BackupEngine
|
|
LATEST_NUM=$(ls -1 "${BACKUP_SOURCE}/private" | grep -E '^[0-9]+$' | sort -n | tail -1)
|
|
if [ -z "$LATEST_NUM" ]; then
|
|
echo "ERROR: No numbered backup directory found in ${BACKUP_SOURCE}/private." >&2
|
|
exit 1
|
|
fi
|
|
echo "Processing RocksDB backup #${LATEST_NUM} into restore-ready format..."
|
|
|
|
# 1. Copy and rename SST files from shared_checksum/:
|
|
# ######_sXXXXXXXX.sst → ######.sst
|
|
SHARED="${BACKUP_SOURCE}/shared_checksum"
|
|
if [ -d "${SHARED}" ]; then
|
|
for sst in "${SHARED}"/*.sst; do
|
|
[ -f "$sst" ] || continue
|
|
dest=$(basename "$sst" | sed 's/_s.*/.sst/')
|
|
cp "$sst" "${STAGING}/${dest}"
|
|
done
|
|
fi
|
|
|
|
# 2. Copy all files from the latest numbered directory (CURRENT, MANIFEST, OPTIONS, ...)
|
|
find "${BACKUP_SOURCE}/private/${LATEST_NUM}" -maxdepth 1 -type f | while read -r f; do
|
|
cp "$f" "${STAGING}/"
|
|
done
|
|
|
|
# Archive the restore-ready staging directory
|
|
BACKUP_DATE=$(date +%Y-%m-%d_%H-%M-%S)
|
|
ARCHIVE="${BACKUP_DEST}/${BACKUP_DATE}.tar.gz"
|
|
|
|
echo "Archiving restore-ready backup to ${ARCHIVE}..."
|
|
tar -czf "${ARCHIVE}" -C "${STAGING}" .
|
|
echo "Backup archived ($(du -sh "${ARCHIVE}" | cut -f1))."
|
|
|
|
# Apply retention policy
|
|
if [ "${BACKUP_RETENTION}" -gt 0 ] && ls "${BACKUP_DEST}"/*.tar.gz > /dev/null 2>&1; then
|
|
echo "Applying retention policy: keeping last ${BACKUP_RETENTION} backups."
|
|
ls -1t "${BACKUP_DEST}"/*.tar.gz | tail -n "+$((BACKUP_RETENTION + 1))" | while read -r old; do
|
|
echo "Removing old backup: ${old}"
|
|
rm -f "${old}"
|
|
done
|
|
fi
|
|
|
|
echo "Backup completed successfully."
|
|
|