Merge pull request #104 from GSA/fix-deployed-db-string

Fix deployed db string
This commit is contained in:
Ryan Ahearn
2022-11-01 13:02:16 -04:00
committed by GitHub
4 changed files with 63 additions and 52 deletions

View File

@@ -1,10 +1,10 @@
import json import json
import os from os import getenv
class CloudfoundryConfig: class CloudfoundryConfig:
def __init__(self): def __init__(self):
self.parsed_services = json.loads(os.environ.get('VCAP_SERVICES') or '{}') self.parsed_services = json.loads(getenv('VCAP_SERVICES') or '{}')
buckets = self.parsed_services.get('s3') or [] buckets = self.parsed_services.get('s3') or []
self.s3_buckets = {bucket['name']: bucket['credentials'] for bucket in buckets} self.s3_buckets = {bucket['name']: bucket['credentials'] for bucket in buckets}
self._empty_bucket_credentials = { self._empty_bucket_credentials = {
@@ -14,6 +14,10 @@ class CloudfoundryConfig:
'region': '' 'region': ''
} }
@property
def database_url(self):
return getenv('DATABASE_URL', '').replace('postgres://', 'postgresql://')
@property @property
def redis_url(self): def redis_url(self):
try: try:
@@ -22,7 +26,7 @@ class CloudfoundryConfig:
'rediss://' 'rediss://'
) )
except KeyError: except KeyError:
return os.environ.get('REDIS_URL') return getenv('REDIS_URL')
def s3_credentials(self, service_name): def s3_credentials(self, service_name):
return self.s3_buckets.get(service_name) or self._empty_bucket_credentials return self.s3_buckets.get(service_name) or self._empty_bucket_credentials

View File

