Production-grade PostgreSQL database migration tool for AWS RDS with DataDog monitoring
Project description
RDS Migration Library
A production-grade Python library for migrating AWS RDS PostgreSQL databases with comprehensive support for materialized views, connection management, validation, and DataDog monitoring.
Features
- Database Migration: Dump and restore PostgreSQL databases using
pg_dumpandpg_restore - Materialized Views: Automatic detection, dependency resolution, and concurrent refresh
- Connection Management: Pre-flight testing, active connection termination, role password rotation
- Validation: Comprehensive pre/post-migration validation with statistics comparison
- Statistics Collection: Database and table-level metrics (row counts, sizes, indexes, functions, sequences, triggers)
- DataDog Integration: All operations send metrics and traces to DataDog
- Type-Safe: Full type hints throughout the codebase
- OOP Design: Modular classes that can be used independently or composed
Installation
# Install dependencies
poetry install
# Or using pip
pip install -r requirements.txt
Quick Start
CLI Usage
# Migrate all databases in staging
rds-migrate migrate --environment staging
# Migrate specific database
rds-migrate migrate -e staging --database mydb
# Dry run (see what would be done)
rds-migrate migrate -e staging --dry-run
# Pre-migration validation
rds-migrate validate -e staging
# Get database statistics
rds-migrate stats -e staging -d mydb --tables
# List materialized views
rds-migrate list-views -e staging -d mydb
# Refresh materialized views
rds-migrate refresh-views -e staging -d mydb
Library Usage
from rds_migration import (
MigrationConfig,
DatabaseMigrator,
ConnectionManager,
DatabaseValidator,
Database,
RDSConfig,
)
# Initialize configuration
config = MigrationConfig.for_environment("staging")
# Full migration with all features
migrator = DatabaseMigrator(config)
results = migrator.migrate_all()
# Or use individual components
from rds_migration.datadog import DataDogMonitor
# Connection management only
monitor = DataDogMonitor(enabled=True, environment="staging")
rds_config = RDSConfig(
rds_id="db-XXX",
endpoint="mydb.us-east-1.rds.amazonaws.com",
password="secret",
)
db = Database(rds_config, monitor)
conn_manager = ConnectionManager(db, monitor)
# Test connection
if conn_manager.test_connection():
print("Connection successful!")
# Get connection statistics
stats = conn_manager.get_connection_stats("mydb")
print(f"Active: {stats['active']}, Idle: {stats['idle']}")
# Terminate connections for a role
terminated = conn_manager.terminate_connections("mydb", role_name="app_user")
print(f"Terminated {terminated} connections")
# Validation only
validator = DatabaseValidator(db, monitor)
db_stats = validator.get_database_stats("mydb")
validator.print_stats_table(db_stats)
# Compare source and destination
source_stats = validator.get_database_stats("mydb")
dest_stats = validator.get_database_stats("mydb")
is_valid, messages = validator.validate_migration("mydb", source_stats, dest_stats)
CLI Commands
migrate
Migrate databases from source to destination RDS instance.
Options:
--environment, -e: Target environment (staging/production)--database, -d: Specific database to migrate (optional)--dry-run: Show what would be done without executing--no-refresh-views: Skip materialized view refresh--work-dir: Directory for SQL dumps (default: ./sql)--log-level: Logging level (DEBUG/INFO/WARNING/ERROR)--datadog-host: DataDog StatsD host--datadog-port: DataDog StatsD port--no-datadog: Disable DataDog monitoring
Examples:
# Migrate all staging databases
rds-migrate migrate --environment staging
# Migrate specific database in production
rds-migrate migrate --environment production --database fulfillment_engine
# Dry run with debug logging
rds-migrate migrate -e staging --dry-run --log-level DEBUG
validate
Validate databases by comparing source and destination statistics without performing migration.
Options:
--environment, -e: Target environment (staging/production)--database, -d: Specific database to validate (optional)--log-level: Logging level--datadog-host: DataDog StatsD host--datadog-port: DataDog StatsD port--no-datadog: Disable DataDog monitoring
Examples:
# Validate all databases
rds-migrate validate --environment staging
# Validate specific database
rds-migrate validate -e staging -d mydb
Validation Checks:
- Table count matching
- Row count matching (allows 5% variance)
- View and materialized view counts
- Function, sequence, and trigger counts
- Database size comparison
stats
Get comprehensive database statistics including table counts, row counts, functions, sequences, triggers, and size.
Options:
--environment, -e: Target environment--database, -d: Database name (required)--source: Get stats from source database (default: destination)--tables: Include table-level statistics--log-level: Logging level--datadog-host: DataDog StatsD host--datadog-port: DataDog StatsD port--no-datadog: Disable DataDog monitoring
Examples:
# Get destination database statistics
rds-migrate stats -e staging -d mydb
# Get source database statistics with table details
rds-migrate stats -e staging -d mydb --source --tables
list-views
List all materialized views in a database with their properties.
Options:
--environment, -e: Target environment--database, -d: Database name (required)--datadog-host: DataDog StatsD host--datadog-port: DataDog StatsD port--no-datadog: Disable DataDog monitoring
Example:
rds-migrate list-views -e staging -d fulfillment_engine
refresh-views
Refresh materialized views in a database with dependency resolution.
Options:
--environment, -e: Target environment--database, -d: Database name (required)--view, -v: Specific view to refresh (optional)--concurrent: Use REFRESH MATERIALIZED VIEW CONCURRENTLY
Examples:
# Refresh all views
rds-migrate refresh-views -e staging -d fulfillment_engine
# Refresh specific view
rds-migrate refresh-views -e staging -d fulfillment_engine -v my_view
# Concurrent refresh (requires unique index)
rds-migrate refresh-views -e staging -d fulfillment_engine --concurrent
Library Architecture
Core Components
DatabaseMigrator
Main orchestrator that coordinates the entire migration process.
from rds_migration import MigrationConfig, DatabaseMigrator
config = MigrationConfig.for_environment("staging")
migrator = DatabaseMigrator(config, enable_datadog=True)
# Test connections before migration
if migrator.test_connections():
# Validate databases
results = migrator.validate_databases()
# Perform migration
results = migrator.migrate_all()
ConnectionManager
Manages database connections, termination, and role password rotation.
from rds_migration import ConnectionManager, Database, RDSConfig
db = Database(RDSConfig(...))
conn_manager = ConnectionManager(db)
# Test connection
conn_manager.test_connection()
# Get active connections
connections = conn_manager.get_active_connections("mydb", role_name="app_user")
# Terminate connections
count = conn_manager.terminate_connections("mydb", role_name="app_user", wait_seconds=10)
# Rotate password and terminate
success, count = conn_manager.terminate_and_rotate("mydb", "app_user")
# Get connection statistics
stats = conn_manager.get_connection_stats("mydb")
DatabaseValidator
Collects statistics and validates migrations.
from rds_migration import DatabaseValidator, Database
validator = DatabaseValidator(Database(...))
# Get database statistics
stats = validator.get_database_stats("mydb")
print(f"Tables: {stats.table_count}, Rows: {stats.total_row_count}")
# Get table-level statistics
table_stats = validator.get_table_stats("mydb")
for ts in table_stats:
print(f"{ts.table_name}: {ts.row_count} rows")
# Validate migration
is_valid, messages = validator.validate_migration("mydb", source_stats, dest_stats)
# Print formatted tables
validator.print_stats_table(stats)
validator.print_comparison_table("mydb", source_stats, dest_stats)
MaterializedViewManager
Manages materialized view detection, dependency resolution, and refresh.
from rds_migration import MaterializedViewManager, Database
view_manager = MaterializedViewManager(Database(...))
# List views
views = view_manager.list_materialized_views("mydb")
# Check if refresh is needed
if view_manager.should_refresh_views("mydb"):
# Refresh all views with dependency resolution
results = view_manager.refresh_all_views("mydb", concurrent=False)
# Refresh specific view
success, rows, duration = view_manager.refresh_materialized_view("mydb", "my_view")
Configuration
Configuration is managed through the MigrationConfig class with environment-specific presets.
from rds_migration.config import MigrationConfig, Environment
# Use environment preset
config = MigrationConfig.for_environment(Environment.STAGING)
# Or create custom configuration
config = MigrationConfig(
environment=Environment.STAGING,
source_rds_id="db-XXX",
destination_rds_id="db-YYY",
source_env="staging",
destination_env="staging-v2",
excluded_databases=["rdsadmin", "template0"],
refresh_materialized_views=True,
work_dir="./sql",
dry_run=False,
)
DataDog Monitoring
All operations send metrics and traces to DataDog under the service name databaseMigrationLibrary.
Metrics
Database Operations:
database.connection.duration.seconds- Connection establishment timedatabase.query.duration.seconds- Query execution timedatabase.command.duration.seconds- Command execution timedatabase.dump.duration.seconds- pg_dump durationdatabase.dump.size.bytes- Dump file sizedatabase.restore.duration.seconds- pg_restore durationdatabase.vacuum.duration.seconds- VACUUM ANALYZE duration
Connection Management:
connections.active- Active connectionsconnections.idle- Idle connectionsconnections.idle_in_transaction- Idle in transactionconnections.total- Total connectionsconnections.terminated- Terminated connections
Validation:
validation.completed- Validation runs (tagged with status)validation.errors- Number of validation errorsvalidation.warnings- Number of validation warningsdatabase.table_count- Number of tablesdatabase.view_count- Number of viewsdatabase.total_row_count- Total row countdatabase.size_bytes- Database size
Migration:
migration.started- Migration initiatedmigration.completed- Successful migrationmigration.failed- Failed migrationmigration.duration.seconds- Total migration time
Materialized Views:
materialized_views.total- Total views in databasematerialized_views.refresh.started- Refresh initiatedmaterialized_views.refresh.completed- Successful refreshmaterialized_views.refresh.failed- Failed refreshmaterialized_views.refresh.duration.seconds- Refresh durationmaterialized_views.refresh.rows- Rows in refreshed view
Traces
Distributed traces are created for:
database.connect- Database connectionsdatabase.query- Query executiondatabase.command- Command executiondatabase.dump- pg_dump operationsdatabase.restore- pg_restore operationsdatabase.vacuum_analyze- VACUUM ANALYZEconnections.terminate- Connection terminationmaterialized_views.refresh- View refresh
Tags
All metrics and traces include relevant tags:
environment: Environment name (staging, production)database: Database namesource: Source environment/RDSdestination: Destination environment/RDSstatus: Operation status (success, failure, error)role: Role name (for connection operations)view: View name (for materialized view operations)
Environment Variables
# AWS Configuration
AWS_PROFILE=staging
AWS_REGION=us-east-1
# DataDog Configuration (optional)
DD_AGENT_HOST=localhost
DD_AGENT_PORT=8125
Configuration Files
Excluded Databases
By default, the following databases are excluded from migration:
postgres(system database)rdsadmin(AWS RDS management)template0(PostgreSQL template)template1(PostgreSQL template)
SSM Parameter Store
Passwords are retrieved from AWS SSM Parameter Store using the pattern:
/${environment}/applications/wms/rds/BU_SHARED_PG_PASSWORD
For example:
- Staging:
/staging/applications/wms/rds/BU_SHARED_PG_PASSWORD - Production:
/production/applications/wms/rds/BU_SHARED_PG_PASSWORD
Development
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=rds_migration
# Run specific test file
pytest tests/test_migration.py
Code Quality
# Type checking
mypy rds_migration/
# Linting
ruff check rds_migration/
# Formatting
black rds_migration/
Comparison to Bash Script
This Python library matches and exceeds the capabilities of the original bash script:
| Feature | Bash Script | Python Library |
|---|---|---|
| Database Migration | ✅ | ✅ |
| Materialized Views | ✅ | ✅ (with dependency resolution) |
| Connection Management | ✅ | ✅ |
| Validation Mode | ✅ | ✅ |
| Statistics Collection | ✅ | ✅ (enhanced) |
| Role Management | ✅ | ✅ |
| DataDog Monitoring | ❌ | ✅ |
| Type Safety | ❌ | ✅ |
| Modular Design | ❌ | ✅ |
| Library Usage | ❌ | ✅ |
| CLI Commands | Basic | Rich with multiple commands |
| Error Handling | Basic | Comprehensive |
| Logging | Echo statements | Structured logging |
| Testing | Manual | Automated tests |
Key Advantages
- Modularity: Individual components can be used independently
- Type Safety: Full type hints for better IDE support and fewer bugs
- DataDog Integration: Comprehensive metrics and tracing
- Better Error Handling: Structured exceptions with detailed context
- Rich Output: Beautiful terminal tables using Rich library
- Dry Run Support: See what would happen without executing
- Flexible Configuration: Environment-specific presets with override support
- Library + CLI: Can be used as both a library and command-line tool
Troubleshooting
Connection Issues
# Test connections before migration
rds-migrate validate -e staging
# Check connection statistics
rds-migrate stats -e staging -d mydb
Materialized View Dependencies
If materialized view refresh fails due to dependencies:
# List all views to see dependencies
rds-migrate list-views -e staging -d mydb
# Refresh views one at a time
rds-migrate refresh-views -e staging -d mydb -v view1
Validation Failures
# Compare source and destination statistics
rds-migrate stats -e staging -d mydb --source
rds-migrate stats -e staging -d mydb
# Run validation to see detailed differences
rds-migrate validate -e staging -d mydb
License
Internal FreshRealm tool - Not for external distribution
Author
Architected and Coded by Arthur Mandel (arthur.mandel@external.freshrealm.com)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file rds_migration_toolkit-1.0.tar.gz.
File metadata
- Download URL: rds_migration_toolkit-1.0.tar.gz
- Upload date:
- Size: 40.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a96e3b65599c65085247a1777df3632de96f17b16744071fbf5df8df9419af9
|
|
| MD5 |
8170ef84e420003974ecf0f91f63ff47
|
|
| BLAKE2b-256 |
2ea790c1bb08c3e05d23904d56a007b683ba6f08d1f4ea82214dfda0b4448732
|
Provenance
The following attestation bundles were made for rds_migration_toolkit-1.0.tar.gz:
Publisher:
publish-to-pypi.yml on arthur-mandel-freshRealm/openSourceTools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rds_migration_toolkit-1.0.tar.gz -
Subject digest:
8a96e3b65599c65085247a1777df3632de96f17b16744071fbf5df8df9419af9 - Sigstore transparency entry: 669640068
- Sigstore integration time:
-
Permalink:
arthur-mandel-freshRealm/openSourceTools@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/arthur-mandel-freshRealm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file rds_migration_toolkit-1.0.0-py3-none-any.whl.
File metadata
- Download URL: rds_migration_toolkit-1.0.0-py3-none-any.whl
- Upload date:
- Size: 44.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
05122a19bb9d5699e49dc37be523c01c4228c26a71d4e7e497e29889f54d58a2
|
|
| MD5 |
90fb88129f465bed99f40ea65a536de1
|
|
| BLAKE2b-256 |
fcd9b98c1228b9c27d15a6c5afda60f4ad24af517c08dae0b29539694cfafa3d
|
Provenance
The following attestation bundles were made for rds_migration_toolkit-1.0.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on arthur-mandel-freshRealm/openSourceTools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rds_migration_toolkit-1.0.0-py3-none-any.whl -
Subject digest:
05122a19bb9d5699e49dc37be523c01c4228c26a71d4e7e497e29889f54d58a2 - Sigstore transparency entry: 669645020
- Sigstore integration time:
-
Permalink:
arthur-mandel-freshRealm/openSourceTools@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/arthur-mandel-freshRealm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file rds_migration_toolkit-1.0-py3-none-any.whl.
File metadata
- Download URL: rds_migration_toolkit-1.0-py3-none-any.whl
- Upload date:
- Size: 44.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
22e0c108168ddf2c6e5f7569bf5eabfcd60f693b1ec11074e01edccbc3b9fdf6
|
|
| MD5 |
8abbc2e6594ba949f92bee886aad445b
|
|
| BLAKE2b-256 |
996f568445cbd25b885c747f94591669bb4eb01b939068845b7e266b4cf064d9
|
Provenance
The following attestation bundles were made for rds_migration_toolkit-1.0-py3-none-any.whl:
Publisher:
publish-to-pypi.yml on arthur-mandel-freshRealm/openSourceTools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
rds_migration_toolkit-1.0-py3-none-any.whl -
Subject digest:
22e0c108168ddf2c6e5f7569bf5eabfcd60f693b1ec11074e01edccbc3b9fdf6 - Sigstore transparency entry: 669640082
- Sigstore integration time:
-
Permalink:
arthur-mandel-freshRealm/openSourceTools@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/arthur-mandel-freshRealm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@bafa3d32df9639de191d1b6905bfcf271d8fc9b0 -
Trigger Event:
workflow_dispatch
-
Statement type: