From c1e3e8939ad5168f3c03d126207828e1d244d7f7 Mon Sep 17 00:00:00 2001 From: Daniel Schick Date: Fri, 5 Dec 2025 18:08:15 +0100 Subject: [PATCH] Externalize all configuration parameters Pt.I --- src/server/BreCal/__init__.py | 22 ++++++++++++++----- src/server/BreCal/local_db.py | 27 ++++++++++++++--------- src/server/config.py.sample | 40 +++++++++++++++++++++++++++++++++++ src/server/flaskapp.wsgi | 33 ++++++++++++++++++----------- 4 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 src/server/config.py.sample diff --git a/src/server/BreCal/__init__.py b/src/server/BreCal/__init__.py index 8924b11..ed16a4f 100644 --- a/src/server/BreCal/__init__.py +++ b/src/server/BreCal/__init__.py @@ -1,6 +1,7 @@ from flask import Flask import os +import sys import logging from . import local_db @@ -36,7 +37,6 @@ from BreCal.stubs.df_times import get_df_times from BreCal.services.schedule_routines import setup_schedule, run_schedule_permanently_in_background def create_app(test_config=None, instance_path=None): - app = Flask(__name__, instance_relative_config=True) app.config.from_mapping( SECRET_KEY='dev' @@ -48,6 +48,8 @@ def create_app(test_config=None, instance_path=None): if instance_path is not None: app.instance_path = instance_path + elif app.config.get("INSTANCE_PATH"): + app.instance_path = app.config["INSTANCE_PATH"] try: import os @@ -69,13 +71,23 @@ def create_app(test_config=None, instance_path=None): app.register_blueprint(history.bp) app.register_blueprint(ports.bp) - logging.basicConfig(filename='brecaltest.log', level=logging.DEBUG, format='%(asctime)s | %(name)s | %(levelname)s | %(message)s') - local_db.initPool(os.path.dirname(app.instance_path)) + log_level = getattr(logging, app.config.get("LOG_LEVEL", "DEBUG")) + log_kwargs = {"format": "%(asctime)s | %(name)s | %(levelname)s | %(message)s"} + if app.config.get("LOG_TO_STDERR"): + log_kwargs["stream"] = sys.stderr + else: + log_kwargs["filename"] = app.config.get("LOG_FILE", "brecaltest.log") + logging.basicConfig(level=log_level, **log_kwargs) + + if app.config.get("SECRET_KEY"): + os.environ["SECRET_KEY"] = app.config["SECRET_KEY"] + + local_db.initPool(os.path.dirname(app.instance_path), config=app.config) logging.info('App started') # Setup Routine jobs (e.g., reevaluation of shipcalls) - setup_schedule(update_shipcalls_interval_in_minutes=60) - run_schedule_permanently_in_background(latency=30) + setup_schedule(update_shipcalls_interval_in_minutes=app.config.get("SCHEDULE_UPDATE_SHIPCALLS_MINUTES", 60)) + run_schedule_permanently_in_background(latency=app.config.get("SCHEDULE_BACKGROUND_LATENCY_SECONDS", 30)) logging.info('Routine Jobs are defined.') return app diff --git a/src/server/BreCal/local_db.py b/src/server/BreCal/local_db.py index 95af1be..e9c684a 100644 --- a/src/server/BreCal/local_db.py +++ b/src/server/BreCal/local_db.py @@ -8,6 +8,7 @@ import sys from BreCal.schemas import defs config_path = None +secure_dir = None _connection_pool = None @@ -23,17 +24,26 @@ def _build_pool_config(connection_data, pool_name, pool_size): return pool_config -def initPool(instancePath, connection_filename="connection_data_prod.json", - pool_name="brecal_pool", pool_size=10): +def initPool(instancePath, config=None, connection_filename="connection_data_prod.json", + credentials_file="email_credentials_test.json", pool_name="brecal_pool", pool_size=10, + secure_directory=None): """ Initialize the MySQL connection pool and load email credentials. """ - global config_path, _connection_pool + global config_path, secure_dir, _connection_pool try: + if config: + connection_filename = config.get("DB_CONNECTION_FILE", connection_filename) + credentials_file = config.get("EMAIL_CREDENTIALS_FILE", credentials_file) + pool_name = config.get("DB_POOL_NAME", pool_name) + pool_size = config.get("DB_POOL_SIZE", pool_size) + secure_directory = config.get("SECURE_DIR", secure_directory) + + if secure_dir is None: + secure_dir = secure_directory if secure_directory else os.path.join(instancePath, '../../../secure') + if config_path is None: - config_path = os.path.join(instancePath, f'../../../secure/{connection_filename}') - - # config_path = 'C:\\temp\\connection_data_test.json' + config_path = os.path.join(secure_dir, connection_filename) print(config_path) if not os.path.exists(config_path): @@ -54,10 +64,7 @@ def initPool(instancePath, connection_filename="connection_data_prod.json", finally: conn_from_pool.close() - credentials_file = "email_credentials_test.json" - credentials_path = os.path.join(instancePath, f'../../../secure/{credentials_file}') - - # credentials_path = "E:/temp/email_credentials_devel.json" + credentials_path = os.path.join(secure_dir, credentials_file) if not os.path.exists(credentials_path): print('cannot find ' + os.path.abspath(credentials_path)) diff --git a/src/server/config.py.sample b/src/server/config.py.sample new file mode 100644 index 0000000..5a1a725 --- /dev/null +++ b/src/server/config.py.sample @@ -0,0 +1,40 @@ +""" +Sample configuration for the Flask instance. + +Copy this file to `src/server/instance/config.py` (the instance folder is git-ignored) +and adjust the values for each deployment target. +""" + +# Flask +SECRET_KEY = "change-me" + +# Python path adjustments used by the WSGI entrypoint (flaskapp.wsgi) +APP_ROOT = "/var/www/brecal/src/server" +SITE_PACKAGES = "/var/www/venv/lib/python3.12/site-packages/" + +# Paths to environment-specific secrets and instance data +SECURE_DIR = "/var/www/secure" # directory that holds connection/email JSON files +INSTANCE_PATH = "/var/www/brecal/src/server/instance" + +# Logging +LOG_FILE = "brecal.log" +LOG_LEVEL = "INFO" # e.g. DEBUG, INFO, WARNING +LOG_TO_STDERR = False + +# Database pool setup +DB_CONNECTION_FILE = "connection_data_prod.json" +DB_POOL_NAME = "brecal_pool" +DB_POOL_SIZE = 10 + +# Email + notifications +EMAIL_CREDENTIALS_FILE = "email_credentials_prod.json" +EMAIL_URL_TEMPLATE = "https://brecal.example.com/shipcalls/" # base URL for links in emails +SMTP_DEBUG_LEVEL = 0 # 0 = quiet, 1 = verbose + +# Scheduler cadence +SCHEDULE_UPDATE_SHIPCALLS_MINUTES = 60 +SCHEDULE_BACKGROUND_LATENCY_SECONDS = 30 + +# Notification cleanup / escalation windows +NOTIFICATION_COOLDOWN_MINS = 10 +NOTIFICATION_MAX_AGE_DAYS = 3 diff --git a/src/server/flaskapp.wsgi b/src/server/flaskapp.wsgi index 4bf64f7..fbcf450 100644 --- a/src/server/flaskapp.wsgi +++ b/src/server/flaskapp.wsgi @@ -1,20 +1,29 @@ -import os -import sys import logging +import os +import runpy +import sys +from pathlib import Path -sys.path.insert(0, '/var/www/brecal_test/src/server') -sys.path.insert(0, '/var/www/venv/lib/python3.12/site-packages/') +BASE_DIR = Path(__file__).resolve().parent +INSTANCE_DIR = BASE_DIR / "instance" +CONFIG_PATH = INSTANCE_DIR / "config.py" -import schedule +config = {} +if CONFIG_PATH.exists(): + config = runpy.run_path(str(CONFIG_PATH)) -# set the key -os.environ['SECRET_KEY'] = 'zdiTz8P3jXOc7jztIQAoelK4zztyuCpJ' +app_root = config.get("APP_ROOT", str(BASE_DIR)) +site_packages = config.get("SITE_PACKAGES") -# Set up logging -logging.basicConfig(stream=sys.stderr, level=logging.DEBUG) +sys.path.insert(0, app_root) +if site_packages: + sys.path.insert(0, site_packages) -# Set up Scheduled Jobs +if config.get("SECRET_KEY"): + os.environ["SECRET_KEY"] = config["SECRET_KEY"] + +log_kwargs = {"level": getattr(logging, config.get("LOG_LEVEL", "DEBUG")), "stream": sys.stderr} +logging.basicConfig(**log_kwargs) -# Import and run the Flask app from BreCal import create_app -application = create_app() +application = create_app(instance_path=config.get("INSTANCE_PATH"))