"""Application configuration.""" import logging import os import tempfile from dotenv import load_dotenv import pyraml.parser from secrets_manager.flask_ext import FlaskSecretsManager import sqlalchemy import owsclient from owsrequest.ows_client import correlation_id_getter, request_context_getter from python_pdp_sdk.backends.authorization_backend import ( AuthorizationBackend, PdpAuthorizationBackend, ) from python_pdp_sdk.connectors.ows_pdp.ows_pdp import OwsPdpClient # Production environment PROD_ENVIRONMENT = 'prod' DEV_ENVIRONMENT = 'dev' QA_ENVIRONMENT = 'qa' TEST_ENVIRONMENT = 'test' ENVIRONMENT = os.environ.get('Environment', DEV_ENVIRONMENT) if ENVIRONMENT == DEV_ENVIRONMENT: # Load environment variables from a .env file load_dotenv() # Service information SERVICE_NAME = 'ows-track' SERVICE_VERSION = '1.0.0' secrets_manager_client = FlaskSecretsManager( application_context=False, environment=ENVIRONMENT, service_name=SERVICE_NAME) # Errors and loggers SENTRY = secrets_manager_client.get_cred('SENTRY_DSN') or None LOGGER_LEVEL = logging.INFO LOGGER_NAME = 'ows1' NEO4J_DATABASE_NAME = os.environ.get('NEO4J_DATABASE_NAME', 'graph.db') NEO4J_URL = secrets_manager_client.get_cred('NEO4J_URL') NEO4J_USERNAME = secrets_manager_client.get_cred('NEO4J_USERNAME') NEO4J_PASSWORD = secrets_manager_client.get_cred('NEO4J_PASSWORD') # Database config if ENVIRONMENT == TEST_ENVIRONMENT and os.environ.get('TEST_DB_BACKEND') == 'mysql': # Functional tests run against a local/container MySQL (see docker-compose # `mysql-test` service) to match the QA/Prod engine. Selected only when # TEST_DB_BACKEND=mysql is set; otherwise tests fall back to SQLite below. # # Use StaticPool (a single shared connection) exactly like the SQLite test # config: the test harness sets up data and the Flask handler reads it # through separate sessions, relying on them sharing one connection (and # therefore one uncommitted transaction). A real connection pool would give # each session its own connection and the setup data would be invisible. POOL_CLASS = sqlalchemy.pool.StaticPool # Connection params come from the environment (docker-compose `unit-lint` # sets them). No credential default is hard-coded; the password must be # supplied via TEST_DB_PASSWORD. _TEST_DB_HOST = os.environ.get('TEST_DB_HOST', '127.0.0.1') _TEST_DB_PORT = os.environ.get('TEST_DB_PORT', '3306') _TEST_DB_USER = os.environ.get('TEST_DB_USER', 'root') _TEST_DB_PASSWORD = os.environ.get('TEST_DB_PASSWORD', '') def _test_mysql_url(db_name): return ( 'mysql+pymysql://{user}:{password}@{host}:{port}/{db_name}' '?charset=utf8mb4'.format( user=_TEST_DB_USER, password=_TEST_DB_PASSWORD, host=_TEST_DB_HOST, port=_TEST_DB_PORT, db_name=db_name)) DB_URL = _test_mysql_url('art_relations') OWS_TRACK_DB_URL = _test_mysql_url('ows_track') elif ENVIRONMENT == TEST_ENVIRONMENT: POOL_CLASS = sqlalchemy.pool.StaticPool DB_URL = 'sqlite://' OWS_TRACK_TEMP_DB = tempfile.NamedTemporaryFile() OWS_TRACK_DB_URL = ''.join(['sqlite:///', OWS_TRACK_TEMP_DB.name, '.db']) else: # DB Pool starts with specified pool size, but will temporarly increase # if there is a surge of requests. POOL_CLASS = sqlalchemy.pool.QueuePool POOL_SIZE = 15 POOL_RECYCLE_MS = 3600 # Avoids connections going stale POOL_MAX_OVERFLOW = 0 POOL_PRE_PING = False # We must explicitly set utf8 encoding for MySQL connections DB_URL = ( 'mysql+pymysql://{user}:{password}@{host}/{db_name}?charset={charset}' .format( user=secrets_manager_client.get_cred('AR_MYSQL_USER'), password=secrets_manager_client.get_cred('AR_MYSQL_PASSWORD'), host=secrets_manager_client.get_cred('AR_MYSQL_HOST'), db_name=secrets_manager_client.get_cred('AR_MYSQL_DATABASE'), charset='utf8mb4')) OWS_TRACK_DB_URL = ( 'mysql+pymysql://{user}:{password}@{host}/{db_name}?charset={charset}' .format( user=secrets_manager_client.get_cred('OWS_TRACK_DB_MYSQL_USER'), password=secrets_manager_client.get_cred('OWS_TRACK_DB_MYSQL_PASSWORD'), host=secrets_manager_client.get_cred('OWS_TRACK_DB_MYSQL_HOST'), db_name=secrets_manager_client.get_cred('OWS_TRACK_DB_MYSQL_DATABASE'), charset='utf8mb4')) # Generic handlers HEALTH_CHECK = '/hello/' path = os.path.dirname(os.path.dirname(__file__)) # API definition API_DEFINITION = pyraml.parser.load( os.path.join( path, 'spec/{service_name}-{version}.raml'.format( service_name=SERVICE_NAME, version=SERVICE_VERSION))) ONLY_LOG_ACCESS_ERRORS = False EXCLUDE_PATH = [HEALTH_CHECK, '/public/performer/roles'] EXCLUDE_PRODUCT_ID_OSR_VALIDATION = [1770138, 1748996, 1729918, 1775562, 219656, 212422] def setup_ows_client(environment) -> owsclient.OwsClient: """Set up ows-client.""" return owsclient.OwsClient( environment=environment, service_name=SERVICE_NAME, correlation_id_getter=correlation_id_getter, request_context_getter=request_context_getter, ) def setup_authorization_backend( ows_client: owsclient.OwsClient ) -> AuthorizationBackend: """Set up Authorization Backend.""" ows_pdp_client = OwsPdpClient(ows_client=ows_client) return PdpAuthorizationBackend(ows_pdp_client) ows_client = setup_ows_client(ENVIRONMENT) pdp_authorization_backend = setup_authorization_backend(ows_client)