-
Notifications
You must be signed in to change notification settings - Fork 4
feat(ses/domain): cloudwatch metrics and dashboard widgets #75
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
99cee14
docs(ses/domain): added a simple spammer script to generate some SES …
mskrajnowski 56245f4
feat(ses/domain): added a configuration set for cloudwatch metrics
mskrajnowski b287dcb
docs(ses/domain): a slightly more sophisticated spammer using the SES…
mskrajnowski 1270b1f
docs(ses/domain): fixed spammer not triggering rejections
mskrajnowski 90efb37
feat(ses/domain): metrics and widgets scaffold
mskrajnowski 4030370
feat(ses/domain): added per domain metrics and dashboard widgets
mskrajnowski 5a15f6d
fix(cloudwatch/metric): metric ids can't contain dots
mskrajnowski 15e0bda
feat(ses/domain): added account metrics and dashboard widgets
mskrajnowski b70a7ba
refactor(ses/domain): changed rejections color
mskrajnowski 9f5e471
Merge branch 'master' into feat/ses-domain-dashboard
mskrajnowski d24910f
Merge branch 'master' into feat/ses-domain-dashboard
mskrajnowski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #!/bin/sh | ||
|
|
||
| set -e | ||
|
|
||
| image_id=$( | ||
| docker build -q -f - bin <<EOF | ||
| FROM python:3.7-alpine | ||
|
|
||
| RUN pip install boto3 | ||
| ADD ./spammer.py /opt/spammer/spammer.py | ||
| ENTRYPOINT ["python", "/opt/spammer/spammer.py"] | ||
| EOF | ||
| ) | ||
|
|
||
| docker run \ | ||
| -t \ | ||
| --rm \ | ||
| -e AWS_DEFAULT_REGION="eu-west-1" \ | ||
| -e AWS_PROFILE="$AWS_PROFILE" \ | ||
| -e AWS_ACCESS_KEY_ID="$AWS_ACCESS_KEY_ID" \ | ||
| -e AWS_SECRET_ACCESS_KEY="$AWS_SECRET_ACCESS_KEY" \ | ||
| -e SPAMMER_DEFAULT_SENDER="no-reply@$(terraform output domain)" \ | ||
| -e SPAMMER_DEFAULT_CONFIGURATION_SET="$(terraform output configuration_set)" \ | ||
| -v "$HOME/.aws:/root/.aws:ro" \ | ||
| "$image_id" "$@" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,148 @@ | ||
| import argparse | ||
| import os | ||
| import random | ||
| import sys | ||
| import time | ||
| from itertools import count | ||
| from textwrap import dedent | ||
| from email.message import EmailMessage | ||
|
|
||
| import boto3 | ||
|
|
||
| EICAR_TEST_FILE = rb"X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*" | ||
|
|
||
| parser = argparse.ArgumentParser( | ||
| description=""" | ||
| Simple script to generate some SES traffic | ||
| for example cloudwatch dashboards | ||
| """, | ||
| ) | ||
| parser.add_argument( | ||
| "--success", | ||
| type=int, | ||
| default=5, | ||
| help="Successful delivery weight", | ||
| ) | ||
| parser.add_argument( | ||
| "--success-email", | ||
| default="success@simulator.amazonses.com", | ||
| help="Where to send emails which should succeed", | ||
| ) | ||
| parser.add_argument( | ||
| "--bounce", | ||
| type=int, | ||
| default=2, | ||
| help="Hard bounce weight", | ||
| ) | ||
| parser.add_argument( | ||
| "--complaint", | ||
| type=int, | ||
| default=1, | ||
| help="Complaint weight", | ||
| ) | ||
| parser.add_argument( | ||
| "--reject", | ||
| type=int, | ||
| default=1, | ||
| help="Anti-virus rejection weight", | ||
| ) | ||
| parser.add_argument( | ||
| "--reject-email", | ||
| help="Verified email address that should be the recipient of reject emails", | ||
| ) | ||
| parser.add_argument( | ||
| "--interval", | ||
| type=int, | ||
| default=5, | ||
| help="delay in seconds between each email", | ||
| ) | ||
| parser.add_argument( | ||
| "--sender", | ||
| default=os.environ["SPAMMER_DEFAULT_SENDER"], | ||
| help="sender email address", | ||
| ) | ||
| parser.add_argument( | ||
| "--configuration-set", | ||
| default=os.environ["SPAMMER_DEFAULT_CONFIGURATION_SET"], | ||
| help="configuration set to use", | ||
| ) | ||
|
|
||
| def build_email_message(i, args): | ||
| email_type = random.choices( | ||
| population=["success", "bounce", "complaint", "reject"], | ||
| weights=[args.success, args.bounce, args.complaint, args.reject], | ||
| k=1, | ||
| )[0] | ||
|
|
||
| email_message = EmailMessage() | ||
| email_message["subject"] = f"{email_type} email" | ||
| email_message["from"] = args.sender | ||
| email_message["to"] = getattr( | ||
| args, | ||
| f"{email_type}_email", | ||
| f"{email_type}@simulator.amazonses.com", | ||
| ) | ||
| email_message["X-SES-CONFIGURATION-SET"] = args.configuration_set | ||
|
|
||
| email_message.set_content( | ||
| dedent( | ||
| f""" | ||
| {email_type} email {i} | ||
| https://github.com/codequest-eu/terraform-modules | ||
| """ | ||
| ), | ||
| subtype="plain", | ||
| ) | ||
|
|
||
| email_message.add_alternative( | ||
| dedent( | ||
| f""" | ||
| <!DOCTYPE html> | ||
| <html> | ||
| <body> | ||
| <p>{email_type} email {i}</p> | ||
| <p><a href="https://github.com/codequest-eu/terraform-modules">codequest-eu/terraform-modules</a></p> | ||
| </body> | ||
| </html> | ||
| """ | ||
| ), | ||
| subtype="html", | ||
| ) | ||
|
|
||
| if email_type == "reject": | ||
| email_message.add_attachment( | ||
| EICAR_TEST_FILE, | ||
| filename="sample.txt", | ||
| maintype="application", | ||
| subtype="octet-stream", | ||
| ) | ||
|
|
||
| return email_message | ||
|
|
||
| def main(): | ||
| args = parser.parse_args() | ||
|
|
||
| if args.reject and not args.reject_email: | ||
| print("You have to specify --reject-email or disable reject emails with --reject 0") | ||
| sys.exit(1) | ||
|
|
||
| ses = boto3.client("ses") | ||
|
|
||
| print(f"Will start sending emails from {args.sender} every {args.interval} seconds") | ||
|
|
||
| for i in count(start=1): | ||
| time.sleep(args.interval) | ||
|
|
||
| email_message = build_email_message(i, args) | ||
| subject = email_message["subject"] | ||
| recipient = email_message["to"] | ||
|
|
||
| print(f"Sending {subject} to {recipient}...") | ||
| message_id = ses.send_raw_email( | ||
| RawMessage=dict(Data=email_message.as_bytes()), | ||
| )["MessageId"] | ||
| print(f"Sent {message_id}") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| locals { | ||
| metrics = { | ||
| emails = module.metrics_count.out_map.sent | ||
| rejections = module.metrics_count.out_map.rejections | ||
| bounces = module.metrics_count.out_map.bounces | ||
| spam = module.metrics_count.out_map.spam | ||
| deliveries = module.metrics_count.out_map.deliveries | ||
| opens = module.metrics_count.out_map.opens | ||
| clicks = module.metrics_count.out_map.clicks | ||
|
|
||
| rejections_percentage = module.metrics_percentage.out_map.rejections | ||
| bounces_percentage = module.metrics_percentage.out_map.bounces | ||
| deliveries_percentage = module.metrics_percentage.out_map.deliveries | ||
|
|
||
| account_bounce_rate = module.metrics_account_reputation.out_map.bounce | ||
| account_spam_rate = module.metrics_account_reputation.out_map.spam | ||
| } | ||
| } | ||
|
|
||
| module "cloudwatch_consts" { | ||
| source = "./../../cloudwatch/consts" | ||
| } | ||
|
|
||
| locals { | ||
| colors = module.cloudwatch_consts.colors | ||
| } | ||
|
|
||
| locals { | ||
| domain_dimensions = { | ||
| "ses:from-domain" = local.domain | ||
| } | ||
|
|
||
| metrics_count = { | ||
| sent = { name = "Send", label = "Sent", color = local.colors.grey } | ||
| rejections = { name = "Reject", label = "Rejections", color = local.colors.red } | ||
| bounces = { name = "Bounce", label = "Bounces", color = local.colors.orange } | ||
| spam = { name = "Complaint", label = "Marked as spam", color = local.colors.red } | ||
| deliveries = { name = "Delivery", label = "Deliveries", color = local.colors.green } | ||
| opens = { name = "Open", label = "Opens", color = local.colors.light_green } | ||
| clicks = { name = "Click", label = "Link clicks", color = local.colors.green } | ||
| } | ||
| } | ||
|
|
||
| module "metrics_count" { | ||
| source = "./../../cloudwatch/metric/many" | ||
|
|
||
| vars_map = { for k, v in local.metrics_count : k => { | ||
| namespace = "AWS/SES" | ||
| dimensions = local.domain_dimensions | ||
| name = v.name | ||
| label = v.label | ||
| color = v.color | ||
| stat = "SampleCount" | ||
| period = 300 | ||
| } } | ||
| } | ||
|
|
||
| module "metrics_percentage" { | ||
| source = "./../../cloudwatch/metric_expression/many" | ||
|
|
||
| vars_map = { for k, v in local.metrics_count : k => { | ||
| expression = "100 * ${module.metrics_count.out_map[k].id} / FILL(${module.metrics_count.out_map.sent.id}, 1)" | ||
| label = v.label | ||
| color = v.color | ||
| } } | ||
| } | ||
|
|
||
| locals { | ||
| metrics_reputation = { | ||
| bounce = { name = "Bounce", label = "Bounce" } | ||
| spam = { name = "Complaint", label = "Spam" } | ||
| } | ||
| } | ||
|
|
||
| module "metrics_account_reputation" { | ||
| source = "./../../cloudwatch/metric/many" | ||
|
|
||
| vars_map = { for k, v in local.metrics_reputation : k => { | ||
| namespace = "AWS/SES" | ||
| name = "Reputation.${v.name}Rate" | ||
| label = "${v.label} rate" | ||
| stat = "Average" | ||
| period = 3600 | ||
| } } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Too few colors ;) I understand that this is not a problem - they will not be presented in the same widget?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm using
greyto signify the desired/expected values, in this casesentis the desired value for thedeliveredmetric, so that's the logic behind makingsentgrey