Files
notifications-api/app/clients/cbc_proxy.py
Toby Lorne 052de84c9e clients: cbc_proxy client has canary method
The CBC Proxy is essentially a lambda function which we invoke with
various arguments.

A way in which this can fail is that the notifications-api app invoking
the function may not be able, any longer, to invoke the function.

This could be caused by, for example:
* an egress restriction preventing access to eu-west-2.lambda.amazonaws.com
* a network partition preventing access to eu-west-2.lambda.amazonaws.com
* the app's credentials have been rotated or revoked

If we invoke a simple "canary" lambda function for which the app should
have access to invoke, and check it for failures, we will know quickly
if something is likely to be broken.

This is especially important for cell broadcasts compared to email/SMS
because we always have a baseline of traffic for email/SMS, and so any
failure is observed almost immediately. This is not true for CB where we
may expect to only see one CB message every week/month/quarter/year, as
opposed to every minute or second for email/SMS.

Signed-off-by: Toby Lorne <toby.lornewelch-richards@digital.cabinet-office.gov.uk>
Co-authored-by: Pea <pea.tyczynska@digital.cabinet-office.gov.uk>
2020-10-26 17:14:08 +00:00

122 lines
3.2 KiB
Python

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
# areas is a list of dicts, with the following items
# * description is a string which populates the areaDesc field
# * polygon is a list of lat/long pairs
#
# 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:
def init_app(self, app):
pass
def send_canary(
self,
identifier,
):
pass
def create_and_send_broadcast(
self,
identifier, headline, description, areas
):
pass
# We have not implementated updating a broadcast
def update_and_send_broadcast(
self,
identifier, references, headline, description, areas
):
pass
# We have not implemented cancelling a broadcast
def cancel_broadcast(
self,
identifier, references, headline, description, areas
):
pass
class CBCProxyClient:
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 send_canary(
self,
identifier,
):
payload_bytes = bytes(json.dumps({
'identifier': identifier,
}), encoding='utf8')
result = self._lambda_client.invoke(
FunctionName='canary',
InvocationType='RequestResponse',
Payload=payload_bytes,
)
if result['StatusCode'] > 299:
raise Exception('Could not invoke lambda')
if 'FunctionError' in result:
raise Exception('Function exited with unhandled exception')
def create_and_send_broadcast(
self,
identifier, headline, description, areas,
):
payload_bytes = bytes(json.dumps({
'identifier': identifier,
'headline': headline,
'description': description,
'areas': areas,
}), encoding='utf8')
result = self._lambda_client.invoke(
FunctionName='bt-ee-1-proxy',
InvocationType='RequestResponse',
Payload=payload_bytes,
)
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(
self,
identifier, references, headline, description, areas,
):
pass
# We have not implemented cancelling a broadcast
def cancel_broadcast(
self,
identifier, references, headline, description, areas,
):
pass