@@ -1,6 +1,6 @@
import json import json
import os
from datetime import timedelta from datetime import timedelta
from os import getenv
from celery.schedules import crontab from celery.schedules import crontab
from kombu import Exchange, Queue from kombu import Exchange, Queue
@@ -64,50 +64,50 @@ class TaskNames(object):
class Config(object): class Config(object):
NOTIFY_APP_NAME = 'api' NOTIFY_APP_NAME = 'api'
NOTIFY_ENVIRONMENT = os.environ.get('NOTIFY_ENVIRONMENT', 'development') NOTIFY_ENVIRONMENT = getenv('NOTIFY_ENVIRONMENT', 'development')
# URL of admin app # URL of admin app
ADMIN_BASE_URL = os.environ.get('ADMIN_BASE_URL', 'http://localhost:6012') ADMIN_BASE_URL = getenv('ADMIN_BASE_URL', 'http://localhost:6012')
# URL of api app (on AWS this is the internal api endpoint) # URL of api app (on AWS this is the internal api endpoint)
API_HOST_NAME = os.environ.get('API_HOST_NAME', 'http://localhost:6011') API_HOST_NAME = getenv('API_HOST_NAME', 'http://localhost:6011')
# Credentials # Credentials
# secrets that internal apps, such as the admin app or document download, must use to authenticate with the API # secrets that internal apps, such as the admin app or document download, must use to authenticate with the API
# ADMIN_CLIENT_ID is called ADMIN_CLIENT_USER_NAME in api repo, they should match # ADMIN_CLIENT_ID is called ADMIN_CLIENT_USER_NAME in api repo, they should match
ADMIN_CLIENT_ID = os.environ.get('ADMIN_CLIENT_ID', 'notify-admin') ADMIN_CLIENT_ID = getenv('ADMIN_CLIENT_ID', 'notify-admin')
INTERNAL_CLIENT_API_KEYS = json.loads( INTERNAL_CLIENT_API_KEYS = json.loads(
os.environ.get( getenv(
'INTERNAL_CLIENT_API_KEYS', 'INTERNAL_CLIENT_API_KEYS',
('{"%s":["%s"]}' % (ADMIN_CLIENT_ID, os.getenv('ADMIN_CLIENT_SECRET'))) ('{"%s":["%s"]}' % (ADMIN_CLIENT_ID, getenv('ADMIN_CLIENT_SECRET')))
) )
) )
# encyption secret/salt # encyption secret/salt
SECRET_KEY = os.environ.get('SECRET_KEY') SECRET_KEY = getenv('SECRET_KEY')
DANGEROUS_SALT = os.environ.get('DANGEROUS_SALT') DANGEROUS_SALT = getenv('DANGEROUS_SALT')
ROUTE_SECRET_KEY_1 = os.environ.get('ROUTE_SECRET_KEY_1', 'dev-route-secret-key-1') ROUTE_SECRET_KEY_1 = getenv('ROUTE_SECRET_KEY_1', 'dev-route-secret-key-1')
ROUTE_SECRET_KEY_2 = os.environ.get('ROUTE_SECRET_KEY_2', 'dev-route-secret-key-2') ROUTE_SECRET_KEY_2 = getenv('ROUTE_SECRET_KEY_2', 'dev-route-secret-key-2')
# DB settings # DB settings
SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI') SQLALCHEMY_DATABASE_URI = cloud_config.database_url
SQLALCHEMY_RECORD_QUERIES = False SQLALCHEMY_RECORD_QUERIES = False
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_POOL_SIZE = int(os.environ.get('SQLALCHEMY_POOL_SIZE', 5)) SQLALCHEMY_POOL_SIZE = int(getenv('SQLALCHEMY_POOL_SIZE', 5))
SQLALCHEMY_POOL_TIMEOUT = 30 SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = 300 SQLALCHEMY_POOL_RECYCLE = 300
SQLALCHEMY_STATEMENT_TIMEOUT = 1200 SQLALCHEMY_STATEMENT_TIMEOUT = 1200
PAGE_SIZE = 50 PAGE_SIZE = 50
API_PAGE_SIZE = 250 API_PAGE_SIZE = 250
REDIS_URL = cloud_config.redis_url REDIS_URL = cloud_config.redis_url
REDIS_ENABLED = os.environ.get('REDIS_ENABLED', '0') == '1' REDIS_ENABLED = getenv('REDIS_ENABLED', '0') == '1'
EXPIRE_CACHE_TEN_MINUTES = 600 EXPIRE_CACHE_TEN_MINUTES = 600
EXPIRE_CACHE_EIGHT_DAYS = 8 * 24 * 60 * 60 EXPIRE_CACHE_EIGHT_DAYS = 8 * 24 * 60 * 60
# AWS Settings # AWS Settings
AWS_REGION = os.environ.get('AWS_REGION') AWS_REGION = getenv('AWS_REGION')
AWS_PINPOINT_REGION = os.environ.get("AWS_PINPOINT_REGION") AWS_PINPOINT_REGION = getenv("AWS_PINPOINT_REGION")
AWS_US_TOLL_FREE_NUMBER = os.environ.get("AWS_US_TOLL_FREE_NUMBER") AWS_US_TOLL_FREE_NUMBER = getenv("AWS_US_TOLL_FREE_NUMBER")
# Whether to ignore POSTs from SNS for replies to SMS we sent # Whether to ignore POSTs from SNS for replies to SMS we sent
RECEIVE_INBOUND_SMS = False RECEIVE_INBOUND_SMS = False
NOTIFY_EMAIL_DOMAIN = os.getenv('NOTIFY_EMAIL_DOMAIN', 'notify.sandbox.10x.gsa.gov') NOTIFY_EMAIL_DOMAIN = getenv('NOTIFY_EMAIL_DOMAIN', 'notify.sandbox.10x.gsa.gov')
SES_STUB_URL = None # TODO: set to a URL in env and remove this to use a stubbed SES service SES_STUB_URL = None # TODO: set to a URL in env and remove this to use a stubbed SES service
# AWS SNS topics for delivery receipts # AWS SNS topics for delivery receipts
VALIDATE_SNS_TOPICS = True VALIDATE_SNS_TOPICS = True
@@ -115,37 +115,37 @@ class Config(object):
# SMS config to be cleaned up during https://github.com/GSA/notifications-api/issues/7 # SMS config to be cleaned up during https://github.com/GSA/notifications-api/issues/7
# MMG API Key # MMG API Key
MMG_API_KEY = os.environ.get('MMG_API_KEY', 'placeholder') MMG_API_KEY = getenv('MMG_API_KEY', 'placeholder')
# Firetext API Key # Firetext API Key
FIRETEXT_API_KEY = os.environ.get("FIRETEXT_API_KEY", "placeholder") FIRETEXT_API_KEY = getenv("FIRETEXT_API_KEY", "placeholder")
FIRETEXT_INTERNATIONAL_API_KEY = os.environ.get("FIRETEXT_INTERNATIONAL_API_KEY", "placeholder") FIRETEXT_INTERNATIONAL_API_KEY = getenv("FIRETEXT_INTERNATIONAL_API_KEY", "placeholder")
# these should always add up to 100% # these should always add up to 100%
SMS_PROVIDER_RESTING_POINTS = { SMS_PROVIDER_RESTING_POINTS = {
'mmg': 50, 'mmg': 50,
'firetext': 50 'firetext': 50
} }
FIRETEXT_INBOUND_SMS_AUTH = json.loads(os.environ.get('FIRETEXT_INBOUND_SMS_AUTH', '[]')) FIRETEXT_INBOUND_SMS_AUTH = json.loads(getenv('FIRETEXT_INBOUND_SMS_AUTH', '[]'))
MMG_INBOUND_SMS_AUTH = json.loads(os.environ.get('MMG_INBOUND_SMS_AUTH', '[]')) MMG_INBOUND_SMS_AUTH = json.loads(getenv('MMG_INBOUND_SMS_AUTH', '[]'))
MMG_INBOUND_SMS_USERNAME = json.loads(os.environ.get('MMG_INBOUND_SMS_USERNAME', '[]')) MMG_INBOUND_SMS_USERNAME = json.loads(getenv('MMG_INBOUND_SMS_USERNAME', '[]'))
MMG_URL = os.environ.get("MMG_URL", "https://api.mmg.co.uk/jsonv2a/api.php") MMG_URL = getenv("MMG_URL", "https://api.mmg.co.uk/jsonv2a/api.php")
FIRETEXT_URL = os.environ.get("FIRETEXT_URL", "https://www.firetext.co.uk/api/sendsms/json") FIRETEXT_URL = getenv("FIRETEXT_URL", "https://www.firetext.co.uk/api/sendsms/json")
# Zendesk # Zendesk
ZENDESK_API_KEY = os.environ.get('ZENDESK_API_KEY') ZENDESK_API_KEY = getenv('ZENDESK_API_KEY')
# Logging # Logging
DEBUG = False DEBUG = False
NOTIFY_LOG_PATH = os.environ.get('NOTIFY_LOG_PATH', 'logs/application.log') NOTIFY_LOG_PATH = getenv('NOTIFY_LOG_PATH', 'logs/application.log')
# Monitoring # Monitoring
CRONITOR_ENABLED = False CRONITOR_ENABLED = False
CRONITOR_KEYS = json.loads(os.environ.get('CRONITOR_KEYS', '{}')) CRONITOR_KEYS = json.loads(getenv('CRONITOR_KEYS', '{}'))
STATSD_HOST = os.environ.get('STATSD_HOST') STATSD_HOST = getenv('STATSD_HOST')
STATSD_PORT = 8125 STATSD_PORT = 8125
STATSD_ENABLED = bool(STATSD_HOST) STATSD_ENABLED = bool(STATSD_HOST)
# Antivirus # Antivirus
ANTIVIRUS_ENABLED = os.environ.get('ANTIVIRUS_ENABLED', '1') == '1' ANTIVIRUS_ENABLED = getenv('ANTIVIRUS_ENABLED', '1') == '1'
SENDING_NOTIFICATIONS_TIMEOUT_PERIOD = 259200 # 3 days SENDING_NOTIFICATIONS_TIMEOUT_PERIOD = 259200 # 3 days
INVITATION_EXPIRATION_DAYS = 2 INVITATION_EXPIRATION_DAYS = 2
@@ -180,7 +180,7 @@ class Config(object):
LETTERS_VOLUME_EMAIL_TEMPLATE_ID = '11fad854-fd38-4a7c-bd17-805fb13dfc12' LETTERS_VOLUME_EMAIL_TEMPLATE_ID = '11fad854-fd38-4a7c-bd17-805fb13dfc12'
NHS_EMAIL_BRANDING_ID = 'a7dc4e56-660b-4db7-8cff-12c37b12b5ea' NHS_EMAIL_BRANDING_ID = 'a7dc4e56-660b-4db7-8cff-12c37b12b5ea'
# we only need real email in Live environment (production) # we only need real email in Live environment (production)
DVLA_EMAIL_ADDRESSES = json.loads(os.environ.get('DVLA_EMAIL_ADDRESSES', '[]')) DVLA_EMAIL_ADDRESSES = json.loads(getenv('DVLA_EMAIL_ADDRESSES', '[]'))
CELERY = { CELERY = {
'broker_url': REDIS_URL, 'broker_url': REDIS_URL,
@@ -323,8 +323,8 @@ class Config(object):
} }
# we can set celeryd_prefetch_multiplier to be 1 for celery apps which handle only long running tasks # we can set celeryd_prefetch_multiplier to be 1 for celery apps which handle only long running tasks
if os.environ.get('CELERYD_PREFETCH_MULTIPLIER'): if getenv('CELERYD_PREFETCH_MULTIPLIER'):
CELERY['worker_prefetch_multiplier'] = os.environ.get('CELERYD_PREFETCH_MULTIPLIER') CELERY['worker_prefetch_multiplier'] = getenv('CELERYD_PREFETCH_MULTIPLIER')
FROM_NUMBER = 'development' FROM_NUMBER = 'development'
@@ -337,21 +337,21 @@ class Config(object):
FREE_SMS_TIER_FRAGMENT_COUNT = 250000 FREE_SMS_TIER_FRAGMENT_COUNT = 250000
HIGH_VOLUME_SERVICE = json.loads(os.environ.get('HIGH_VOLUME_SERVICE', '[]')) HIGH_VOLUME_SERVICE = json.loads(getenv('HIGH_VOLUME_SERVICE', '[]'))
TEMPLATE_PREVIEW_API_HOST = os.environ.get('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013') TEMPLATE_PREVIEW_API_HOST = getenv('TEMPLATE_PREVIEW_API_HOST', 'http://localhost:6013')
TEMPLATE_PREVIEW_API_KEY = os.environ.get('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key') TEMPLATE_PREVIEW_API_KEY = getenv('TEMPLATE_PREVIEW_API_KEY', 'my-secret-key')
DOCUMENT_DOWNLOAD_API_HOST = os.environ.get('DOCUMENT_DOWNLOAD_API_HOST', 'http://localhost:7000') DOCUMENT_DOWNLOAD_API_HOST = getenv('DOCUMENT_DOWNLOAD_API_HOST', 'http://localhost:7000')
DOCUMENT_DOWNLOAD_API_KEY = os.environ.get('DOCUMENT_DOWNLOAD_API_KEY', 'auth-token') DOCUMENT_DOWNLOAD_API_KEY = getenv('DOCUMENT_DOWNLOAD_API_KEY', 'auth-token')
def _default_s3_credentials(bucket_name): def _default_s3_credentials(bucket_name):
return { return {
'bucket': bucket_name, 'bucket': bucket_name,
'access_key_id': os.environ.get('AWS_ACCESS_KEY_ID'), 'access_key_id': getenv('AWS_ACCESS_KEY_ID'),
'secret_access_key': os.environ.get('AWS_SECRET_ACCESS_KEY'), 'secret_access_key': getenv('AWS_SECRET_ACCESS_KEY'),
'region': os.environ.get('AWS_REGION') 'region': getenv('AWS_REGION')
} }
@@ -391,7 +391,7 @@ class Test(Development):
CONTACT_LIST_BUCKET = _default_s3_credentials('test-contact-list') CONTACT_LIST_BUCKET = _default_s3_credentials('test-contact-list')
# this is overriden in CI # this is overriden in CI
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_TEST_URI') SQLALCHEMY_DATABASE_URI = getenv('SQLALCHEMY_DATABASE_TEST_URI')
CELERY = { CELERY = {
**Config.CELERY, **Config.CELERY,

View File

@@ -28,14 +28,14 @@ AWS_US_TOLL_FREE_NUMBER=+18446120782
ADMIN_BASE_URL=http://admin:6012 ADMIN_BASE_URL=http://admin:6012
API_HOST_NAME=http://dev:6011 API_HOST_NAME=http://dev:6011
REDIS_URL=redis://redis:6380 REDIS_URL=redis://redis:6380
SQLALCHEMY_DATABASE_URI=postgresql://postgres:chummy@db:5432/notification_api DATABASE_URL=postgresql://postgres:chummy@db:5432/notification_api
SQLALCHEMY_DATABASE_TEST_URI=postgresql://postgres:chummy@db:5432/test_notification_api SQLALCHEMY_DATABASE_TEST_URI=postgresql://postgres:chummy@db:5432/test_notification_api
# Local direct setup, all overwritten in cloud.gov # Local direct setup, all overwritten in cloud.gov
# ADMIN_BASE_URL=http://localhost:6012 # ADMIN_BASE_URL=http://localhost:6012
# API_HOST_NAME=http://localhost:6011 # API_HOST_NAME=http://localhost:6011
# REDIS_URL=redis://localhost:6379 # REDIS_URL=redis://localhost:6379
# SQLALCHEMY_DATABASE_URI=postgresql://localhost:5432/notification_api # DATABASE_URL=postgresql://localhost:5432/notification_api
# SQLALCHEMY_DATABASE_TEST_URI=postgresql://localhost:5432/test_notification_api # SQLALCHEMY_DATABASE_TEST_URI=postgresql://localhost:5432/test_notification_api
############################################################# #############################################################

View File

@@ -5,12 +5,13 @@ import pytest
from app.cloudfoundry_config import CloudfoundryConfig from app.cloudfoundry_config import CloudfoundryConfig
bucket_credentials = { _bucket_credentials = {
'access_key_id': 'csv-access', 'access_key_id': 'csv-access',
'bucket': 'csv-upload-bucket', 'bucket': 'csv-upload-bucket',
'region': 'us-gov-west-1', 'region': 'us-gov-west-1',
'secret_access_key': 'csv-secret' 'secret_access_key': 'csv-secret'
} }
_postgres_url = 'postgres://postgres:password@localhost:5432/db_name'
@pytest.fixture @pytest.fixture
@@ -18,7 +19,7 @@ def vcap_services():
return { return {
'aws-rds': [{ 'aws-rds': [{
'credentials': { 'credentials': {
'uri': 'postgres uri' 'uri': _postgres_url
} }
}], }],
'aws-elasticache-redis': [{ 'aws-elasticache-redis': [{
@@ -29,7 +30,7 @@ def vcap_services():
's3': [ 's3': [
{ {
'name': 'notifications-api-csv-upload-bucket-test', 'name': 'notifications-api-csv-upload-bucket-test',
'credentials': bucket_credentials 'credentials': _bucket_credentials
}, },
{ {
'name': 'notifications-api-contact-list-bucket-test', 'name': 'notifications-api-contact-list-bucket-test',
@@ -45,6 +46,12 @@ def vcap_services():
} }
def test_database_url(vcap_services):
os.environ['DATABASE_URL'] = _postgres_url
assert CloudfoundryConfig().database_url == 'postgresql://postgres:password@localhost:5432/db_name'
def test_redis_url(vcap_services): def test_redis_url(vcap_services):
os.environ['VCAP_SERVICES'] = json.dumps(vcap_services) os.environ['VCAP_SERVICES'] = json.dumps(vcap_services)
@@ -62,7 +69,7 @@ def test_redis_url_falls_back_to_REDIS_URL():
def test_s3_bucket_credentials(vcap_services): def test_s3_bucket_credentials(vcap_services):
os.environ['VCAP_SERVICES'] = json.dumps(vcap_services) os.environ['VCAP_SERVICES'] = json.dumps(vcap_services)
assert CloudfoundryConfig().s3_credentials('notifications-api-csv-upload-bucket-test') == bucket_credentials assert CloudfoundryConfig().s3_credentials('notifications-api-csv-upload-bucket-test') == _bucket_credentials
def test_s3_bucket_credentials_falls_back_to_empty_creds(): def test_s3_bucket_credentials_falls_back_to_empty_creds():