S3のファイル操作イベントをLambdaとWebhook使ってDiscordに通知するやつ
TL;DR
目的
- S3 でファイル操作(追加・削除等)がされる度に通知してほしかった
- Lambda と Webhook を使った通知を作った
- 通知先は Discord
つくったもの
構成
ソースコード
想定
- AWS アカウントを作成済み
- AWS CLI をローカル環境にインストール・configure の設定済み
(インストール方法について前回の記事で少しだけ触れています)
1. S3 でバケットを作成
通常通りにバケットを作成します。
既存のバケットを用いる場合は、すべて読み飛ばして「手順 2: 通知用の Webhook を作成する」に進みます。
-
S3 のコンソール(https://s3.console.aws.amazon.com/)にアクセスします。
-
左側のダッシュボードから[Buckets]を選択し、[Create bucket]をクリックします。
-
バケットの情報を入力して[Create Bucket]をクリックします。
- Bucket name: バケット名
- s3-notification-test-satory074(任意の一意な名前を入力)
- Bucket name: バケット名
2. 通知用の Webhook を作成する
通知先となる Discord のチャンネルの Webhook を用意します。
以前の記事の「手順 4: Slack の Webhook URL を取得する」で解説しています。
(Slack 用の手順を Discord 用の手順へ書き換えを行った記事です)
作成した Webhook URL を控えたらこの手順は終了です。
3. 通知用の Lambda を作成する
通知処理を行う Lambda を作成します。
こちらも以前の記事の「手順 5: Lambda を作る」とほぼ同じですが、本記事用に書き換えながら簡単に同じ手順を記載します。
3.1 プログラムを用意する
冒頭でも載せましたが、ソースコードは以下になります。
3.1.0 lambda_function.json
ソースコードについて少し説明させてください。読み飛ばしても大丈夫です。
colors = {
"ObjectCreated:CompleteMultipartUpload": 0x008000,
"ObjectCreated:Put": 0x008000,
"ObjectCreated:Post": 0x008000,
"ObjectCreated:Copy": 0x008B8B,
"ObjectRemoved:Delete": 0xFF6347,
"ObjectRemoved:DeleteMarkerCreated": 0xFF6347,
}
event["Records"]["eventName"]
(追加したよとか削除したよとかいうファイル操作の種類)に対応する、Discord の通知メッセージの左側の線の色を決めています。
for rec in event["Records"]:
color = colors[rec["eventName"]] if rec["eventName"] in colors else 0x000000
size = (
convert_size(rec["s3"]["object"]["size"])
if "size" in rec["s3"]["object"]
else ""
)
# Webhook data
data = {
"username": rec["eventSource"], # イベントソース(aws:s3)
"avatar_url": "https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/main/dist/Storage/SimpleStorageService.png", # S3のアイコン(っぽいやつ)
"embeds": [
{
"title": rec["s3"]["object"]["key"], # ファイル名
"description": size, # ファイルサイズ
"color": color, # 通知メッセージの色
"timestamp": rec["eventTime"], # タイムスタンプ
"footer": {"text": rec["eventName"]}, # イベント名
"fields": [
{ # リージョン
"name": "awsRegion",
"value": rec["awsRegion"],
"inline": True,
},
{ # バケット名
"name": "bucket",
"value": rec["s3"]["bucket"]["name"],
"inline": True,
},
],
}
],
}
# POST
requests.post(
WEBHOOK_URL, json.dumps(data), headers={"Content-Type": "application/json"},
)
Records
ごとに「データ取得」「通知の Post」を行っています。
size
については後述します。
data
は Webhook で POST される通知メッセージのデータです。
通知メッセージの各値の意味や編集については、以下の記事を参考にしましたので、興味がある方は色々カスタマイズしてみてください。
event
が、S3 でファイル操作された情報ですが、ここでは(すべて正確に網羅する自信がないので)説明を割愛をしますので、興味がある方は別のサイトを調べたり、実際にevent
の中身を出力しまくってみてください。
event
の一例だけ添えておきます。
{
"Records": [{
"eventVersion": "2.1",
"eventSource": "aws:s3",
"awsRegion": "ap-northeast-1",
"eventTime": "2022-11-14T12:21:32.108Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "XXXXXXXXXXXX"
},
"requestParameters": {
"sourceIPAddress": "xxx.xxx.xxx.xxx"
},
"responseElements": {
"x-amz-request-id": "XXXXXXXXXXXXXXXX",
"x-amz-id-2": "xxxx"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "s3-to-discord",
"bucket": {
"name": "s3-notification-test-satory074",
"ownerIdentity": {
"principalId": "XXXXXXXXXXXXXXXX"
},
"arn": "arn:aws:s3:::s3-notification-test-satory074"
},
"object": {
"key": "Figure_1.png",
"size": 1024,
"eTag": "xxxx",
"versionId": "xxxx",
"sequencer": "XXXXXXXXXXXXXXXXXXXXX"
}
}
}
]
}
# 参考: https://pystyle.info/python-data-size-conversion/
def convert_size(size):
""" Convert size to readable format """
units = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB")
i = math.floor(math.log(size, 1024)) if size > 0 else 0
size = round(size / 1024 ** i, 2)
return f"{size} {units[i]}"
size
(ファイルサイズ)がバイトなので、適切な単位に変換を行っています。
3.1.1 lambda.json
データ構造
JSON Key | 内容 | 書き換え | 備考 | |
---|---|---|---|---|
name | Lambda の関数名 | 任意の 名前でも OK です | ||
description | Lambda の関数の説明 | |||
runtime | ランタイム | |||
region | Lambda を作成するリージョン | |||
handler | ハンドラ | |||
role | 関数のロール | 必要 | ロールの ARN | |
timeout | タイムアウト | |||
memory | メモリ | |||
variables | 関数を実行する為に必要な引数 | |||
accountId | AWS アカウントの ID | 必要 | ||
TZ | タイムゾーン | |||
WebhookURL | Webhook の URL | 必要 | 手順 2 で控えた Webhook の URL |
3.2 作成したコードを Lambda にアップロード
satory074@MacBook-Pro ~/src/s3_to_discord $ lambda-uploader
λ Building Package
λ Uploading Package
λ Fin
4. S3 と Lambda の連携
手順 1 で作成した S3 バケットでファイル操作のイベントが行われるたびに、手順 3 で作成した Lambda で Discord への通知を行う設定をします。
-
S3 のコンソール(https://s3.console.aws.amazon.com/)にアクセスします。
-
バケットの一覧から手順 1 で作成したバケットをクリックします。
-
[Properties タブ]をクリックし、Event notifications 項目の[Create event notification]をクリックします。
-
各項目を入力して、[Save changes]をクリックします。
- Event name: イベント名
- 任意の名前(例: notification)
- Event types: (通知を行う)対象のイベント
- 左側の「All ...」すべてにチェックをつけていいと思います
- Lambda function: イベントを連携する Lambda 関数
- 手順 3 で作成した Lambda を選択
- Event name: イベント名
-
手順 3 で作成した Lambda にアクセスすると、S3 と連携してるっぽい図が見られると思います。
-
S3 でファイルをアップロードしたり消したりしてみて、Discord に通知されていれば成功です!おつかれさまでした!!
おわりに
S3 より EC2 の通知が欲しくなった
Discussion