Some checks are pending
CI Pipeline / Run Tests (push) Waiting to run
CI Pipeline / Lint Code (push) Waiting to run
CI Pipeline / Security Scan (push) Waiting to run
CI Pipeline / Build Docker Images (push) Blocked by required conditions
CI Pipeline / E2E Tests (push) Blocked by required conditions
233 lines
7.4 KiB
Bash
Executable File
233 lines
7.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Database Migration Script
|
|
# Handles database schema migrations and data updates
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
DB_PATH="${PROJECT_ROOT}/data/metadata.db"
|
|
|
|
echo "🔄 Database Migration Script"
|
|
echo "==========================="
|
|
|
|
cd "$PROJECT_ROOT"
|
|
|
|
# Check if database exists
|
|
if [ ! -f "$DB_PATH" ]; then
|
|
echo "❌ Database not found: $DB_PATH"
|
|
echo "Please ensure the gateway has been initialized first"
|
|
exit 1
|
|
fi
|
|
|
|
# Create backup before migration
|
|
echo "💾 Creating pre-migration backup..."
|
|
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
|
|
BACKUP_FILE="./backups/pre_migration_${TIMESTAMP}.sql"
|
|
mkdir -p backups
|
|
|
|
sqlite3 "$DB_PATH" .dump > "$BACKUP_FILE"
|
|
echo "✅ Backup created: $BACKUP_FILE"
|
|
|
|
# Check current schema version
|
|
echo "📊 Checking current schema..."
|
|
CURRENT_TABLES=$(sqlite3 "$DB_PATH" ".tables")
|
|
echo "Current tables: $CURRENT_TABLES"
|
|
|
|
# Migration functions
|
|
run_migration() {
|
|
local version="$1"
|
|
local description="$2"
|
|
local sql="$3"
|
|
|
|
echo "🔄 Migration $version: $description"
|
|
|
|
if sqlite3 "$DB_PATH" "$sql"; then
|
|
echo "✅ Migration $version completed"
|
|
|
|
# Log migration
|
|
sqlite3 "$DB_PATH" "INSERT OR IGNORE INTO schema_migrations (version, description, applied_at) VALUES ('$version', '$description', datetime('now'));"
|
|
else
|
|
echo "❌ Migration $version failed"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Create migrations table if it doesn't exist
|
|
echo "🗄️ Creating migrations table..."
|
|
sqlite3 "$DB_PATH" "
|
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
version TEXT PRIMARY KEY,
|
|
description TEXT NOT NULL,
|
|
applied_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);"
|
|
|
|
# Check which migrations have been applied
|
|
APPLIED_MIGRATIONS=$(sqlite3 "$DB_PATH" "SELECT version FROM schema_migrations;" 2>/dev/null || echo "")
|
|
echo "Applied migrations: $APPLIED_MIGRATIONS"
|
|
|
|
# Migration 1: Add performance indexes
|
|
if ! echo "$APPLIED_MIGRATIONS" | grep -q "001_performance_indexes"; then
|
|
run_migration "001_performance_indexes" "Add performance indexes" "
|
|
CREATE INDEX IF NOT EXISTS idx_files_owner_pubkey ON files(owner_pubkey);
|
|
CREATE INDEX IF NOT EXISTS idx_files_storage_type ON files(storage_type);
|
|
CREATE INDEX IF NOT EXISTS idx_files_access_level ON files(access_level);
|
|
CREATE INDEX IF NOT EXISTS idx_files_size ON files(size);
|
|
CREATE INDEX IF NOT EXISTS idx_files_last_access ON files(last_access);
|
|
CREATE INDEX IF NOT EXISTS idx_chunks_chunk_hash ON chunks(chunk_hash);
|
|
CREATE INDEX IF NOT EXISTS idx_users_storage_used ON users(storage_used);
|
|
"
|
|
else
|
|
echo "⏭️ Skipping migration 001_performance_indexes (already applied)"
|
|
fi
|
|
|
|
# Migration 2: Add monitoring columns
|
|
if ! echo "$APPLIED_MIGRATIONS" | grep -q "002_monitoring_columns"; then
|
|
run_migration "002_monitoring_columns" "Add monitoring and metrics columns" "
|
|
ALTER TABLE files ADD COLUMN download_count INTEGER DEFAULT 0;
|
|
ALTER TABLE files ADD COLUMN stream_count INTEGER DEFAULT 0;
|
|
ALTER TABLE users ADD COLUMN bandwidth_used INTEGER DEFAULT 0;
|
|
ALTER TABLE users ADD COLUMN api_requests INTEGER DEFAULT 0;
|
|
CREATE INDEX IF NOT EXISTS idx_files_download_count ON files(download_count);
|
|
CREATE INDEX IF NOT EXISTS idx_files_stream_count ON files(stream_count);
|
|
"
|
|
else
|
|
echo "⏭️ Skipping migration 002_monitoring_columns (already applied)"
|
|
fi
|
|
|
|
# Migration 3: Add cache tables
|
|
if ! echo "$APPLIED_MIGRATIONS" | grep -q "003_cache_tables"; then
|
|
run_migration "003_cache_tables" "Add cache management tables" "
|
|
CREATE TABLE IF NOT EXISTS cache_entries (
|
|
cache_key TEXT PRIMARY KEY,
|
|
cache_value BLOB,
|
|
cache_type TEXT NOT NULL,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
expires_at DATETIME,
|
|
hit_count INTEGER DEFAULT 0
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_cache_entries_type ON cache_entries(cache_type);
|
|
CREATE INDEX IF NOT EXISTS idx_cache_entries_expires ON cache_entries(expires_at);
|
|
"
|
|
else
|
|
echo "⏭️ Skipping migration 003_cache_tables (already applied)"
|
|
fi
|
|
|
|
# Migration 4: Add rate limiting tables
|
|
if ! echo "$APPLIED_MIGRATIONS" | grep -q "004_rate_limiting"; then
|
|
run_migration "004_rate_limiting" "Add rate limiting tracking" "
|
|
CREATE TABLE IF NOT EXISTS rate_limit_events (
|
|
id INTEGER PRIMARY KEY,
|
|
client_ip TEXT NOT NULL,
|
|
limit_type TEXT NOT NULL,
|
|
blocked BOOLEAN DEFAULT FALSE,
|
|
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE INDEX IF NOT EXISTS idx_rate_limit_ip ON rate_limit_events(client_ip);
|
|
CREATE INDEX IF NOT EXISTS idx_rate_limit_timestamp ON rate_limit_events(timestamp);
|
|
"
|
|
else
|
|
echo "⏭️ Skipping migration 004_rate_limiting (already applied)"
|
|
fi
|
|
|
|
# Data consistency checks
|
|
echo "🔍 Running data consistency checks..."
|
|
|
|
# Check for orphaned chunks
|
|
ORPHANED_CHUNKS=$(sqlite3 "$DB_PATH" "
|
|
SELECT COUNT(*) FROM chunks c
|
|
LEFT JOIN files f ON c.file_hash = f.hash
|
|
WHERE f.hash IS NULL;
|
|
")
|
|
|
|
if [ "$ORPHANED_CHUNKS" -gt 0 ]; then
|
|
echo "⚠️ Found $ORPHANED_CHUNKS orphaned chunks"
|
|
read -p "Remove orphaned chunks? (y/N): " -n 1 -r
|
|
echo
|
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
sqlite3 "$DB_PATH" "
|
|
DELETE FROM chunks WHERE file_hash NOT IN (SELECT hash FROM files);
|
|
"
|
|
echo "✅ Orphaned chunks removed"
|
|
fi
|
|
else
|
|
echo "✅ No orphaned chunks found"
|
|
fi
|
|
|
|
# Check for expired sessions
|
|
EXPIRED_SESSIONS=$(sqlite3 "$DB_PATH" "
|
|
SELECT COUNT(*) FROM sessions
|
|
WHERE expires_at < datetime('now');
|
|
")
|
|
|
|
if [ "$EXPIRED_SESSIONS" -gt 0 ]; then
|
|
echo "🧹 Cleaning up $EXPIRED_SESSIONS expired sessions..."
|
|
sqlite3 "$DB_PATH" "DELETE FROM sessions WHERE expires_at < datetime('now');"
|
|
echo "✅ Expired sessions cleaned"
|
|
else
|
|
echo "✅ No expired sessions found"
|
|
fi
|
|
|
|
# Update storage statistics
|
|
echo "📊 Updating storage statistics..."
|
|
sqlite3 "$DB_PATH" "
|
|
UPDATE users SET
|
|
storage_used = (
|
|
SELECT COALESCE(SUM(size), 0)
|
|
FROM files
|
|
WHERE owner_pubkey = users.pubkey
|
|
),
|
|
file_count = (
|
|
SELECT COUNT(*)
|
|
FROM files
|
|
WHERE owner_pubkey = users.pubkey
|
|
);
|
|
"
|
|
echo "✅ Storage statistics updated"
|
|
|
|
# Vacuum database for performance
|
|
echo "🧹 Optimizing database..."
|
|
sqlite3 "$DB_PATH" "VACUUM;"
|
|
sqlite3 "$DB_PATH" "ANALYZE;"
|
|
echo "✅ Database optimized"
|
|
|
|
# Final validation
|
|
echo "🔍 Final validation..."
|
|
|
|
# Check table integrity
|
|
INTEGRITY_CHECK=$(sqlite3 "$DB_PATH" "PRAGMA integrity_check;")
|
|
if [ "$INTEGRITY_CHECK" = "ok" ]; then
|
|
echo "✅ Database integrity check passed"
|
|
else
|
|
echo "❌ Database integrity check failed: $INTEGRITY_CHECK"
|
|
FAILED_CHECKS=$((FAILED_CHECKS + 1))
|
|
fi
|
|
|
|
# Check foreign key constraints
|
|
FK_CHECK=$(sqlite3 "$DB_PATH" "PRAGMA foreign_key_check;")
|
|
if [ -z "$FK_CHECK" ]; then
|
|
echo "✅ Foreign key constraints valid"
|
|
else
|
|
echo "⚠️ Foreign key constraint violations found: $FK_CHECK"
|
|
fi
|
|
|
|
echo ""
|
|
echo "📊 Migration Summary"
|
|
echo "==================="
|
|
echo "Total checks: $TOTAL_CHECKS"
|
|
echo "Passed: $PASSED_CHECKS"
|
|
echo "Failed: $FAILED_CHECKS"
|
|
|
|
if [ $FAILED_CHECKS -eq 0 ]; then
|
|
echo ""
|
|
echo "🎉 All migrations and checks completed successfully!"
|
|
echo "✅ Database is healthy and up-to-date"
|
|
exit 0
|
|
else
|
|
echo ""
|
|
echo "⚠️ Some checks failed"
|
|
echo "💾 Backup available at: $BACKUP_FILE"
|
|
echo "🔧 Please investigate and fix issues"
|
|
exit 1
|
|
fi |