MorphGuard / scripts /migrate_users.py
juanquy's picture
Initial clean commit of modular MorphGuard
2978bba
Raw
History Blame Contribute Delete
4.5 kB
#!/usr/bin/env python3
"""
migrate_users.py
Migrates users from SQLite (users.db) to PostgreSQL (TimescaleDB).
SAFE operation: Reads from SQLite, Inserts into Postgres. Does not delete SQLite data.
"""
import sqlite3
import psycopg2
import os
import sys
import logging
from datetime import datetime
# Set up logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Paths
SQLITE_DB_PATH = 'users.db'
# Configuration (mirrors setup_timescaledb.py logic)
def get_postgres_connection():
try:
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
try:
import config
host = getattr(config, 'DB_HOST', 'localhost')
port = getattr(config, 'DB_PORT', 5432)
dbname = getattr(config, 'DB_NAME', 'morphguard')
user = getattr(config, 'DB_USER', 'morphguard')
password = getattr(config, 'DB_PASSWORD', 'morphguard')
except ImportError:
# Fallback to env vars or strict defaults matching deploy scripts
host = os.environ.get('MORPHGUARD_DB_HOST', 'localhost')
port = int(os.environ.get('MORPHGUARD_DB_PORT', 5432))
dbname = os.environ.get('MORPHGUARD_DB_NAME', 'morphguard')
user = os.environ.get('MORPHGUARD_DB_USER', 'morphguard')
password = os.environ.get('MORPHGUARD_DB_PASS', 'morphguard')
logger.info(f"Connecting to Postgres at {host}:{port} db={dbname} user={user}...")
conn = psycopg2.connect(
host=host, port=port, dbname=dbname, user=user, password=password
)
return conn
except Exception as e:
logger.error(f"Failed to connect to Postgres: {e}")
return None
def migrate():
if not os.path.exists(SQLITE_DB_PATH):
logger.error(f"SQLite database not found at {SQLITE_DB_PATH}")
return
# Connect to SQLite
try:
sqlite_conn = sqlite3.connect(SQLITE_DB_PATH)
sqlite_conn.row_factory = sqlite3.Row
sqlite_cur = sqlite_conn.cursor()
logger.info("Connected to SQLite")
except Exception as e:
logger.error(f"Failed to connect to SQLite: {e}")
return
# Connect to Postgres
pg_conn = get_postgres_connection()
if not pg_conn:
return
pg_cur = pg_conn.cursor()
try:
# Fetch all users from SQLite
sqlite_cur.execute("SELECT * FROM users")
users = sqlite_cur.fetchall()
logger.info(f"Found {len(users)} users in SQLite database.")
count = 0
for user in users:
# Map fields
# SQLite: id, username, password_hash, role, email, created_at (REAL), last_login (REAL), active (INT)
# Postgres: id (SERIAL), username, password_hash, role, email, created_at (TIMESTAMPTZ), last_login (TIMESTAMPTZ), active (BOOL)
username = user['username']
# Check if user exists in Postgres
pg_cur.execute("SELECT id FROM users WHERE username = %s", (username,))
if pg_cur.fetchone():
logger.info(f"Skipping existing user: {username}")
continue
password_hash = user['password_hash']
role = user['role']
email = user['email'] if 'email' in user.keys() else None
# Handle timestamps (SQLite stores as float timestamp)
created_at_ts = user['created_at']
last_login_ts = user['last_login']
created_at = datetime.fromtimestamp(created_at_ts) if created_at_ts else datetime.now()
last_login = datetime.fromtimestamp(last_login_ts) if last_login_ts else None
active = bool(user['active'])
# Insert into Postgres
pg_cur.execute("""
INSERT INTO users (username, password_hash, role, email, created_at, last_login, active)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (username, password_hash, role, email, created_at, last_login, active))
count += 1
pg_conn.commit()
logger.info(f"Successfully migrated {count} users.")
except Exception as e:
pg_conn.rollback()
logger.error(f"Migration failed: {e}")
finally:
sqlite_conn.close()
pg_conn.close()
if __name__ == "__main__":
migrate()