import os import sys import traceback import functools from docker.errors import NotFound as ImageNotFound from sentry_sdk import init, capture_message, configure_scope from . import settings from .utils.container import client from .utils.database import get_enabled_backend from .utils.filesystem import is_empty from .utils.retry import RetryPolicy from .backends.exceptions import NonExistentTemplate, ImportDataError def list_dump_files(): files_in_dir = os.listdir(settings.DUMP_DIR) return filter(lambda x: x.endswith('.sql'), files_in_dir) def indent(string, level=1): spacing = " " * level return spacing + string def remove_recreate_database(template): """ find existing database, remove it, then recreate """ backend = get_enabled_backend().Template try: db = backend(client, template, False) if db.running(): db.stop() db.do_backup() db.remove() except NonExistentTemplate: pass # this means this database is being imported for the first time try: database = backend(client, template, True) except ImageNotFound as e: import sys print("\n### ERROR ###", file=sys.stderr) print(e.explanation.decode(), file=sys.stderr) print("Pull the image and try again.", file=sys.stderr) sys.exit(1) return database def start_template_database(db_name): print(f"- Creating database {db_name}") db = remove_recreate_database(db_name) print(indent("* Starting database...")) db.start() print(indent("* Started")) print(indent("* Waiting for database to accept connections")) try: db.wait_for_service_listening() return db except Exception as e: print(indent( f"* Max time waiting for database exceeded" ", retrying..." )) db.stop() db.restore_backup() print_exception() raise e def main(): dumps = list_dump_files() for dump in dumps: db_name,_ = os.path.splitext(dump) sql_file = os.path.join(settings.DUMP_DIR, dump) if is_empty(sql_file): print(f"- Skipping: {sql_file} is empty") continue start_db_func = functools.partial(start_template_database, db_name) db = RetryPolicy(5, delay=2)(start_db_func) if not db: continue # skip to next database to import print(indent("* Importing data...")) try: db.import_data(sql_file) except (ImportDataError, Exception) as e: with configure_scope() as scope: scope.set_extra("engine_status", db.get_engine_status()) scope.set_tag('database', db_name) capture_message(e) print(indent("* An error happened, debug information:", level=2)) print(db.get_engine_status(), file=sys.stderr) print(indent("* Restoring previous database", level=2)) db.stop() db.restore_backup() finally: db.remove_backup() print(indent("* Stopping database...")) db.stop() print(indent("* Stopped")) if __name__ == "__main__": init(settings.SENTRY_DSN) try: main() except Exception as e: capture_message(e)