Closed11
SNSの通知をLambdaでわかりやすくする
例えばスポットインスタンスの停止イベントをSNSでメール通知した場合、
このようなメッセージがくる
改行されないjsonですね
これでは見づらいのでLambdaで加工してみます
chatbotに飛ばす場合
いくぶんか見やすくなるのですが、やはりNameタグなりの情報がほしいところ
方針
こちらの記事ではEventBridge→SNS
としましたが、
EventBridge→Lambda→SNS
としてある程度文面を作ろうと思います。
- インスタンスID
- 2分後に停止すること
を通知出来るようにしたいと思います
イメージ図
ポイント
eventbridgeターゲットの指定
snsトピックがターゲットとなっている場合、Lambda関数に変更します。
resource "aws_cloudwatch_event_target" "sns" {
rule = aws_cloudwatch_event_rule.spot-interruption-rule.name
arn = aws_lambda_function.eventbridge-lambda-sns.arn
}
Lambda関数周辺リソースの作成
長いので折りたたみます
lambda.tf
resource "aws_lambda_function" "eventbridge-lambda-sns" {
function_name = "eventbridge-lambda-sns"
handler = "main.lambda_handler"
runtime = "python3.10"
filename = data.archive_file.example_zip.output_path
source_code_hash = data.archive_file.example_zip.output_base64sha256
role = aws_iam_role.lambda_role.arn
environment {
variables = {
SNS_TOPIC = aws_sns_topic.topic.arn
}
}
}
resource "aws_iam_role" "lambda_role" {
name = "example-lambda-role"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
aws_iam_policy.lambda_sns_publish.arn
]
}
resource "aws_iam_policy" "lambda_sns_publish" {
name = "lambda_sns_publish"
path = "/"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "${aws_sns_topic.topic.arn}"
}
]
}
EOF
}
resource "aws_cloudwatch_log_group" "example_log_group" {
name = "/aws/lambda/${aws_lambda_function.eventbridge-lambda-sns.function_name}"
retention_in_days = 30
}
ポイントは
- Lambdaのログを格納するロググループを作成する
- 指定したSNSへpublish出来るようにIAMポリシーを作成する
- SNSトピックの指定には環境変数を用いる
ことです
Lambdaを操作する権限をEventBridgeに与える
aws_lambda_permission
を使うことで、EventBridgeがLambdaを呼び出せるようにします。
リソースポリシーを使用する、というやつです。
resource "aws_lambda_permission" "allow_eventbridge" {
statement_id = "allow_eventbridge"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.eventbridge-lambda-sns.function_name
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.spot-interruption-rule.arn
}
Lambda関数コード
言語はpythonです。長いので折りたたみます
main.py
import json
import os
from datetime import datetime, timedelta, timezone
import boto3
def lambda_handler(event, context):
sns_topic_arn = os.environ.get('SNS_TOPIC')
detail = event['detail']
instance_id = detail['instance-id']
# Parse the termination time and convert it to JST
termination_time_utc = datetime.strptime(event['time'], '%Y-%m-%dT%H:%M:%SZ')
termination_time_jst = termination_time_utc.replace(tzinfo=timezone.utc).astimezone(timezone(timedelta(hours=9)))
# Format the received time without timezone
received_time = termination_time_jst.strftime('%Y-%m-%d %H:%M:%S')
# Add 2 minutes to the termination time
termination_time_jst += timedelta(minutes=2)
# Format the termination time without timezone
termination_time = termination_time_jst.strftime('%Y-%m-%d %H:%M:%S')
# Combine instance ID, received time, and termination time in one message
message = f'Instance ID: {instance_id}\nSpot Interruption Notice: {received_time}\nTermination Time: {termination_time}'
sns = boto3.client('sns')
sns.publish(
TopicArn=sns_topic_arn,
Message=message,
Subject='Spot Instance Interruption Warning'
)
return {
'statusCode': 200,
'body': json.dumps('Success!')
}
ポイントは
- 環境変数でSNSトピックのArnを受け取る
- スポットインスタンス停止通知イベントからインスタンスIDと通知受領時間を受け取る
- pythonの
strftime
でフォーマットを整える - pythonの
timedelta
で2分後の停止予定時刻を作成する - 取得・作成した情報から文面を作成し、SNSでメール通知する
結果
こんな感じでメール通知できます。
このスクラップは2023/06/25にクローズされました