Initial backup skill implementation
This commit is contained in:
146
scripts/backup.sh
Normal file
146
scripts/backup.sh
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
BACKUP_TARGET="${BACKUP_TARGET:-/backups}"
|
||||
BACKUP_PASSWORD="${BACKUP_PASSWORD:-}"
|
||||
BACKUP_RETENTION="${BACKUP_RETENTION:-7d}"
|
||||
|
||||
# Paths to backup
|
||||
BACKUP_PATHS=(
|
||||
"/data/postgres"
|
||||
"/data/redis"
|
||||
"/data/duckdb"
|
||||
"/data/loki"
|
||||
"/data/caddy"
|
||||
"/personalities"
|
||||
"/workspaces"
|
||||
)
|
||||
|
||||
# Validate password
|
||||
if [ -z "$BACKUP_PASSWORD" ]; then
|
||||
echo "ERROR: BACKUP_PASSWORD is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Setup restic environment
|
||||
export RESTIC_PASSWORD="$BACKUP_PASSWORD"
|
||||
export RESTIC_REPOSITORY="$BACKUP_TARGET"
|
||||
|
||||
# Setup cloud credentials if provided
|
||||
[ -n "$BACKUP_S3_ACCESS_KEY" ] && export AWS_ACCESS_KEY_ID="$BACKUP_S3_ACCESS_KEY"
|
||||
[ -n "$BACKUP_S3_SECRET_KEY" ] && export AWS_SECRET_ACCESS_KEY="$BACKUP_S3_SECRET_KEY"
|
||||
[ -n "$BACKUP_B2_ACCOUNT_ID" ] && export B2_ACCOUNT_ID="$BACKUP_B2_ACCOUNT_ID"
|
||||
[ -n "$BACKUP_B2_ACCOUNT_KEY" ] && export B2_ACCOUNT_KEY="$BACKUP_B2_ACCOUNT_KEY"
|
||||
|
||||
START_TIME=$(date +%s)
|
||||
echo "=== VibeStack Backup ==="
|
||||
echo "Time: $(date -Iseconds)"
|
||||
echo "Target: $BACKUP_TARGET"
|
||||
echo ""
|
||||
|
||||
# Pre-backup: dump PostgreSQL if running
|
||||
pre_backup_postgres() {
|
||||
if command -v pg_dump &>/dev/null && [ -d "/data/postgres" ]; then
|
||||
echo "Creating PostgreSQL dump..."
|
||||
|
||||
# Source postgres env if available
|
||||
[ -f /run/vibestack/postgres.env ] && source /run/vibestack/postgres.env
|
||||
|
||||
local pg_user="${POSTGRES_USER:-vibestack}"
|
||||
local pg_db="${POSTGRES_DB:-vibestack}"
|
||||
local dump_file="/data/postgres/backup.sql"
|
||||
|
||||
if pg_dump -U "$pg_user" -d "$pg_db" -f "$dump_file" 2>/dev/null; then
|
||||
echo " PostgreSQL dump created: $dump_file"
|
||||
else
|
||||
echo " PostgreSQL dump skipped (database not running or accessible)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Pre-backup: trigger Redis BGSAVE if running
|
||||
pre_backup_redis() {
|
||||
if command -v redis-cli &>/dev/null; then
|
||||
echo "Triggering Redis BGSAVE..."
|
||||
|
||||
# Source redis env if available
|
||||
[ -f /run/vibestack/redis.env ] && source /run/vibestack/redis.env
|
||||
|
||||
local redis_pass="${REDIS_PASSWORD:-}"
|
||||
local auth_args=""
|
||||
[ -n "$redis_pass" ] && auth_args="-a $redis_pass"
|
||||
|
||||
if redis-cli $auth_args BGSAVE 2>/dev/null; then
|
||||
# Wait for save to complete
|
||||
sleep 2
|
||||
echo " Redis BGSAVE triggered"
|
||||
else
|
||||
echo " Redis BGSAVE skipped (not running)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Run pre-backup hooks
|
||||
echo "Running pre-backup hooks..."
|
||||
pre_backup_postgres
|
||||
pre_backup_redis
|
||||
echo ""
|
||||
|
||||
# Build list of paths that exist
|
||||
existing_paths=()
|
||||
for path in "${BACKUP_PATHS[@]}"; do
|
||||
if [ -e "$path" ]; then
|
||||
existing_paths+=("$path")
|
||||
echo "Including: $path"
|
||||
fi
|
||||
done
|
||||
|
||||
# Allow overriding with specific path
|
||||
if [ -n "$1" ] && [ -e "$1" ]; then
|
||||
existing_paths=("$1")
|
||||
echo "Backing up only: $1"
|
||||
fi
|
||||
|
||||
if [ ${#existing_paths[@]} -eq 0 ]; then
|
||||
echo "WARNING: No paths to backup"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Starting backup..."
|
||||
|
||||
# Run restic backup
|
||||
BACKUP_OUTPUT=$(restic backup "${existing_paths[@]}" --json 2>&1 | tail -1)
|
||||
|
||||
# Parse results
|
||||
SNAPSHOT_ID=$(echo "$BACKUP_OUTPUT" | jq -r '.snapshot_id // empty' 2>/dev/null || echo "")
|
||||
BYTES_ADDED=$(echo "$BACKUP_OUTPUT" | jq -r '.data_added // 0' 2>/dev/null || echo "0")
|
||||
|
||||
END_TIME=$(date +%s)
|
||||
DURATION=$((END_TIME - START_TIME))
|
||||
|
||||
echo ""
|
||||
echo "Backup complete!"
|
||||
echo " Snapshot: ${SNAPSHOT_ID:-unknown}"
|
||||
echo " Duration: ${DURATION}s"
|
||||
echo " Data added: $BYTES_ADDED bytes"
|
||||
|
||||
# Apply retention policy
|
||||
echo ""
|
||||
echo "Applying retention policy: keep within $BACKUP_RETENTION..."
|
||||
restic forget --keep-within "$BACKUP_RETENTION" --prune
|
||||
|
||||
# Write status
|
||||
cat > /run/vibestack/backup-status.json << EOF
|
||||
{
|
||||
"status": "idle",
|
||||
"last_backup": "$(date -Iseconds)",
|
||||
"last_status": "success",
|
||||
"snapshot_id": "$SNAPSHOT_ID",
|
||||
"duration_seconds": $DURATION,
|
||||
"bytes_added": $BYTES_ADDED
|
||||
}
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "=== Backup Complete ==="
|
||||
Reference in New Issue
Block a user