| Server IP : 3.147.158.171 / Your IP : 216.73.216.229 Web Server : Apache/2.4.67 (Amazon Linux) OpenSSL/3.5.5 System : Linux ip-172-31-2-178.us-east-2.compute.internal 6.1.172-216.329.amzn2023.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 20 06:31:34 UTC 2026 x86_64 User : ec2-user ( 1000) PHP Version : 8.4.21 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /tsai/repo/builder/backend/scripts/ |
Upload File : |
import os
import sys
import argparse
from dotenv import load_dotenv, find_dotenv
import subprocess
from datetime import datetime
import shutil
import gzip
if not find_dotenv():
print("Error: .env file not found.")
sys.exit(1)
load_dotenv()
MYSQL_HOST = os.getenv('MYSQL_HOST')
MYSQL_USER = os.getenv('MYSQL_USER')
MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD')
BACKUP_DIR = os.getenv('BACKUP_DIR')
# Check if any required environment variable is missing
missing = [name for name, var in [
('MYSQL_HOST', MYSQL_HOST),
('MYSQL_USER', MYSQL_USER),
('MYSQL_PASSWORD', MYSQL_PASSWORD),
('BACKUP_DIR', BACKUP_DIR)
] if var is None]
if missing:
print(f"Error: Missing environment variables: {', '.join(missing)}")
sys.exit(1)
# Type assertions for type checkers (we've validated these are not None above)
assert MYSQL_HOST is not None
assert MYSQL_USER is not None
assert MYSQL_PASSWORD is not None
assert BACKUP_DIR is not None
databases_env = os.getenv('DATABASES')
if not databases_env:
print("Error: No default databases specified in .env file.")
sys.exit(1)
DEFAULT_DATABASES = [db.strip() for db in databases_env.split(',')]
def backup_database(database, backup_dir):
timestamp = datetime.now().strftime('%Y-%m-%d_%H%M%S')
# Sanitize database name for filename (remove path separators and special chars)
safe_db_name = database.replace('/', '_').replace('\\', '_').replace(' ', '_')
backup_file = os.path.join(backup_dir, f"{safe_db_name}_{timestamp}.sql.gz")
# Use MYSQL_PWD environment variable for security (password not visible in process list)
env = os.environ.copy()
env['MYSQL_PWD'] = MYSQL_PASSWORD
dump_command = [
'mysqldump',
'--skip-comments',
f'--host={MYSQL_HOST}',
f'--user={MYSQL_USER}',
database
]
try:
# Run mysqldump and capture output (binary mode to handle non-UTF-8 data)
result = subprocess.run(dump_command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, check=True, env=env)
# Write compressed output
with gzip.open(backup_file, 'wb') as f:
f.write(result.stdout)
# Verify backup success (check file isn't empty)
file_size = os.path.getsize(backup_file)
if file_size > 0:
# Convert to KB or MB for readable output
size_kb = file_size / 1024
if size_kb > 1024:
size_str = f"{size_kb / 1024:.2f} MB"
else:
size_str = f"{size_kb:.2f} KB"
print(f"Backup of {database} completed successfully ({size_str})")
return True
else:
print(f"Warning: Backup of {database} resulted in empty file")
return False
except subprocess.CalledProcessError as e:
print(f"Error backing up {database}: {e}")
if e.stderr:
print(f"mysqldump error output: {e.stderr.decode() if isinstance(e.stderr, bytes) else e.stderr}")
return False
except Exception as e:
print(f"Unexpected error backing up {database}: {e}")
return False
def main():
parser = argparse.ArgumentParser(
description='Backup MySQL databases to compressed SQL files.',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Backup default databases (from .env DATABASES list)
python db_back.py
# Backup specific database(s)
python db_back.py database_name
python db_back.py db1 db2 db3
# Backup to a custom directory
python db_back.py --backup-dir /path/to/backups
# Backup specific databases to a custom directory
python db_back.py --backup-dir /path/to/backups db1 db2
""")
parser.add_argument('databases', nargs='*',
help='Databases to backup (uses DATABASES env var if not specified)')
parser.add_argument('--backup-dir', type=str,
help='Override backup directory from .env')
args = parser.parse_args()
# Check if mysqldump is available
if not shutil.which('mysqldump'):
print("Error: mysqldump command not found in PATH")
sys.exit(1)
# Use command-line backup dir if provided, otherwise use env var
backup_dir = args.backup_dir if args.backup_dir else BACKUP_DIR
# Ensure backup directory exists
os.makedirs(backup_dir, exist_ok=True)
# Use command-line databases if provided, otherwise use defaults from env
databases = args.databases if args.databases else DEFAULT_DATABASES
# Track backup statistics
success_count = 0
failed_count = 0
for db in databases:
if backup_database(db, backup_dir):
success_count += 1
else:
failed_count += 1
# Print summary report
print("\n" + "=" * 50)
print("Backup Summary Report")
print("=" * 50)
print(f"Total databases: {len(databases)}")
print(f"Successful: {success_count}")
print(f"Failed: {failed_count}")
print(f"Backup directory: {backup_dir}")
print("=" * 50)
if __name__ == "__main__":
main()