Merge pull request #3508 from alphagov/redis-ssl-181796569

Prepare to switch to Redis on PaaS
This commit is contained in:
Ben Thorner
2022-04-12 15:47:46 +01:00
committed by GitHub
3 changed files with 44 additions and 15 deletions

View File

@@ -16,6 +16,9 @@ def set_config_env_vars(vcap_services):
# Postgres config # Postgres config
os.environ['SQLALCHEMY_DATABASE_URI'] = vcap_services['postgres'][0]['credentials']['uri'].replace('postgres', os.environ['SQLALCHEMY_DATABASE_URI'] = vcap_services['postgres'][0]['credentials']['uri'].replace('postgres',
'postgresql') 'postgresql')
# Redis config
if 'redis' in vcap_services:
os.environ['REDIS_URL'] = vcap_services['redis'][0]['credentials']['uri']
vcap_application = json.loads(os.environ['VCAP_APPLICATION']) vcap_application = json.loads(os.environ['VCAP_APPLICATION'])
os.environ['NOTIFY_ENVIRONMENT'] = vcap_application['space_name'] os.environ['NOTIFY_ENVIRONMENT'] = vcap_application['space_name']

View File

@@ -2,6 +2,8 @@ import os
import sys import sys
import traceback import traceback
import gunicorn import gunicorn
import eventlet
import socket
from gds_metrics.gunicorn import child_exit # noqa from gds_metrics.gunicorn import child_exit # noqa
@@ -30,3 +32,22 @@ def on_exit(server):
def worker_int(worker): def worker_int(worker):
worker.log.info("worker: received SIGINT {}".format(worker.pid)) worker.log.info("worker: received SIGINT {}".format(worker.pid))
def fix_ssl_monkeypatching():
"""
eventlet works by monkey-patching core IO libraries (such as ssl) to be non-blocking. However, there's currently
a bug: In the normal socket library it may throw a timeout error as a `socket.timeout` exception. However
eventlet.green.ssl's patch raises an ssl.SSLError('timed out',) instead. redispy handles socket.timeout but not
ssl.SSLError, so we solve this by monkey patching the monkey patching code to raise the correct exception type
:scream:
https://github.com/eventlet/eventlet/issues/692
"""
# this has probably already been called somewhere in gunicorn internals, however, to be sure, we invoke it again.
# eventlet.monkey_patch can be called multiple times without issue
eventlet.monkey_patch()
eventlet.green.ssl.timeout_exc = socket.timeout
fix_ssl_monkeypatching()

View File

@@ -10,39 +10,38 @@ from app.cloudfoundry_config import (
@pytest.fixture @pytest.fixture
def postgres_config(): def cloudfoundry_config():
return [ return {
{ 'postgres': [{
'credentials': { 'credentials': {
'uri': 'postgres uri' 'uri': 'postgres uri'
} }
} }],
] 'redis': [{
'credentials': {
'uri': 'redis uri'
@pytest.fixture }
def cloudfoundry_config(postgres_config): }],
return {
'postgres': postgres_config,
'user-provided': [] 'user-provided': []
} }
@pytest.fixture @pytest.fixture
def cloudfoundry_environ(os_environ, cloudfoundry_config): def vcap_application(os_environ):
os.environ['VCAP_SERVICES'] = json.dumps(cloudfoundry_config)
os.environ['VCAP_APPLICATION'] = '{"space_name": "🚀🌌"}' os.environ['VCAP_APPLICATION'] = '{"space_name": "🚀🌌"}'
def test_extract_cloudfoundry_config_populates_other_vars(cloudfoundry_environ): def test_extract_cloudfoundry_config_populates_other_vars(cloudfoundry_config, vcap_application):
os.environ['VCAP_SERVICES'] = json.dumps(cloudfoundry_config)
extract_cloudfoundry_config() extract_cloudfoundry_config()
assert os.environ['SQLALCHEMY_DATABASE_URI'] == 'postgresql uri' assert os.environ['SQLALCHEMY_DATABASE_URI'] == 'postgresql uri'
assert os.environ['REDIS_URL'] == 'redis uri'
assert os.environ['NOTIFY_ENVIRONMENT'] == '🚀🌌' assert os.environ['NOTIFY_ENVIRONMENT'] == '🚀🌌'
assert os.environ['NOTIFY_LOG_PATH'] == '/home/vcap/logs/app.log' assert os.environ['NOTIFY_LOG_PATH'] == '/home/vcap/logs/app.log'
def test_set_config_env_vars_ignores_unknown_configs(cloudfoundry_config, cloudfoundry_environ): def test_set_config_env_vars_ignores_unknown_configs(cloudfoundry_config, vcap_application):
cloudfoundry_config['foo'] = {'credentials': {'foo': 'foo'}} cloudfoundry_config['foo'] = {'credentials': {'foo': 'foo'}}
cloudfoundry_config['user-provided'].append({ cloudfoundry_config['user-provided'].append({
'name': 'bar', 'credentials': {'bar': 'bar'} 'name': 'bar', 'credentials': {'bar': 'bar'}
@@ -52,3 +51,9 @@ def test_set_config_env_vars_ignores_unknown_configs(cloudfoundry_config, cloudf
assert 'foo' not in os.environ assert 'foo' not in os.environ
assert 'bar' not in os.environ assert 'bar' not in os.environ
def test_set_config_env_vars_copes_if_redis_not_set(cloudfoundry_config, vcap_application):
del cloudfoundry_config['redis']
set_config_env_vars(cloudfoundry_config)
assert 'REDIS_URL' not in os.environ