From 33ea75930aedd4fa1af82bbfb40721a62209b359 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 11:18:46 +0100 Subject: [PATCH 01/13] clients: add cbc proxy clients We are going to invoke a lambda to send a message to the CBC We need a CBC Proxy Client to do this The Client will be able to send/update/cancel broadcasts in the CBC Unless we have configured the app with AWS credentials for the CBCProxyClient, we just want to use a client that does nothing: the noop client The AWS access keys are separate for the CBC Proxy vs other Notify AWS things because the CBC Proxy lives in another AWS account Signed-off-by: Toby Lorne Co-authored-by: Pea Co-authored-by: Katie --- app/__init__.py | 6 ++++ app/clients/cbc_proxy.py | 59 ++++++++++++++++++++++++++++++++++++++++ app/config.py | 5 ++++ 3 files changed, 70 insertions(+) create mode 100644 app/clients/cbc_proxy.py diff --git a/app/__init__.py b/app/__init__.py index efa1a6697..d79cb6bde 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -23,6 +23,7 @@ from werkzeug.local import LocalProxy from app.celery.celery import NotifyCelery from app.clients import Clients +from app.clients.cbc_proxy import CBCProxyClient, CBCProxyNoopClient from app.clients.document_download import DocumentDownloadClient from app.clients.email.aws_ses import AwsSesClient from app.clients.email.aws_ses_stub import AwsSesStubClient @@ -60,6 +61,7 @@ zendesk_client = ZendeskClient() statsd_client = StatsdClient() redis_store = RedisClient() performance_platform_client = PerformancePlatformClient() +cbc_proxy_client = CBCProxyNoopClient() document_download_client = DocumentDownloadClient() metrics = GDSMetrics() @@ -112,6 +114,10 @@ def create_app(application): performance_platform_client.init_app(application) document_download_client.init_app(application) + if application.config['CBC_PROXY_AWS_ACCESS_KEY_ID']: + cbc_proxy_client = CBCProxyClient() + cbc_proxy_client.init_app(application) + register_blueprint(application) register_v2_blueprints(application) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py new file mode 100644 index 000000000..8b8fe436c --- /dev/null +++ b/app/clients/cbc_proxy.py @@ -0,0 +1,59 @@ +# Noop = no operation +class CBCProxyNoopClient: + + def init_app(self, app): + pass + + def create_and_send_broadcast( + self, + identifier, headline, description, + ): + # identifier=broadcast_message.identifier, + # headline="GOV.UK Notify Broadcast", + # description=broadcast_message.description, + pass + + # We have not implementated updating a broadcast + def update_and_send_broadcast( + self, + identifier, references, headline, description, + ): + pass + + # We have not implemented cancelling a broadcast + def cancel_broadcast( + self, + identifier, references, headline, description, + ): + pass + + +class CBCProxyClient: + + def init_app(self, app): + self.aws_access_key_id = app.config['CBC_PROXY_AWS_ACCESS_KEY_ID'] + self.aws_secret_access_key = app.config['CBC_PROXY_AWS_SECRET_ACCESS_KEY'] + self.aws_region = 'eu-west-2' + + def create_and_send_broadcast( + self, + identifier, headline, description, + ): + # identifier=broadcast_message.identifier, + # headline="GOV.UK Notify Broadcast", + # description=broadcast_message.description, + pass + + # We have not implementated updating a broadcast + def update_and_send_broadcast( + self, + identifier, references, headline, description, + ): + pass + + # We have not implemented cancelling a broadcast + def cancel_broadcast( + self, + identifier, references, headline, description, + ): + pass diff --git a/app/config.py b/app/config.py index 7b9981e52..91667bf0f 100644 --- a/app/config.py +++ b/app/config.py @@ -353,6 +353,11 @@ class Config(object): AWS_REGION = 'eu-west-1' + # CBC Proxy + # if the access keys are empty then noop client is used + CBC_PROXY_AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID', '') + CBC_PROXY_AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY', '') + ###################### # Config overrides ### From 2cc0a658515893ca253abeaf4a2aa273056e01f7 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 11:57:26 +0100 Subject: [PATCH 02/13] celery: broadcast msg create invokes cbc proxy When we create a broadcast message, we should invoke the cbc proxy to send a cap message Either a function will be invoked within AWS, or a noop function call is made, depending on the environment We have only implemented CB message creation in the CBC Proxy, without polygons, therefore we: * only invoke the CBC Proxy during message creation * only send description, identifier, and hard-coded headline Signed-off-by: Toby Lorne Co-authored-by: Pea Co-authored-by: Katie --- app/celery/broadcast_message_tasks.py | 16 +++++++++- .../celery/test_broadcast_message_tasks.py | 32 +++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/celery/broadcast_message_tasks.py b/app/celery/broadcast_message_tasks.py index f73705f5a..9a02e2096 100644 --- a/app/celery/broadcast_message_tasks.py +++ b/app/celery/broadcast_message_tasks.py @@ -2,8 +2,9 @@ import requests from flask import current_app from notifications_utils.statsd_decorators import statsd -from app import notify_celery +from app import cbc_proxy_client, notify_celery +from app.models import BroadcastEventMessageType from app.dao.broadcast_message_dao import dao_get_broadcast_event_by_id @@ -12,6 +13,19 @@ from app.dao.broadcast_message_dao import dao_get_broadcast_event_by_id def send_broadcast_event(broadcast_event_id, provider='stub-1'): broadcast_event = dao_get_broadcast_event_by_id(broadcast_event_id) + if broadcast_event.message_type == BroadcastEventMessageType.ALERT: + current_app.logger.info( + f'invoking cbc proxy to send ' + f'broadcast_event {broadcast_event.reference} ' + f'msgType {broadcast_event.message_type} to {provider}' + ) + + cbc_proxy_client.create_and_send_broadcast( + identifier=str(broadcast_event.id), + headline="GOV.UK Notify Broadcast", + description=broadcast_event.transmitted_content['body'], + ) + current_app.logger.info( f'sending broadcast_event {broadcast_event.reference} ' f'msgType {broadcast_event.message_type} to {provider}' diff --git a/tests/app/celery/test_broadcast_message_tasks.py b/tests/app/celery/test_broadcast_message_tasks.py index 76d5e2001..c1830ce5c 100644 --- a/tests/app/celery/test_broadcast_message_tasks.py +++ b/tests/app/celery/test_broadcast_message_tasks.py @@ -9,7 +9,7 @@ from tests.app.db import create_template, create_broadcast_message, create_broad @freeze_time('2020-08-01 12:00') -def test_send_broadcast_event_sends_data_correctly(sample_service): +def test_send_broadcast_event_sends_data_correctly(mocker, sample_service): template = create_template(sample_service, BROADCAST_TYPE) broadcast_message = create_broadcast_message( template, @@ -18,10 +18,20 @@ def test_send_broadcast_event_sends_data_correctly(sample_service): ) event = create_broadcast_event(broadcast_message) + mock_create_broadcast = mocker.patch( + 'app.cbc_proxy_client.create_and_send_broadcast', + ) + with requests_mock.Mocker() as request_mock: request_mock.post("http://test-cbc-proxy/broadcasts/events/stub-1", json={'valid': 'true'}, status_code=200) send_broadcast_event(broadcast_event_id=str(event.id)) + mock_create_broadcast.assert_called_once_with( + identifier=str(event.id), + headline="GOV.UK Notify Broadcast", + description='this is an emergency broadcast message', + ) + assert request_mock.call_count == 1 assert request_mock.request_history[0].method == 'POST' assert request_mock.request_history[0].headers["Content-type"] == "application/json" @@ -36,16 +46,22 @@ def test_send_broadcast_event_sends_data_correctly(sample_service): } -def test_send_broadcast_event_sends_references(sample_service): +def test_send_broadcast_event_sends_references(mocker, sample_service): template = create_template(sample_service, BROADCAST_TYPE, content='content') broadcast_message = create_broadcast_message(template, areas=['london'], status=BroadcastStatusType.BROADCASTING) alert_event = create_broadcast_event(broadcast_message, message_type=BroadcastEventMessageType.ALERT) cancel_event = create_broadcast_event(broadcast_message, message_type=BroadcastEventMessageType.CANCEL) + mock_create_broadcast = mocker.patch( + 'app.cbc_proxy_client.create_and_send_broadcast', + ) + with requests_mock.Mocker() as request_mock: request_mock.post("http://test-cbc-proxy/broadcasts/events/stub-1", json={'valid': 'true'}, status_code=200) send_broadcast_event(broadcast_event_id=str(cancel_event.id)) + assert not mock_create_broadcast.called + assert request_mock.call_count == 1 assert request_mock.request_history[0].method == 'POST' assert request_mock.request_history[0].headers["Content-type"] == "application/json" @@ -56,11 +72,15 @@ def test_send_broadcast_event_sends_references(sample_service): assert cbc_json['previous_event_references'] == [alert_event.reference] -def test_send_broadcast_event_errors(sample_service): +def test_send_broadcast_event_errors(mocker, sample_service): template = create_template(sample_service, BROADCAST_TYPE) broadcast_message = create_broadcast_message(template, status=BroadcastStatusType.BROADCASTING) event = create_broadcast_event(broadcast_message) + mock_create_broadcast = mocker.patch( + 'app.cbc_proxy_client.create_and_send_broadcast', + ) + with requests_mock.Mocker() as request_mock: request_mock.post("http://test-cbc-proxy/broadcasts/events/stub-1", text='503 bad gateway', status_code=503) # we're not retrying or anything for the moment - but this'll ensure any exception gets logged @@ -68,3 +88,9 @@ def test_send_broadcast_event_errors(sample_service): send_broadcast_event(broadcast_event_id=str(event.id)) assert ex.value.response.status_code == 503 + + mock_create_broadcast.assert_called_once_with( + identifier=str(event.id), + headline="GOV.UK Notify Broadcast", + description='this is an emergency broadcast message', + ) From efa6fb0bd9364ac7c5c1dff68cc437bc37fac579 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 13:01:17 +0100 Subject: [PATCH 03/13] clients: explicitly declare cbc_proxy_client it is global rather than local but python cannot infer this and we get UnboundLocalError Signed-off-by: Toby Lorne --- app/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/__init__.py b/app/__init__.py index d79cb6bde..e30655832 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -114,6 +114,7 @@ def create_app(application): performance_platform_client.init_app(application) document_download_client.init_app(application) + global cbc_proxy_client if application.config['CBC_PROXY_AWS_ACCESS_KEY_ID']: cbc_proxy_client = CBCProxyClient() cbc_proxy_client.init_app(application) From 14f8e7a5ff6d18dfadd2b20cf892c05b66103d79 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 13:33:51 +0100 Subject: [PATCH 04/13] clients: cbc_proxy client inits lambda client Using correct: * key id * secret key * region Signed-off-by: Toby Lorne Co-authored-by: Pea Co-authored-by: Katie --- app/clients/cbc_proxy.py | 11 ++++++++--- tests/app/clients/test_cbc_proxy.py | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/app/clients/test_cbc_proxy.py diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 8b8fe436c..2405c67f5 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -1,3 +1,5 @@ +import boto3 + # Noop = no operation class CBCProxyNoopClient: @@ -31,9 +33,12 @@ class CBCProxyNoopClient: class CBCProxyClient: def init_app(self, app): - self.aws_access_key_id = app.config['CBC_PROXY_AWS_ACCESS_KEY_ID'] - self.aws_secret_access_key = app.config['CBC_PROXY_AWS_SECRET_ACCESS_KEY'] - self.aws_region = 'eu-west-2' + self._lambda_client = boto3.client( + 'lambda', + region_name='eu-west-2', + aws_access_key_id=app.config['CBC_PROXY_AWS_ACCESS_KEY_ID'], + aws_secret_access_key=app.config['CBC_PROXY_AWS_SECRET_ACCESS_KEY'], + ) def create_and_send_broadcast( self, diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py new file mode 100644 index 000000000..34bc89b0c --- /dev/null +++ b/tests/app/clients/test_cbc_proxy.py @@ -0,0 +1,27 @@ +import pytest + +from app.clients.cbc_proxy import CBCProxyClient + + +@pytest.fixture(scope='function') +def cbc_proxy(client, mocker): + client = CBCProxyClient() + current_app = mocker.Mock(config={ + 'CBC_PROXY_AWS_ACCESS_KEY_ID': 'cbc-proxy-aws-access-key-id', + 'CBC_PROXY_AWS_SECRET_ACCESS_KEY': 'cbc-proxy-aws-secret-access-key', + }) + client.init_app(current_app) + return client + + +def test_cbc_proxy_lambda_client_has_correct_region(cbc_proxy): + assert cbc_proxy._lambda_client._client_config.region_name == 'eu-west-2' + pass + + +def test_cbc_proxy_lambda_client_has_correct_keys(cbc_proxy): + key = cbc_proxy._lambda_client._request_signer._credentials.access_key + secret = cbc_proxy._lambda_client._request_signer._credentials.secret_key + + assert key == 'cbc-proxy-aws-access-key-id' + assert secret == 'cbc-proxy-aws-secret-access-key' From ee79768d431a71a73b500b0bcbaca3175cecb347 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 13:59:52 +0100 Subject: [PATCH 05/13] clients: cbc_proxy client uses _ld not _lambda _ld is better than _lambda because it causes primitive python syntax highlighting to not get confused _lambda is better than _ld because it is less jargon Signed-off-by: Toby Lorne Co-authored-by: Pea Co-authored-by: Katie --- app/clients/cbc_proxy.py | 2 +- tests/app/clients/test_cbc_proxy.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 2405c67f5..5bf3655b2 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -33,7 +33,7 @@ class CBCProxyNoopClient: class CBCProxyClient: def init_app(self, app): - self._lambda_client = boto3.client( + self._ld_client = boto3.client( 'lambda', region_name='eu-west-2', aws_access_key_id=app.config['CBC_PROXY_AWS_ACCESS_KEY_ID'], diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index 34bc89b0c..58ed5b8c6 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -14,14 +14,14 @@ def cbc_proxy(client, mocker): return client -def test_cbc_proxy_lambda_client_has_correct_region(cbc_proxy): - assert cbc_proxy._lambda_client._client_config.region_name == 'eu-west-2' +def test_cbc_proxy_ld_client_has_correct_region(cbc_proxy): + assert cbc_proxy._ld_client._client_config.region_name == 'eu-west-2' pass -def test_cbc_proxy_lambda_client_has_correct_keys(cbc_proxy): - key = cbc_proxy._lambda_client._request_signer._credentials.access_key - secret = cbc_proxy._lambda_client._request_signer._credentials.secret_key +def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): + key = cbc_proxy._ld_client._request_signer._credentials.access_key + secret = cbc_proxy._ld_client._request_signer._credentials.secret_key assert key == 'cbc-proxy-aws-access-key-id' assert secret == 'cbc-proxy-aws-secret-access-key' From 73507b3abc6bd26ac3b957c3fcf474bf9d1a92af Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 14:00:53 +0100 Subject: [PATCH 06/13] clients: cbc_proxy invokes hardcoded function right now we are doing an end-to-end journey with a CBC from Notify (the CBE) and we would like to approve a broadcast in notify and have it appear on our test handset in order to do this, we: * hook up the lambda that we made in the correct VPC to cbc_proxy client * test that it is called correctly Signed-off-by: Toby Lorne Co-authored-by: Pea Co-authored-by: Katie --- app/clients/cbc_proxy.py | 16 +++++++++++--- tests/app/clients/test_cbc_proxy.py | 34 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 5bf3655b2..7e3cf6ba4 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -1,3 +1,5 @@ +import json + import boto3 # Noop = no operation @@ -44,9 +46,17 @@ class CBCProxyClient: self, identifier, headline, description, ): - # identifier=broadcast_message.identifier, - # headline="GOV.UK Notify Broadcast", - # description=broadcast_message.description, + payload_bytes = bytes(json.dumps({ + 'identifier': identifier, + 'headline': headline, + 'description': description, + }), encoding='utf8') + + self._ld_client.invoke( + FunctionName='bt-ee-1-proxy', + InvocationType='RequestResponse', + Payload=payload_bytes, + ) pass # We have not implementated updating a broadcast diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index 58ed5b8c6..bc8fe429f 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -1,3 +1,5 @@ +import json + import pytest from app.clients.cbc_proxy import CBCProxyClient @@ -25,3 +27,35 @@ def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): assert key == 'cbc-proxy-aws-access-key-id' assert secret == 'cbc-proxy-aws-secret-access-key' + + +def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): + identifier = 'my-identifier' + headline = 'my-headline' + description = 'my-description' + + ld_client_mock = mocker.patch.object( + cbc_proxy, + '_ld_client', + create=True, + ) + + cbc_proxy.create_and_send_broadcast( + identifier=identifier, + headline=headline, + description=description, + ) + + ld_client_mock.invoke.assert_called_once_with( + FunctionName='bt-ee-1-proxy', + InvocationType='RequestResponse', + Payload=mocker.ANY, + ) + + kwargs = ld_client_mock.invoke.mock_calls[0][-1] + payload_bytes = kwargs['Payload'] + payload = json.loads(payload_bytes) + + assert payload['identifier'] == identifier + assert payload['headline'] == headline + assert payload['description'] == description From 75de4abd476c7961a6a62336417ecc5436c6f332 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 15:18:11 +0100 Subject: [PATCH 07/13] clients: cbc_proxy handles lambda invoke response Signed-off-by: Toby Lorne --- app/clients/cbc_proxy.py | 9 +++++++-- tests/app/clients/test_cbc_proxy.py | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 7e3cf6ba4..81f3c7f46 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -52,12 +52,17 @@ class CBCProxyClient: 'description': description, }), encoding='utf8') - self._ld_client.invoke( + result = self._ld_client.invoke( FunctionName='bt-ee-1-proxy', InvocationType='RequestResponse', Payload=payload_bytes, ) - pass + + if result['StatusCode'] > 299: + raise Exception('Could not invoke lambda') + + if 'FunctionError' in result: + raise Exception('Function exited with unhandled exception') # We have not implementated updating a broadcast def update_and_send_broadcast( diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index bc8fe429f..123c1c4ea 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -29,6 +29,7 @@ def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): assert secret == 'cbc-proxy-aws-secret-access-key' + def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): identifier = 'my-identifier' headline = 'my-headline' @@ -40,6 +41,10 @@ def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): create=True, ) + ld_client_mock.invoke.return_value = { + 'StatusCode': 200, + } + cbc_proxy.create_and_send_broadcast( identifier=identifier, headline=headline, From 62951fa0396c26f232cec09083db3ff4dff3eb7e Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 15:18:24 +0100 Subject: [PATCH 08/13] clients: cbc_proxy tests for handling lambda response Signed-off-by: Toby Lorne --- app/clients/cbc_proxy.py | 1 + tests/app/clients/test_cbc_proxy.py | 64 ++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 81f3c7f46..05acadeea 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -2,6 +2,7 @@ import json import boto3 + # Noop = no operation class CBCProxyNoopClient: diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index 123c1c4ea..0d049e60a 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -29,7 +29,6 @@ def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): assert secret == 'cbc-proxy-aws-secret-access-key' - def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): identifier = 'my-identifier' headline = 'my-headline' @@ -64,3 +63,66 @@ def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): assert payload['identifier'] == identifier assert payload['headline'] == headline assert payload['description'] == description + + +def test_cbc_proxy_create_and_send_handles_invoke_error(mocker, cbc_proxy): + identifier = 'my-identifier' + headline = 'my-headline' + description = 'my-description' + + ld_client_mock = mocker.patch.object( + cbc_proxy, + '_ld_client', + create=True, + ) + + ld_client_mock.invoke.return_value = { + 'StatusCode': 400, + } + + with pytest.raises(Exception) as e: + cbc_proxy.create_and_send_broadcast( + identifier=identifier, + headline=headline, + description=description, + ) + + assert e.match('Could not invoke lambda') + + ld_client_mock.invoke.assert_called_once_with( + FunctionName='bt-ee-1-proxy', + InvocationType='RequestResponse', + Payload=mocker.ANY, + ) + + +def test_cbc_proxy_create_and_send_handles_function_error(mocker, cbc_proxy): + identifier = 'my-identifier' + headline = 'my-headline' + description = 'my-description' + + ld_client_mock = mocker.patch.object( + cbc_proxy, + '_ld_client', + create=True, + ) + + ld_client_mock.invoke.return_value = { + 'StatusCode': 200, + 'FunctionError': 'something', + } + + with pytest.raises(Exception) as e: + cbc_proxy.create_and_send_broadcast( + identifier=identifier, + headline=headline, + description=description, + ) + + assert e.match('Function exited with unhandled exception') + + ld_client_mock.invoke.assert_called_once_with( + FunctionName='bt-ee-1-proxy', + InvocationType='RequestResponse', + Payload=mocker.ANY, + ) From a3293d3c8c65d8df151d57c3a5460db95b53ea74 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Tue, 20 Oct 2020 16:43:01 +0100 Subject: [PATCH 09/13] manifest: add cbc proxy env vars Signed-off-by: Toby Lorne Co-authored-by: Katie --- manifest.yml.j2 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/manifest.yml.j2 b/manifest.yml.j2 index f23ec08cd..8085644cd 100644 --- a/manifest.yml.j2 +++ b/manifest.yml.j2 @@ -125,6 +125,11 @@ applications: AWS_ACCESS_KEY_ID: '{{ AWS_ACCESS_KEY_ID }}' AWS_SECRET_ACCESS_KEY: '{{ AWS_SECRET_ACCESS_KEY }}' + {% if CBC_PROXY_AWS_ACCESS_KEY_ID is defined %} + CBC_PROXY_AWS_ACCESS_KEY_ID: '{{ CBC_PROXY_AWS_ACCESS_KEY_ID }}' + CBC_PROXY_AWS_SECRET_ACCESS_KEY: '{{ CBC_PROXY_AWS_SECRET_ACCESS_KEY }}' + {% endif %} + STATSD_HOST: "notify-statsd-exporter-{{ environment }}.apps.internal" ZENDESK_API_KEY: '{{ ZENDESK_API_KEY }}' From 1badf93f0aede87ceae6150e104814e88b69183b Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Thu, 22 Oct 2020 12:11:22 +0100 Subject: [PATCH 10/13] config: correctly get cbc_proxy_client env vars Signed-off-by: Toby Lorne --- app/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/config.py b/app/config.py index 91667bf0f..fedcc811e 100644 --- a/app/config.py +++ b/app/config.py @@ -355,8 +355,8 @@ class Config(object): # CBC Proxy # if the access keys are empty then noop client is used - CBC_PROXY_AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID', '') - CBC_PROXY_AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY', '') + CBC_PROXY_AWS_ACCESS_KEY_ID = os.environ.get('CBC_PROXY_AWS_ACCESS_KEY_ID', '') + CBC_PROXY_AWS_SECRET_ACCESS_KEY = os.environ.get('CBC_PROXY_AWS_SECRET_ACCESS_KEY', '') ###################### From adc2ce82838ba9a138f9b7cc6725573ea7e9af13 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Thu, 22 Oct 2020 12:19:25 +0100 Subject: [PATCH 11/13] clients: cbc_proxy has clarifying comments Signed-off-by: Toby Lorne --- app/clients/cbc_proxy.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 05acadeea..9f990cc38 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -2,6 +2,19 @@ import json import boto3 +# The variable names in this file have specific meaning in a CAP message +# +# identifier is a unique field for each CAP message +# +# headline is a field which we are not sure if we will use +# +# description is the body of the message +# +# references is a whitespace separated list of message identifiers +# where each identifier is a previous sent message +# ie a Cancel message would have a unique identifier but have the identifier of +# the preceeding Alert message in the references field + # Noop = no operation class CBCProxyNoopClient: @@ -13,9 +26,6 @@ class CBCProxyNoopClient: self, identifier, headline, description, ): - # identifier=broadcast_message.identifier, - # headline="GOV.UK Notify Broadcast", - # description=broadcast_message.description, pass # We have not implementated updating a broadcast From c9eb9c8622e4634d6c1231e5aeb722d82cc77fe9 Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Thu, 22 Oct 2020 12:20:31 +0100 Subject: [PATCH 12/13] clients: cbc_proxy client tests remove unused stmt Signed-off-by: Toby Lorne --- tests/app/clients/test_cbc_proxy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index 0d049e60a..705d91c28 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -18,7 +18,6 @@ def cbc_proxy(client, mocker): def test_cbc_proxy_ld_client_has_correct_region(cbc_proxy): assert cbc_proxy._ld_client._client_config.region_name == 'eu-west-2' - pass def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): From ff1ffc7fba70860093beb59cbe56e1dc4faa92dd Mon Sep 17 00:00:00 2001 From: Toby Lorne Date: Thu, 22 Oct 2020 12:22:11 +0100 Subject: [PATCH 13/13] clients: cbc_proxy lambda client is unabbreviated for code clarity Signed-off-by: Toby Lorne --- app/clients/cbc_proxy.py | 4 ++-- tests/app/clients/test_cbc_proxy.py | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/clients/cbc_proxy.py b/app/clients/cbc_proxy.py index 9f990cc38..73db662ba 100644 --- a/app/clients/cbc_proxy.py +++ b/app/clients/cbc_proxy.py @@ -46,7 +46,7 @@ class CBCProxyNoopClient: class CBCProxyClient: def init_app(self, app): - self._ld_client = boto3.client( + self._lambda_client = boto3.client( 'lambda', region_name='eu-west-2', aws_access_key_id=app.config['CBC_PROXY_AWS_ACCESS_KEY_ID'], @@ -63,7 +63,7 @@ class CBCProxyClient: 'description': description, }), encoding='utf8') - result = self._ld_client.invoke( + result = self._lambda_client.invoke( FunctionName='bt-ee-1-proxy', InvocationType='RequestResponse', Payload=payload_bytes, diff --git a/tests/app/clients/test_cbc_proxy.py b/tests/app/clients/test_cbc_proxy.py index 705d91c28..606231f62 100644 --- a/tests/app/clients/test_cbc_proxy.py +++ b/tests/app/clients/test_cbc_proxy.py @@ -16,13 +16,13 @@ def cbc_proxy(client, mocker): return client -def test_cbc_proxy_ld_client_has_correct_region(cbc_proxy): - assert cbc_proxy._ld_client._client_config.region_name == 'eu-west-2' +def test_cbc_proxy_lambda_client_has_correct_region(cbc_proxy): + assert cbc_proxy._lambda_client._client_config.region_name == 'eu-west-2' -def test_cbc_proxy_ld_client_has_correct_keys(cbc_proxy): - key = cbc_proxy._ld_client._request_signer._credentials.access_key - secret = cbc_proxy._ld_client._request_signer._credentials.secret_key +def test_cbc_proxy_lambda_client_has_correct_keys(cbc_proxy): + key = cbc_proxy._lambda_client._request_signer._credentials.access_key + secret = cbc_proxy._lambda_client._request_signer._credentials.secret_key assert key == 'cbc-proxy-aws-access-key-id' assert secret == 'cbc-proxy-aws-secret-access-key' @@ -35,7 +35,7 @@ def test_cbc_proxy_create_and_send_invokes_function(mocker, cbc_proxy): ld_client_mock = mocker.patch.object( cbc_proxy, - '_ld_client', + '_lambda_client', create=True, ) @@ -71,7 +71,7 @@ def test_cbc_proxy_create_and_send_handles_invoke_error(mocker, cbc_proxy): ld_client_mock = mocker.patch.object( cbc_proxy, - '_ld_client', + '_lambda_client', create=True, ) @@ -102,7 +102,7 @@ def test_cbc_proxy_create_and_send_handles_function_error(mocker, cbc_proxy): ld_client_mock = mocker.patch.object( cbc_proxy, - '_ld_client', + '_lambda_client', create=True, )