diff --git a/app/celery/provider_tasks.py b/app/celery/provider_tasks.py index f6d6f7847..30bb2e1d8 100644 --- a/app/celery/provider_tasks.py +++ b/app/celery/provider_tasks.py @@ -34,7 +34,13 @@ def check_sms_delivery_receipt(self, message_id, notification_id, sent_at): failure appears in the cloudwatch logs, so this should keep retrying until the log appears, or until we run out of retries. """ - status, provider_response = aws_cloudwatch_client.check_sms(message_id, notification_id, sent_at) + # TODO the localstack version of cloudwatch doesn't have our log groups. Possibly create them with awslocal? + if aws_cloudwatch_client.is_localstack(): + status = 'success' + provider_response = 'this is a fake successful localstack sms message' + else: + status, provider_response = aws_cloudwatch_client.check_sms(message_id, notification_id, sent_at) + if status == 'success': status = NOTIFICATION_DELIVERED elif status == 'failure': diff --git a/app/clients/cloudwatch/aws_cloudwatch.py b/app/clients/cloudwatch/aws_cloudwatch.py index 04e8e995c..eca3c6f01 100644 --- a/app/clients/cloudwatch/aws_cloudwatch.py +++ b/app/clients/cloudwatch/aws_cloudwatch.py @@ -1,4 +1,5 @@ import json +import os import re import time @@ -14,13 +15,26 @@ class AwsCloudwatchClient(Client): """ def init_app(self, current_app, *args, **kwargs): - self._client = client( - "logs", - region_name=cloud_config.sns_region, - aws_access_key_id=cloud_config.sns_access_key, - aws_secret_access_key=cloud_config.sns_secret_key, - config=AWS_CLIENT_CONFIG - ) + if os.getenv("LOCALSTACK_ENDPOINT_URL"): + self._client = client( + "logs", + region_name=cloud_config.sns_region, + aws_access_key_id=cloud_config.sns_access_key, + aws_secret_access_key=cloud_config.sns_secret_key, + config=AWS_CLIENT_CONFIG, + endpoint_url=os.getenv("LOCALSTACK_ENDPOINT_URL") + ) + self._is_localstack = True + else: + self._client = client( + "logs", + region_name=cloud_config.sns_region, + aws_access_key_id=cloud_config.sns_access_key, + aws_secret_access_key=cloud_config.sns_secret_key, + config=AWS_CLIENT_CONFIG + ) + self._is_localstack = False + super(Client, self).__init__(*args, **kwargs) self.current_app = current_app self._valid_sender_regex = re.compile(r"^\+?\d{5,14}$") @@ -29,6 +43,9 @@ class AwsCloudwatchClient(Client): def name(self): return 'cloudwatch' + def is_localstack(self): + return self._is_localstack + def _get_log(self, my_filter, log_group_name, sent_at): # Check all cloudwatch logs from the time the notification was sent (currently 5 minutes previously) until now diff --git a/app/clients/sms/aws_sns.py b/app/clients/sms/aws_sns.py index dbba5e8ff..aa90ef5be 100644 --- a/app/clients/sms/aws_sns.py +++ b/app/clients/sms/aws_sns.py @@ -1,3 +1,4 @@ +import os import re from time import monotonic @@ -16,13 +17,23 @@ class AwsSnsClient(SmsClient): """ def init_app(self, current_app, *args, **kwargs): - self._client = client( - "sns", - region_name=cloud_config.sns_region, - aws_access_key_id=cloud_config.sns_access_key, - aws_secret_access_key=cloud_config.sns_secret_key, - config=AWS_CLIENT_CONFIG - ) + if os.getenv("LOCALSTACK_ENDPOINT_URL"): + self._client = client( + "sns", + region_name=cloud_config.sns_region, + aws_access_key_id=cloud_config.sns_access_key, + aws_secret_access_key=cloud_config.sns_secret_key, + config=AWS_CLIENT_CONFIG, + endpoint_url=os.getenv("LOCALSTACK_ENDPOINT_URL") + ) + else: + self._client = client( + "sns", + region_name=cloud_config.sns_region, + aws_access_key_id=cloud_config.sns_access_key, + aws_secret_access_key=cloud_config.sns_secret_key, + config=AWS_CLIENT_CONFIG, + ) super(SmsClient, self).__init__(*args, **kwargs) self.current_app = current_app self._valid_sender_regex = re.compile(r"^\+?\d{5,14}$") diff --git a/docs/localstack.md b/docs/localstack.md new file mode 100644 index 000000000..d3503ad9a --- /dev/null +++ b/docs/localstack.md @@ -0,0 +1,40 @@ +How to Use Localstack in Your Development Work +================================== + + + +### Install Docker Desktop (One-Time) + +* https://docs.docker.com/desktop/install/mac-install/ + + +### Install Localstack (One-Time) + +* >pip install --upgrade localstack +* >localstack --version + + +### Add LOCALSTACK_ENDPOINT_URL to Your .env File (One-Time) + +* Find the value in the sample.env file. Copy and uncomment it into your .env file + +### Run with Localstack (Recurring) + +#### Start Docker Desktop and localstack image + +* Open Docker Desktop from Finder +* Images->Local->localstack/localstack click on start button on right hand side + + +#### Start Localstack + +* From your project directory in a separate terminal window, either: +* >localstack start +* >pipenv run localstack start + +#### Proceed Normally + +Assuming you followed all these steps and nothing went wrong, you should be running with localstack for SNS now. +You should be able to send an SMS message in the UI and observe it in the dashboard moving from Pending to Delivered +over a period of five minutes. And you should not receive a text message. + diff --git a/sample.env b/sample.env index 643c25c63..9cd957e64 100644 --- a/sample.env +++ b/sample.env @@ -16,6 +16,10 @@ AWS_US_TOLL_FREE_NUMBER=+18556438890 # DATABASE_URL=postgresql://postgres:chummy@db:5432/notification_api # SQLALCHEMY_DATABASE_TEST_URI=postgresql://postgres:chummy@db:5432/test_notification_api + +# If you want to do local development with localstack copy this to your .env file and uncomment it +# LOCALSTACK_ENDPOINT_URL=http://localhost:4566 + # Local direct setup, all overwritten in cloud.gov ADMIN_BASE_URL=http://localhost:6012 API_HOST_NAME=http://localhost:6011