Update server config, SSL handling, and port mapping logic

Refactored `run_server` to accept explicit config and SSL paths. Added dynamic environment-based config loading and stricter SSL path checks for production. Updated `docker-compose.yml` to use environment variable for port mapping and adjusted `config_prod.json` to reflect correct port usage.
This commit is contained in:
GotthardG
2025-04-11 12:37:18 +02:00
parent afa473e8a8
commit 86d03285e4
3 changed files with 49 additions and 26 deletions

View File

@ -1,10 +1,10 @@
{ {
"ssl_cert_path": "/app/backend/ssl/mx-aare-test.psi.ch.pem", "ssl_cert_path": "/app/backend/ssl/mx-aare-test.psi.ch.pem",
"ssl_key_path": "/app/backend/ssl/mx-aare-test.psi.ch.key", "ssl_key_path": "/app/backend/ssl/mx-aare-test.psi.ch.key",
"OPENAPI_URL": "https://backend:8000/openapi.json", "PORT": 1492,
"OPENAPI_URL": "https://backend:1492/openapi.json",
"SCHEMA_PATH": "/app/src/openapi.json", "SCHEMA_PATH": "/app/src/openapi.json",
"OUTPUT_DIRECTORY": "/app/openapi", "OUTPUT_DIRECTORY": "/app/openapi",
"PORT": 8000,
"SSL_KEY_PATH": "/app/backend/ssl/mx-aare-test.psi.ch.key", "SSL_KEY_PATH": "/app/backend/ssl/mx-aare-test.psi.ch.key",
"SSL_CERT_PATH": "/app/backend/ssl/mx-aare-test.psi.ch.pem" "SSL_CERT_PATH": "/app/backend/ssl/mx-aare-test.psi.ch.pem"
} }

View File

@ -50,21 +50,26 @@ def get_project_metadata():
) )
def run_server(): def run_server(config, cert_path, key_path):
import uvicorn import uvicorn
environment = os.getenv(
"ENVIRONMENT", "dev"
) # needs to be set explicitly here if not globally available
print(f"[INFO] Starting server in {environment} environment...") print(f"[INFO] Starting server in {environment} environment...")
print(f"[INFO] SSL Certificate Path: {cert_path}") print(f"[INFO] SSL Certificate Path: {cert_path}")
print(f"[INFO] SSL Key Path: {key_path}") print(f"[INFO] SSL Key Path: {key_path}")
port = config.get("PORT", os.getenv("PORT")) port = config.get("PORT")
if not port: if not port:
print("[ERROR] No port defined in config or environment variables. Aborting!") print("[ERROR] No port defined in config or environment variables. Aborting!")
sys.exit(1) # Exit if no port is defined sys.exit(1) # Exit if no port is defined
port = int(port) port = int(port)
print(f"[INFO] Running on port {port}") print(f"[INFO] Running on port {port}")
uvicorn.run( uvicorn.run(
app, app,
host="0.0.0.0" if environment in ["dev", "test"] else "0.0.0.0", host="0.0.0.0",
port=port, port=port,
log_level="debug", log_level="debug",
ssl_keyfile=key_path, ssl_keyfile=key_path,
@ -214,6 +219,9 @@ if __name__ == "__main__":
# Load environment variables from .env file # Load environment variables from .env file
load_dotenv() load_dotenv()
environment = os.getenv("ENVIRONMENT", "dev")
config_file = Path(__file__).resolve().parent / f"config_{environment}.json"
# Check if `generate-openapi` option is passed # Check if `generate-openapi` option is passed
if len(sys.argv) > 1 and sys.argv[1] == "generate-openapi": if len(sys.argv) > 1 and sys.argv[1] == "generate-openapi":
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
@ -230,28 +238,42 @@ if __name__ == "__main__":
print("openapi.json generated successfully.") print("openapi.json generated successfully.")
sys.exit(0) # Exit after generating the file sys.exit(0) # Exit after generating the file
# Default behavior: Run the server based on the environment # Explicitly load the configuration file
environment = os.getenv("ENVIRONMENT", "dev") with open(config_file, "r") as f:
port = int(os.getenv("PORT", 8000)) config = json.load(f)
# Explicitly obtain SSL paths from config
if environment in ["test", "dev"]:
cert_path = config.get("ssl_cert_path", "ssl/cert.pem")
key_path = config.get("ssl_key_path", "ssl/key.pem")
elif environment == "prod":
cert_path = config.get("SSL_CERT_PATH")
key_path = config.get("SSL_KEY_PATH")
if not cert_path or not key_path:
raise ValueError(
"SSL_CERT_PATH and SSL_KEY_PATH must be explicitly"
"set in config_prod.json for production."
)
else:
raise ValueError(f"Unknown environment: {environment}")
is_ci = os.getenv("CI", "false").lower() == "true" is_ci = os.getenv("CI", "false").lower() == "true"
# Handle certificates for dev/test if not available
ssl_dir = Path(cert_path).parent
ssl_dir.mkdir(parents=True, exist_ok=True)
if environment in ["dev", "test"] and (
not Path(cert_path).exists() or not Path(key_path).exists()
):
print(f"[INFO] Generating SSL certificates at {ssl_dir}")
ssl_heidi.generate_self_signed_cert(cert_path, key_path)
if is_ci or environment == "test": if is_ci or environment == "test":
# Test or CI Mode: Run server process temporarily for test validation server_process = Process(target=run_server, args=(config, cert_path, key_path))
ssl_dir = Path(cert_path).parent
ssl_dir.mkdir(parents=True, exist_ok=True)
# Generate self-signed certs if missing
if not Path(cert_path).exists() or not Path(key_path).exists():
print(f"[INFO] Generating self-signed SSL certificates at {ssl_dir}")
ssl_heidi.generate_self_signed_cert(cert_path, key_path)
# Start the server as a subprocess, wait, then terminate
server_process = Process(target=run_server)
server_process.start() server_process.start()
sleep(5) # Wait for 5 seconds to verify the server is running sleep(5)
server_process.terminate() # Terminate the server process (for CI) server_process.terminate()
server_process.join() # Ensure proper cleanup server_process.join()
print("CI: Server started and terminated successfully for test validation.") print("CI/Test environment: Server started and terminated successfully.")
else: else:
# Dev or Prod: Start the server as usual run_server(config, cert_path, key_path)
run_server()

View File

@ -7,7 +7,7 @@ services:
dockerfile: backend/Dockerfile dockerfile: backend/Dockerfile
ports: ports:
- "8000:8000" # Map container port 8000 to host - "${PORT}:${PORT}" # Map container port 8000 to host
volumes: volumes:
- ./backend:/app/backend # Map backend directory to /app/backend - ./backend:/app/backend # Map backend directory to /app/backend
- ./app:/app/app # Map app directory to /app/app - ./app:/app/app # Map app directory to /app/app
@ -28,6 +28,7 @@ services:
DB_PASSWORD: ${DB_PASSWORD} DB_PASSWORD: ${DB_PASSWORD}
DB_HOST: postgres DB_HOST: postgres
DB_NAME: ${DB_NAME} DB_NAME: ${DB_NAME}
PORT: ${PORT}
postgres: # ⬅️ New service (our PostgreSQL database) postgres: # ⬅️ New service (our PostgreSQL database)
image: postgres:16 image: postgres:16