Skip to content

Commit

Permalink
Merge pull request #8760 from ministryofjustice/Update_221124_2
Browse files Browse the repository at this point in the history
Update_221124_2
  • Loading branch information
nbuckingham72 authored Nov 22, 2024
2 parents 755c829 + 492184c commit b8a988a
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 1 deletion.
60 changes: 59 additions & 1 deletion terraform/environments/ppud/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1138,4 +1138,62 @@ resource "aws_iam_role_policy_attachment" "attach_aws_signer_policy_to_aws_signe
count = local.is-development == true ? 1 : 0
role = aws_iam_role.aws_signer_role_dev[0].name
policy_arn = aws_iam_policy.aws_signer_policy_dev[0].arn
}
}

#############################################
# IAM Role & Policy for Send CPU graph - DEV
#############################################

resource "aws_iam_role" "lambda_role_cloudwatch_get_metric_data_dev" {
count = local.is-development == true ? 1 : 0
name = "PPUD_Lambda_Function_Role_Cloudwatch_Get_Metric_Data_Dev"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}

resource "aws_iam_policy" "iam_policy_for_lambda_cloudwatch_get_metric_data_dev" {
count = local.is-development == true ? 1 : 0
name = "aws_iam_policy_for_terraform_aws_lambda_role_cloudwatch_get_metric_data_dev"
path = "/"
description = "AWS IAM Policy for managing aws lambda role cloudwatch get_metric_data development"
policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [{
"Effect" : "Allow",
"Action" : [
"cloudwatch:GetMetricData"
],
"Resource" : [
"arn:aws:ssm:eu-west-2:${local.environment_management.account_ids["ppud-development"]}:*"
]
},
{
"Effect" : "Allow",
"Action" : [
"ses:SendEmail"
],
"Resource" : [
"arn:aws:sqs:eu-west-2:${local.environment_management.account_ids["ppud-development"]}:*"
]
}]
})
}

resource "aws_iam_role_policy_attachment" "attach_lambda_policy_cloudwatch_get_metric_data_to_lambda_role_cloudwatch_get_metric_data_dev" {
count = local.is-development == true ? 1 : 0
role = aws_iam_role.lambda_role_cloudwatch_get_metric_data_dev[0].name
policy_arn = aws_iam_policy.iam_policy_for_lambda_cloudwatch_get_metric_data_dev[0].arn
}
42 changes: 42 additions & 0 deletions terraform/environments/ppud/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -481,3 +481,45 @@ data "archive_file" "zip_the_send_cpu_notification_code_prod" {
source_dir = "${path.module}/lambda_scripts/"
output_path = "${path.module}/lambda_scripts/send_cpu_notification_prod.zip"
}

################################################
# Lambda Function to graph CPU Utilization - DEV
################################################

resource "aws_lambda_permission" "allow_cloudwatch_to_call_lambda_send_cpu_graph_dev" {
count = local.is-development == true ? 1 : 0
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.terraform_lambda_func_send_cpu_graph_dev[0].function_name
principal = "lambda.alarms.cloudwatch.amazonaws.com"
source_arn = "arn:aws:cloudwatch:eu-west-2:${local.environment_management.account_ids["ppud-development"]}:alarm:*"
}

resource "aws_lambda_function" "terraform_lambda_func_send_cpu_graph_dev" {
# checkov:skip=CKV_AWS_117: "PPUD Lambda functions do not require VPC access and can run in no-VPC mode"
count = local.is-development == true ? 1 : 0
filename = "${path.module}/lambda_scripts/send_cpu_graph_dev.zip"
function_name = "send_cpu_graph"
role = aws_iam_role.lambda_role_cloudwatch_get_metric_data_dev[0].arn
handler = "send_cpu_graph_dev.lambda_handler"
runtime = "python3.12"
timeout = 300
depends_on = [aws_iam_role_policy_attachment.attach_lambda_policy_cloudwatch_invoke_lambda_to_lambda_role_cloudwatch_invoke_lambda_dev]
reserved_concurrent_executions = 5
# code_signing_config_arn = "arn:aws:lambda:eu-west-2:${local.environment_management.account_ids["ppud-development"]}:code-signing-config:csc-0c7136ccff2de748f"
dead_letter_config {
target_arn = aws_sqs_queue.lambda_queue_dev[0].arn
}
tracing_config {
mode = "Active"
}
}

