← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~ack/maas-site-manager:settings-module into maas-site-manager:main

 

Alberto Donato has proposed merging ~ack/maas-site-manager:settings-module into maas-site-manager:main.

Commit message:
collect global setings for the application in a module.

This allows overriding default values via MSM_-prefixed vars and makes allowed_origins configurable



Requested reviews:
  MAAS Committers (maas-committers)

For more details, see:
https://code.launchpad.net/~ack/maas-site-manager/+git/site-manager/+merge/441473
-- 
Your team MAAS Committers is requested to review the proposed merge of ~ack/maas-site-manager:settings-module into maas-site-manager:main.
diff --git a/backend/README.md b/backend/README.md
index 5642c59..dd6dd0a 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -130,5 +130,5 @@ There are CSV files available that can be used as test data.
 
 If you are running the app in docker you can easily load those
 
-- go to the test data directory `cd ../testdata`
-- run the loading script `./import.sh`
+- export the `POSTGRES_*` environment vars as needed
+- run the loading script `../testdata/import.sh`
diff --git a/backend/msm/schema/_pagination.py b/backend/msm/schema/_pagination.py
index c6b2bb4..7225425 100644
--- a/backend/msm/schema/_pagination.py
+++ b/backend/msm/schema/_pagination.py
@@ -7,6 +7,8 @@ from pydantic import (
     Field,
 )
 
+from ..settings import SETTINGS
+
 DEFAULT_PAGE_SIZE = 20
 MAX_PAGE_SIZE = 100
 
@@ -33,7 +35,9 @@ class PaginationParams(NamedTuple):
 
 async def pagination_params(
     page: int = Query(default=1, gte=1),
-    size: int = Query(default=DEFAULT_PAGE_SIZE, lte=MAX_PAGE_SIZE, gte=1),
+    size: int = Query(
+        default=SETTINGS.default_page_size, lte=SETTINGS.max_page_size, gte=1
+    ),
 ) -> PaginationParams:
     """Return pagination parameters."""
     return PaginationParams(page=page, size=size, offset=(page - 1) * size)
diff --git a/backend/msm/settings.py b/backend/msm/settings.py
new file mode 100644
index 0000000..680fcf3
--- /dev/null
+++ b/backend/msm/settings.py
@@ -0,0 +1,32 @@
+from pydantic import (
+    BaseSettings,
+    Field,
+    PostgresDsn,
+)
+
+
+class Settings(BaseSettings):
+    """API settings."""
+
+    db_dsn: PostgresDsn = Field(
+        default="postgresql+asyncpg://postgres:msm@localhost/msm",
+        env="MSM_DB_DSN",
+    )  # type: ignore
+
+    default_page_size: int = Field(
+        default=20, gte=1, env="MSM_DEFAULT_PAGE_SIZE"
+    )
+
+    max_page_size: int = Field(default=100, gte=1, env="MSM_MAX_PAGE_SIZE")
+
+    allowed_origins: list[str] = Field(
+        default=[
+            "http://localhost:8405";,
+            "http://127.0.0.1:8405";,
+            "http://[::1]:8405";,
+        ],
+        env="MSM_ALLOWED_ORIGINS",
+    )
+
+
+SETTINGS = Settings()
diff --git a/backend/msm/user_api/_setup.py b/backend/msm/user_api/_setup.py
index 03b9d18..29d8437 100644
--- a/backend/msm/user_api/_setup.py
+++ b/backend/msm/user_api/_setup.py
@@ -1,5 +1,4 @@
 from contextlib import asynccontextmanager
-from os import environ
 from typing import AsyncGenerator
 
 from fastapi import FastAPI
@@ -8,25 +7,14 @@ from fastapi.middleware.cors import CORSMiddleware
 from . import _base
 from .. import PACKAGE
 from ..db import Database
+from ..settings import SETTINGS
 
-POSTGRES_HOST = environ.get("POSTGRES_HOST")
-POSTGRES_PORT = environ.get("POSTGRES_PORT")
-POSTGRES_DB = environ.get("POSTGRES_DB")
-POSTGRES_USER = environ.get("POSTGRES_USER")
-POSTGRES_PASSWORD = environ.get("POSTGRES_PASSWORD")
-DEFAULT_DB_DSN = (
-    "postgresql+asyncpg://"
-    + f"{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}/{POSTGRES_DB}"
-)
 
-# TODO: make config dynamic and allow env vars
-origins = [
-    "http://localhost:8405";,
-    "http://127.0.0.1:8405";,
-]
+def create_app(db_dsn: str | None = None) -> FastAPI:
+    """Create the FastAPI WSGI application."""
+    if db_dsn is None:
+        db_dsn = str(SETTINGS.db_dsn)
 
-
-def create_app(db_dsn: str = DEFAULT_DB_DSN) -> FastAPI:
     @asynccontextmanager
     async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
         await db.connect()
@@ -42,7 +30,7 @@ def create_app(db_dsn: str = DEFAULT_DB_DSN) -> FastAPI:
     )
     app.add_middleware(
         CORSMiddleware,
-        allow_origins=origins,
+        allow_origins=SETTINGS.allowed_origins,
         allow_credentials=True,
         allow_methods=["*"],
         allow_headers=["*"],
diff --git a/backend/tox.ini b/backend/tox.ini
index 6157881..83f9d8a 100644
--- a/backend/tox.ini
+++ b/backend/tox.ini
@@ -7,11 +7,7 @@ no_package = true
 
 [testenv]
 pass_env =
-    POSTGRES_DB
-    POSTGRES_HOST
-    POSTGRES_PASSWORD
-    POSTGRES_PORT
-    POSTGRES_USER
+    MSM_*
 
 [testenv:test]
 deps =
diff --git a/docker-compose.env b/docker-compose.env
index c59d0d9..cef13c5 100644
--- a/docker-compose.env
+++ b/docker-compose.env
@@ -9,3 +9,6 @@ POSTGRES_PORT=5432
 POSTGRES_DB="postgres"  # default for postgres docker image
 POSTGRES_USER="postgres"  # default for postgres docker image
 POSTGRES_PASSWORD="msm"  # default for postgres docker image
+
+# for site manager itself
+MSM_DB_DSN="postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@{$POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}"

Follow ups