Skip to content

Commit

Permalink
Merge pull request #9014 from ministryofjustice/Update_091224_1
Browse files Browse the repository at this point in the history
Update_091224_1
  • Loading branch information
nbuckingham72 authored Dec 9, 2024
2 parents 64ea0a8 + 403d232 commit dfa4552
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 28 deletions.
25 changes: 25 additions & 0 deletions terraform/environments/ppud/eventbridge.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ resource "aws_cloudwatch_event_target" "trigger_lambda_target_send_cpu_graph_pro
arn = aws_lambda_function.terraform_lambda_func_send_cpu_graph_prod[0].arn
}

# Eventbridge rule to invoke the PPUD ELB report lambda function every weekday at 20:15

resource "aws_lambda_permission" "allow_eventbridge_invoke_ppud_elb_report_prod" {
count = local.is-production == true ? 1 : 0
statement_id = "AllowEventBridgeInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.terraform_lambda_func_ppud_elb_report_prod[0].function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.daily_schedule_ppud_elb_report_prod[0].arn
}

resource "aws_cloudwatch_event_rule" "daily_schedule_ppud_elb_report_prod" {
count = local.is-production == true ? 1 : 0
name = "ppud-elb-report-daily-weekday-schedule"
description = "Trigger Lambda at 20:15 UTC on weekdays"
schedule_expression = "cron(15 20 ? * MON-FRI *)"
}

resource "aws_cloudwatch_event_target" "trigger_lambda_target_ppud_elb_report_prod" {
count = local.is-production == true ? 1 : 0
rule = aws_cloudwatch_event_rule.daily_schedule_ppud_elb_report_prod[0].name
target_id = "ppud_elb_report"
arn = aws_lambda_function.terraform_lambda_func_ppud_elb_report_prod[0].arn
}

# Eventbridge rule to invoke the PPUD Email Report lambda function every Monday at 07:00

