bliss/backup-deployed.sh
2026-08-02 23:00:26 -04:00

108 lines
2.7 KiB
Bash
Executable file

#!/usr/bin/env bash
set -Eeuo pipefail
ACTIVATE=false
if [[ "${1:-}" == "--activate" ]]; then
ACTIVATE=true
shift
fi
if [[ "$#" -ne 0 ]]; then
echo "Usage: $0 [--activate]" >&2
exit 2
fi
REMOTE="${BLISS_BACKUP_REMOTE:-root@134.122.14.193}"
APP_DIR="${BLISS_BACKUP_APP_DIR:-/home/nodejs/bliss2}"
LOCAL_DIR="${BLISS_BACKUP_LOCAL_DIR:-$(pwd)/backups}"
STAMP="$(date +%Y%m%d-%H%M%S)"
ARCHIVE="$LOCAL_DIR/bliss-backup-$STAMP.tar.gz"
PARTIAL="$ARCHIVE.partial"
mkdir -p "$LOCAL_DIR"
rm -f "$PARTIAL"
cleanup() {
rm -f "$PARTIAL"
}
trap cleanup EXIT
echo "Backing up $REMOTE:$APP_DIR"
echo "You may be prompted for the droplet passcode."
ssh -o ConnectTimeout=15 "$REMOTE" bash -s -- "$APP_DIR" >"$PARTIAL" <<'REMOTE_SCRIPT'
set -Eeuo pipefail
APP_DIR="$1"
test -d "$APP_DIR/public"
test -d "$APP_DIR/dbs"
test -f "$APP_DIR/package.json"
TMP_DIR="$(mktemp -d /root/bliss-backup.XXXXXX)"
cleanup_remote() {
rm -rf "$TMP_DIR"
}
trap cleanup_remote EXIT
mkdir -p "$TMP_DIR/dbs"
cd "$APP_DIR"
echo "Creating consistent SQLite snapshots..." >&2
BACKUP_DIR="$TMP_DIR/dbs" node <<'NODE'
const fs = require("fs");
const path = require("path");
const Database = require("better-sqlite3");
(async () => {
const names = fs.readdirSync("dbs").filter(name => name.endsWith(".sqlite"));
if (names.length === 0) throw new Error("No SQLite databases found in dbs/");
for (const name of names) {
const source = new Database(path.resolve("dbs", name), { readonly: true });
const destination = path.join(process.env.BACKUP_DIR, name);
await source.backup(destination);
source.close();
const snapshot = new Database(destination, { readonly: true });
const result = snapshot.pragma("quick_check", { simple: true });
snapshot.close();
if (result !== "ok") throw new Error(`${name}: SQLite quick_check returned ${result}`);
console.error(` ${name}: OK`);
}
})().catch(error => {
console.error(error);
process.exit(1);
});
NODE
echo "Copying static files..." >&2
cp -a public "$TMP_DIR/public"
printf 'source=%s\ncreated_utc=%s\n' \
"$APP_DIR" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$TMP_DIR/MANIFEST.txt"
echo "Streaming compressed archive..." >&2
tar -C "$TMP_DIR" -czf - MANIFEST.txt public dbs
REMOTE_SCRIPT
echo "Verifying downloaded archive..."
gzip -t "$PARTIAL"
tar -tzf "$PARTIAL" >/dev/null
DB_COUNT="$(tar -tzf "$PARTIAL" | awk '/^dbs\/[^/]+\.sqlite$/ {count++} END {print count+0}')"
if [[ "$DB_COUNT" -eq 0 ]]; then
echo "Backup verification failed: archive contains no SQLite databases" >&2
exit 1
fi
mv "$PARTIAL" "$ARCHIVE"
trap - EXIT
echo "Backup complete: $ARCHIVE"
echo "SQLite databases: $DB_COUNT"
du -h "$ARCHIVE"
if [[ "$ACTIVATE" == true ]]; then
echo
"$(dirname "$0")/switch-bliss-data.sh" "$ARCHIVE"
fi