separate cbc proxy into separate clients

this is a pretty big and convoluted refactor unfortunately.

Previously:

There was one global `cbc_proxy_client` object in apps. This class has
the information about how to invoke the bt-ee lambda, and handles all
calls to lambda. This includes calls to the canary too (which is a
separate lambda).

The future:

There's one global `cbc_proxy_client`. This knows about the different
provider functions and lambdas, and you'll need to ask this client for a
proxy for your chosen provider. call cbc_proxy_client.get_proxy('ee')`
and it'll return you a proxy that knows what ee's lambda function is,
how to transform any content in a way that is exclusive to ee, and in
future how to parse any response from ee.

The present:

I also cleaned up some duplicate tests.
I'm really not sure about the names of some of these variables - in
particular `cbc_proxy_client` isn't a client - it's more of a java style
factory, where you call a function on it to get the client of your
choice.
This commit is contained in:
Leo Hemsted
2020-11-17 12:35:22 +00:00
parent 0257774cfa
commit 087cc5053d
7 changed files with 110 additions and 193 deletions

View File

@@ -1,6 +1,7 @@
import json
import boto3
from flask import current_app
from app.config import BroadcastProvider
@@ -16,9 +17,8 @@ from app.config import BroadcastProvider
# * description is a string which populates the areaDesc field
# * polygon is a list of lat/long pairs
#
# previous_provider_messages 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
# previous_provider_messages is a list of previous events (models.py::BroadcastProviderMessage)
# ie a Cancel message would have a unique event but have the event of
# the preceeding Alert message in the previous_provider_messages field
@@ -26,11 +26,31 @@ class CBCProxyException(Exception):
pass
# Noop = no operation
class CBCProxyNoopClient:
class CBCProxyClient:
_lambda_client = None
def init_app(self, app):
pass
if app.config.get('CBC_PROXY_AWS_ACCESS_KEY_ID'):
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 get_proxy(self, provider):
proxy_classes = {
'canary': CBCProxyCanary,
BroadcastProvider.EE: CBCProxyEE,
}
return proxy_classes[provider](self._lambda_client)
class CBCProxyClientBase:
lambda_name = None
def __init__(self, lambda_client):
self._lambda_client = lambda_client
def send_canary(
self,
@@ -67,25 +87,17 @@ class CBCProxyNoopClient:
):
pass
def _invoke_lambda(self, payload):
if not self.lambda_name:
current_app.logger.warning(
'{self.__class__.__name__} tried to send {payload} but cbc proxy aws env vars not set'
)
return
class CBCProxyClient:
provider_function_name_map = {
BroadcastProvider.EE: 'bt-ee-1-proxy',
}
def init_app(self, app):
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 _invoke_lambda(self, function_name, payload):
payload_bytes = bytes(json.dumps(payload), encoding='utf8')
result = self._lambda_client.invoke(
FunctionName=function_name,
FunctionName=self.lambda_name,
InvocationType='RequestResponse',
Payload=payload_bytes,
)
@@ -98,15 +110,23 @@ class CBCProxyClient:
return result
class CBCProxyCanary(CBCProxyClientBase):
"""
The canary is a lambda which tests notify's connectivity to the Cell Broadcast AWS infrastructure. It calls the
canary, a specific lambda that does not open a vpn or connect to a provider but just responds from within AWS.
"""
lambda_name = 'canary'
def send_canary(
self,
identifier,
):
"""
canary - a specific lambda that does not connect to a provider, but just confirms the connectivity between
Notify and the CBC proxy AWS account
"""
self._invoke_lambda(function_name='canary', payload={'identifier': identifier})
self._invoke_lambda(payload={'identifier': identifier})
class CBCProxyEE(CBCProxyClientBase):
lambda_name = 'bt-ee-1-proxy'
def send_link_test(
self,
@@ -118,7 +138,7 @@ class CBCProxyClient:
"""
payload = {'message_type': 'test', 'identifier': identifier}
self._invoke_lambda(function_name='bt-ee-1-proxy', payload=payload)
self._invoke_lambda(payload=payload)
def create_and_send_broadcast(
self,
@@ -134,20 +154,4 @@ class CBCProxyClient:
'sent': sent,
'expires': expires,
}
self._invoke_lambda(function_name='bt-ee-1-proxy', payload=payload)
# We have not implementated updating a broadcast
def update_and_send_broadcast(
self,
identifier, previous_provider_messages, headline, description, areas,
sent, expires,
):
pass
# We have not implemented cancelling a broadcast
def cancel_broadcast(
self,
identifier, previous_provider_messages, headline, description, areas,
sent, expires,
):
pass
self._invoke_lambda(payload=payload)