"""Application configuration.""" import base64 import logging import os from os.path import abspath, dirname, join, pardir from dotenv import load_dotenv from secrets_manager.flask_ext import FlaskSecretsManager # Load environment variables from a .env file if present dotenv_path = abspath(join(dirname(__file__), pardir, ".env")) load_dotenv(dotenv_path, override=True) # Service information SERVICE_NAME = "ows-charts" SERVICE_VERSION = "1.0.0" # Production environment PROD_ENVIRONMENT = "prod" DEV_ENVIRONMENT = "dev" QA_ENVIRONMENT = "qa" TEST_ENVIRONMENT = "test" ENVIRONMENT = os.environ.get("Environment") or DEV_ENVIRONMENT secrets_manager_client = FlaskSecretsManager( application_context=False, environment=ENVIRONMENT, service_name=SERVICE_NAME) # Snowflake SNOWFLAKE_ACCOUNT = os.environ.get('SNOWFLAKE_ACCOUNT') SNOWFLAKE_USER = os.environ.get('SNOWFLAKE_USER') SNOWFLAKE_ROLE = os.environ.get('SNOWFLAKE_ROLE') SNOWFLAKE_WAREHOUSE = os.environ.get('SNOWFLAKE_WAREHOUSE') SNOWFLAKE_SCHEMA = os.environ.get('SNOWFLAKE_SCHEMA', 'DEV') SNOWFLAKE_DATABASE = os.environ.get('SNOWFLAKE_DATABASE') SNOWFLAKE_POOL_SIZE = 15 # UWSGI number of threads SNOWFLAKE_POOL_RECYCLE = 4 * 55 * 60 # Snowflake timeout: ~4 hours SNOWFLAKE_POOL_MAX_OVERFLOW = 5 SNOWFLAKE_POOL_PRE_PING = False SNOWFLAKE_POOL_RESET_ON_RETURN = None SENTRY_MESSAGE_FORMAT = '{service} error for resource {resource}:' # Default for local dev if ENVIRONMENT == DEV_ENVIRONMENT: SNOWFLAKE_PRIVATE_KEY_PATH = os.environ['HOME'] + '/.ssh/snowflake/rsa_key.p8' try: SNOWFLAKE_PRIVATE_KEY_PATH = secrets_manager_client.get_cred( 'SNOWFLAKE_PRIVATE_KEY_PATH') or SNOWFLAKE_PRIVATE_KEY_PATH SNOWFLAKE_KEY_PASSPHRASE = secrets_manager_client.get_cred( 'SNOWFLAKE_KEY_PASSPHRASE') or None except Exception: SNOWFLAKE_KEY_PASSPHRASE = None if SNOWFLAKE_KEY_PASSPHRASE: from cryptography.hazmat.primitives import serialization with open(SNOWFLAKE_PRIVATE_KEY_PATH, 'rb') as key: p_key = serialization.load_pem_private_key( key.read(), password=SNOWFLAKE_KEY_PASSPHRASE.encode()) pkb = p_key.private_bytes( encoding=serialization.Encoding.DER, format=serialization.PrivateFormat.PKCS8, encryption_algorithm=serialization.NoEncryption()) SNOWFLAKE_CONNECT_ARGS = {'private_key': pkb} else: SNOWFLAKE_CONNECT_ARGS = {} else: # For QA and PROD environments we use Secrets Manager SNOWFLAKE_PRIVATE_KEY = secrets_manager_client.get_cred('SNOWFLAKE_PRIVATE_KEY') or None if not SNOWFLAKE_PRIVATE_KEY or SNOWFLAKE_PRIVATE_KEY == 'dummy': # default value set by Terraform when you create a secret # noqa SNOWFLAKE_CONNECT_ARGS = {} else: SNOWFLAKE_CONNECT_ARGS = {'private_key': base64.b64decode(bytes(SNOWFLAKE_PRIVATE_KEY, encoding='utf-8'))} logging.info('Snowflake private key is set from Secrets Manager.') # Database config if ENVIRONMENT == TEST_ENVIRONMENT: DB_URL = 'sqlite://' SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = {} else: POOL_SIZE = 15 POOL_RECYCLE = 3600 # Avoids connections going stale POOL_MAX_OVERFLOW = 0 DB_URL = os.environ.get('DB_URL') SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ENGINE_OPTIONS = { 'pool_size': POOL_SIZE, 'pool_recycle': POOL_RECYCLE, 'max_overflow': POOL_MAX_OVERFLOW } # Errors and loggers SENTRY = secrets_manager_client.get_cred('SENTRY_DSN') if not SENTRY and ENVIRONMENT in [PROD_ENVIRONMENT, QA_ENVIRONMENT]: raise Exception(f"Sentry is not configured in {ENVIRONMENT}") LOGGER_DSN = os.environ.get("LOGGER_DSN") or None LOGGER_LEVEL = logging.INFO LOGGER_NAME = "ows1" HEALTH_CHECK = "/hello/" # Swagger documentation path SWAGGER_FILE_PATH = "spec/ows_charts-1.0.0.yaml" CHART_FILTER_PROPERTY_TO_COLUMN = { "country": "country", "frequency": "frequency", "genre": "genre", "id": "chartid", "platform": "platform", "target": "target", "type": "type" } CHART_RANKINGS_DEFAULT_LIMIT_ROWS = 1000 REDIS_HOST = os.environ.get("REDIS_HOST") REDIS_PORT = int(os.environ.get("REDIS_PORT", 6379)) REDIS_CACHE_TTL = int(os.environ.get("REDIS_CACHE_TTL", 60 * 60 * 1)) # 1 hour by default # CHARTS_TO_EXCLUDE is responsible for excluding outdated charts from selecting by passing platform_frequency_type # (variable example spotify_viral_weekly) of a particular chart(s) # This logic can be removed when we`ll stop storing and updating outdated and removed charts in our DB # Made to be consistent with Insights team # Insights reason described in IN-10347 # Also see IN-15241 for spotify_nmf CHARTS_TO_EXCLUDE = (os.environ.get("CHARTS_TO_EXCLUDE", "spotify_viral_weekly,spotify_spotify_nmf_weekly").lower().split(",")) SOUND_RECORDING_MAJOR_MOVE = int(os.environ.get("SOUND_RECORDING_MAJOR_MOVE", 5)) SNOWFLAKE_CORTEX_SEARCH_API_URL = os.environ.get('SNOWFLAKE_CORTEX_SEARCH_API_URL', '') SNOWFLAKE_CORTEX_SEARCH_TIMEOUT_MS = int(os.environ.get('SNOWFLAKE_CORTEX_SEARCH_TIMEOUT_MS', 3000))