resource "aws_lambda_permission" "allow_eventbridge_invoke_ppud_email_report_prod" {
Expand Down
2 changes: 1 addition & 1 deletion terraform/environments/ppud/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,7 @@ resource "aws_iam_policy" "iam_policy_for_lambda_cloudwatch_get_metric_data_prod
"sqs:SendMessage"
],
"Resource" : [
"arn:aws:sqs:eu-west-2:${local.environment_management.account_ids["ppud-production"]}:Lambda-Queue-Production"
"arn:aws:sqs:eu-west-2:${local.environment_management.account_ids["ppud-production"]}:*"
]
}
]
Expand Down
6 changes: 3 additions & 3 deletions terraform/environments/ppud/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -580,9 +580,9 @@ resource "aws_lambda_function" "terraform_lambda_func_ppud_elb_report_prod" {
depends_on = [aws_iam_role_policy_attachment.attach_lambda_policy_cloudwatch_get_metric_data_to_lambda_role_cloudwatch_get_metric_data_prod]
reserved_concurrent_executions = 5
# code_signing_config_arn = "arn:aws:lambda:eu-west-2:${local.environment_management.account_ids["ppud-production"]}:code-signing-config:csc-0bafee04a642a41c1"
# dead_letter_config {
# target_arn = aws_sqs_queue.lambda_queue_prod[0].arn
# }
dead_letter_config {
target_arn = aws_sqs_queue.lambda_queue_prod[0].arn
}
tracing_config {
mode = "Active"
}
Expand Down
59 changes: 35 additions & 24 deletions terraform/environments/ppud/lambda_scripts/ppud_elb_report_prod.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,68 @@
# Python script to retrieve elastic load balancer data from cloudwatch, count the connections per 15 minutes
# graph it and email it to end users via the internal mail relay.
# Nick Buckingham
# 9 December 2024

import boto3
import os
os.environ['MPLCONFIGDIR'] = "/tmp/graph"
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
import io
import base64
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from botocore.exceptions import NoCredentialsError, PartialCredentialsError
import base64
import smtplib

# Configuration
CURRENT_DATE = datetime.now().strftime('%a %d %b %Y')
SENDER = '[email protected]'
RECIPIENTS = ['[email protected]']
SUBJECT = f'AWS Daily PPUD ELB Request Report - {CURRENT_DATE}'
SUBJECT = f'AWS PPUD Load Balancer Report - {CURRENT_DATE}'
AWS_REGION = 'eu-west-2'
ELB_NAME = "PPUD-ALB" # Replace with your ELB name
ELB_NAME = "app/PPUD-ALB/9d129853721723f4" # Replace with your ELB name

# SMTP Configuration
SMTP_SERVER = "10.27.9.39"
SMTP_PORT = 25

# Initialize AWS clients
cloudwatch = boto3.client("cloudwatch", region_name=AWS_REGION)
ses = boto3.client("ses", region_name=AWS_REGION)
#ses = boto3.client("ses", region_name=AWS_REGION)

def get_hourly_request_counts(elb_name):
def get_elb_request_counts(ELB_NAME):
"""Fetches daily connection counts for the ELB from CloudWatch."""
# Calculate the start and end time for the day
#start_time = datetime(2024, 12, 8, 6, 0, 0) # 08:00 UTC, 28 Nov 2024
#end_time = datetime(2024, 12, 8, 20, 10, 0) # 17:00 UTC, 28 Nov 2024
current_time = datetime.utcnow()
end_time = datetime.utcnow()
start_time = end_time - timedelta(days=1) # Fetch data for the last 1 day
start_time = end_time - timedelta(hours=14)

response = cloudwatch.get_metric_statistics(
Namespace="AWS/ELB",
Namespace="AWS/ApplicationELB",
MetricName="RequestCount",
Dimensions=[
{"Name": "LoadBalancerName", "Value": elb_name}
{"Name": "LoadBalancer", "Value": ELB_NAME},
# {'Name': 'TargetGroup', 'Value': 'PPUD'},
# {'Name': 'AvailabilityZone', 'Value': 'eu-west-2c'}
],
StartTime=start_time,
EndTime=end_time,
Period=3600, # Daily period
Period=900, # 15 minute intervals
Statistics=["Sum"]
)

data_points = sorted(response["Datapoints"], key=lambda x: x["Timestamp"])
return [(dp["Timestamp"].strftime('%H:%M'), dp["Sum"]) for dp in data_points]

def plot_graph(request_data):
"""Plots the graph of hourly requests and returns it as an in-memory file."""
def create_graph(request_data):
"""Plots the graph of requests and returns it as an in-memory file."""
times, requests = zip(*request_data)
plt.figure(figsize=(20, 6))
plt.bar(times, requests, color="blue")
plt.title(f"Hourly Requests to {ELB_NAME} Over the Last 24 Hours")
plt.plot(times, requests, color="blue")
plt.title(f"Requests to the PPUD Load Balancer on {CURRENT_DATE} (Every 15 Minutes)")
plt.xlabel("Time (UTC)")
plt.ylabel("Number of Requests")
plt.xticks(rotation=45)
Expand All @@ -77,20 +87,19 @@ def plot_graph(request_data):
os.remove(temp_file)
return encoded_string

# Function to send an email via SES
def send_email_with_graph(graph_base64):
def email_image_to_users(graph_base64):
"""
Send an email with the graph embedded in the email body using AWS SES.
"""
cloudwatch = boto3.client("cloudwatch", region_name=AWS_REGION)
ses_client = boto3.client("ses", region_name=AWS_REGION)

# Email body with the embedded image
email_body = f"""
<html>
<body>
<p>Hi Team,</p>
<p>Please find below the daily PPUD ELB Request Report.</p>
<img src="data:image/png;base64,{graph_base64}" alt="PPUD ELB Request Report" />
<p>Please find below the PPUD Elastic Load Balancer report for {CURRENT_DATE}.</p>
<img src="data:image/png;base64,{graph_base64}" alt="PPUD ELB Report" />
<p>This is an automated email.</p>
</body>
</html>
Expand Down Expand Up @@ -126,20 +135,22 @@ def send_email_with_graph(graph_base64):
print("Email sent successfully.")
except Exception as e:
print(f"Error sending email: {e}")


def lambda_handler(event, context):
try:
# Get hourly request counts
request_data = get_hourly_request_counts(ELB_NAME)
request_data = get_elb_request_counts(ELB_NAME)
if not request_data:
print("No data found for the specified ELB.")
return

# Create graph
temp_file = plot_graph(request_data)
#temp_file = plot_graph(request_data)
graph_base64 = create_graph(request_data)

# Send email
send_email_with_graph(SENDER, temp_file)
email_image_to_users(graph_base64)
print("Process completed successfully.")

except (NoCredentialsError, PartialCredentialsError) as cred_error:
Expand Down

0 comments on commit dfa4552

Please sign in to comment.