#!/usr/bin/env python3 """Read EMEA/APAC TiDB schemas without persisting or printing credentials.""" from __future__ import annotations import getpass import json import ssl import subprocess import sys import urllib.parse from pathlib import Path VENDORED_PYMYSQL = ( Path(__file__).resolve().parents[1] / "aws-lambda-apac-copy" / "emea-source" / "unpacked" / "EMEA-Tenants-Scoring-Task" ) sys.path.insert(0, str(VENDORED_PYMYSQL)) import pymysql # noqa: E402 PROFILE = "552185537300_DBaaS-DevUser-Role" REGION = "us-west-2" SOURCE_FUNCTION = "EMEA-Tenants-Summary-Task" def lambda_environment() -> dict[str, str]: completed = subprocess.run( [ "aws", "lambda", "get-function-configuration", "--profile", PROFILE, "--region", REGION, "--function-name", SOURCE_FUNCTION, "--query", "Environment.Variables", "--output", "json", ], check=True, capture_output=True, text=True, ) return json.loads(completed.stdout) def url_connection(dsn: str): parsed = urllib.parse.urlparse(dsn) if not parsed.hostname or not parsed.path.lstrip("/"): raise RuntimeError("database URL must include a host and database") context = ssl.create_default_context() context.minimum_version = ssl.TLSVersion.TLSv1_2 return pymysql.connect( host=parsed.hostname, port=parsed.port or 4000, user=urllib.parse.unquote(parsed.username or ""), password=urllib.parse.unquote(parsed.password or ""), database=urllib.parse.unquote(parsed.path.lstrip("/")), charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, autocommit=True, ssl=context, connect_timeout=10, read_timeout=30, write_timeout=30, ) def environment_connection(environment: dict[str, str]): dsn = environment.get("TARGET_DATABASE_URL") if dsn: return url_connection(dsn) context = ssl.create_default_context() context.minimum_version = ssl.TLSVersion.TLSv1_2 return pymysql.connect( host=environment["TARGET_DB_HOST"], port=int(environment.get("TARGET_DB_PORT", "4000")), user=environment["TARGET_DB_USER"], password=environment["TARGET_DB_PASSWORD"], database=environment["TARGET_DB_NAME"], charset="utf8mb4", cursorclass=pymysql.cursors.DictCursor, autocommit=True, ssl=context, connect_timeout=10, read_timeout=30, write_timeout=30, ) def database_identity(connection) -> dict[str, str]: with connection.cursor() as cursor: cursor.execute("SELECT DATABASE() AS database_name, VERSION() AS version") return cursor.fetchone() def source_tables(connection) -> list[str]: with connection.cursor() as cursor: cursor.execute( """ SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND (table_name LIKE 'emea\\_%' OR table_name = 'domain_intelligence') ORDER BY table_name """ ) return [row["table_name"] for row in cursor.fetchall()] def destination_tables(connection) -> list[str]: with connection.cursor() as cursor: cursor.execute( """ SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE() AND (table_name LIKE 'apac\\_%' OR table_name = 'domain_intelligence') ORDER BY table_name """ ) return [row["table_name"] for row in cursor.fetchall()] def show_create(connection, table: str) -> str: if not all(character.isalnum() or character == "_" for character in table): raise RuntimeError(f"unsafe table name: {table}") with connection.cursor() as cursor: cursor.execute(f"SHOW CREATE TABLE `{table}`") row = cursor.fetchone() return row["Create Table"] def main() -> None: apac_dsn = getpass.getpass("APAC database URL: ") emea = environment_connection(lambda_environment()) apac = url_connection(apac_dsn) try: print("EMEA_IDENTITY", json.dumps(database_identity(emea), sort_keys=True)) print("APAC_IDENTITY", json.dumps(database_identity(apac), sort_keys=True)) tables = source_tables(emea) print("EMEA_TABLES", json.dumps(tables)) print("APAC_EXISTING_TABLES", json.dumps(destination_tables(apac))) for table in tables: print(f"--- SHOW_CREATE {table} ---") print(show_create(emea, table) + ";") finally: emea.close() apac.close() if __name__ == "__main__": main()