# Archive the zip file

data "archive_file" "zip_the_send_cpu_graph_code_dev" {
count = local.is-development == true ? 1 : 0
type = "zip"
source_dir = "${path.module}/lambda_scripts/"
output_path = "${path.module}/lambda_scripts/send_cpu_graph_dev.zip"
}
101 changes: 101 additions & 0 deletions terraform/environments/ppud/lambda_scripts/send_cpu_graph_dev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import boto3
import datetime
import matplotlib.pyplot as plt
import io
import base64
from botocore.exceptions import ClientError

# Initialize clients
cloudwatch = boto3.client('cloudwatch')
ses = boto3.client('ses')

def lambda_handler(event, context):
# 1. Define parameters
instance_id = event.get('InstanceId', 'i-0c98db0c20242e12c') # Replace with your instance ID
email_recipient = event.get('RecipientEmail', '[email protected]') # Replace with recipient email
email_sender = '[email protected]' # Replace with a verified SES sender email
region = 'eu-west-2' # Replace with your AWS region

# 2. Fetch CPU Utilization data from CloudWatch
try:
response = cloudwatch.get_metric_data(
MetricDataQueries=[
{
'Id': 'cpuUtilization',
'MetricStat': {
'Metric': {
'Namespace': 'AWS/EC2',
'MetricName': 'CPUUtilization',
'Dimensions': [{'Name': 'InstanceId', 'Value': instance_id}]
},
'Period': 300, # 5 minutes
'Stat': 'Average'
},
'ReturnData': True
}
],
StartTime=datetime.datetime.utcnow() - datetime.timedelta(hours=168),
EndTime=datetime.datetime.utcnow()
)
except ClientError as e:
print(f"Error fetching CloudWatch data: {e}")
return {'statusCode': 500, 'body': str(e)}

# 3. Process data for graphing
timestamps = []
values = []
for data_point in response['MetricDataResults'][0]['Timestamps']:
timestamps.append(data_point)
for data_point in response['MetricDataResults'][0]['Values']:
values.append(data_point)

# Sort data by timestamps
sorted_data = sorted(zip(timestamps, values))
timestamps, values = zip(*sorted_data)

# 4. Generate a graph
plt.figure(figsize=(10, 6))
plt.plot(timestamps, values, label="CPU Utilization", marker='o')
plt.xlabel('Time')
plt.ylabel('CPU Utilization (%)')
plt.title(f'CPU Utilization for {instance_id}')
plt.legend()
plt.grid(True)

# Save the graph to memory
image_buffer = io.BytesIO()
plt.savefig(image_buffer, format='png')
image_buffer.seek(0)

# Convert to base64 for email attachment
graph_base64 = base64.b64encode(image_buffer.getvalue()).decode('utf-8')
image_buffer.close()

# 5. Send the email via SES
email_subject = f"CPU Utilization Graph for {instance_id}"
email_body = (
f"Attached is the CPU Utilization graph for the EC2 instance {instance_id} "
f"for the past week. \n\nBest regards,\nYour Monitoring Team"
)

email_html_body = (
f"<html><body><p>{email_body}</p><img src='data:image/png;base64,{graph_base64}'/></body></html>"
)

try:
ses.send_email(
Source=email_sender,
Destination={'ToAddresses': [email_recipient]},
Message={
'Subject': {'Data': email_subject},
'Body': {
'Html': {'Data': email_html_body}
}
}
)
print(f"Email sent successfully to {email_recipient}")
except ClientError as e:
print(f"Error sending email: {e}")
return {'statusCode': 500, 'body': str(e)}

return {'statusCode': 200, 'body': 'Email sent successfully'}

0 comments on commit b8a988a

Please sign in to comment.