From 403d232b63a0b504e78e2dc92db44f2f113986c6 Mon Sep 17 00:00:00 2001 From: Buckingham Date: Mon, 9 Dec 2024 10:41:19 +0000 Subject: [PATCH] Update_091224_1 --- terraform/environments/ppud/eventbridge.tf | 25 ++++++++ terraform/environments/ppud/iam.tf | 2 +- terraform/environments/ppud/lambda.tf | 6 +- .../lambda_scripts/ppud_elb_report_prod.py | 59 +++++++++++-------- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/terraform/environments/ppud/eventbridge.tf b/terraform/environments/ppud/eventbridge.tf index eb5cb30e52c..067f3748561 100644 --- a/terraform/environments/ppud/eventbridge.tf +++ b/terraform/environments/ppud/eventbridge.tf @@ -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" { diff --git a/terraform/environments/ppud/iam.tf b/terraform/environments/ppud/iam.tf index 18e4220fe05..4fce3a754f5 100644 --- a/terraform/environments/ppud/iam.tf +++ b/terraform/environments/ppud/iam.tf @@ -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"]}:*" ] } ] diff --git a/terraform/environments/ppud/lambda.tf b/terraform/environments/ppud/lambda.tf index 0603ab0cfe3..b4743fb0732 100644 --- a/terraform/environments/ppud/lambda.tf +++ b/terraform/environments/ppud/lambda.tf @@ -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" } diff --git a/terraform/environments/ppud/lambda_scripts/ppud_elb_report_prod.py b/terraform/environments/ppud/lambda_scripts/ppud_elb_report_prod.py index 2ab6e77d6ce..a0de1784e03 100644 --- a/terraform/environments/ppud/lambda_scripts/ppud_elb_report_prod.py +++ b/terraform/environments/ppud/lambda_scripts/ppud_elb_report_prod.py @@ -1,23 +1,27 @@ +# 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 = 'noreply@internaltest.ppud.justice.gov.uk' RECIPIENTS = ['nick.buckingham@colt.net'] -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" @@ -25,34 +29,40 @@ # 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) @@ -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"""

Hi Team,

-

Please find below the daily PPUD ELB Request Report.

- PPUD ELB Request Report +

Please find below the PPUD Elastic Load Balancer report for {CURRENT_DATE}.

+ PPUD ELB Report

This is an automated email.

@@ -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: