Coverage for mcpgateway/bootstrap_db.py: 83%
22 statements
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-09 11:03 +0100
« prev ^ index » next coverage.py v7.9.2, created at 2025-07-09 11:03 +0100
1# -*- coding: utf-8 -*-
2"""Database bootstrap/upgrade entry-point for MCP Gateway.
4Copyright 2025
5SPDX-License-Identifier: Apache-2.0
6Authors: Madhav Kandukuri
8The script:
101. Creates a synchronous SQLAlchemy ``Engine`` from ``settings.database_url``.
112. Looks for an *alembic.ini* two levels up from this file to drive migrations.
123. If the database is still empty (no ``gateways`` table), it:
13 - builds the base schema with ``Base.metadata.create_all()``
14 - stamps the migration head so Alembic knows it is up-to-date
154. Otherwise, it applies any outstanding Alembic revisions.
165. Logs a **"Database ready"** message on success.
18It is intended to be invoked via ``python -m mcpgateway.bootstrap_db`` or
19directly with ``python mcpgateway/bootstrap_db.py``.
20"""
22# Standard
23import asyncio
24from importlib.resources import files
25import logging
27# Third-Party
28from alembic.config import Config
29from sqlalchemy import create_engine, inspect
31# First-Party
32from alembic import command
33from mcpgateway.config import settings
34from mcpgateway.db import Base
36logger = logging.getLogger(__name__)
39async def main() -> None:
40 """
41 Bootstrap or upgrade the database schema, then log readiness.
43 Runs `create_all()` + `alembic stamp head` on an empty DB, otherwise just
44 executes `alembic upgrade head`, leaving application data intact.
46 Args:
47 None
48 """
49 engine = create_engine(settings.database_url)
50 ini_path = files("mcpgateway").joinpath("alembic.ini")
51 cfg = Config(str(ini_path)) # path in container
52 cfg.attributes["configure_logger"] = False
54 command.ensure_version(cfg)
56 insp = inspect(engine)
57 if "gateways" not in insp.get_table_names(): 57 ↛ 58line 57 didn't jump to line 58 because the condition on line 57 was never true
58 logger.info("Empty DB detected - creating baseline schema")
59 Base.metadata.create_all(engine)
60 command.stamp(cfg, "head") # record baseline
61 else:
62 command.upgrade(cfg, "head") # apply any new revisions
63 logger.info("Database ready")
66if __name__ == "__main__":
67 asyncio.run(main())