🔔

S3イベント通知をトリガーにTeams投稿

2021/09/19に公開

S3にファイルが生成されたら、それをトリガーにTeamsに投稿するサンプル

実現すること

S3バケットの内容をCloudFrontで公開している状況で、S3にファイルが生成されたら、そのイベント通知をトリガーにしてCloudFrontのURLをTeamsに投稿して関係者にお知らせする!

実際には……

実際には、LambdaからMediaConvertキックしてストリーミング用の動画とそれを表示するHTMLを生成してS3に保存する処理があって、そのHTM生成をお知らせするために作ったものです、はい。

事前準備

  • S3バケットの作成
  • S3に紐づくCloudFrontディストリビューションの作成
  • TeamsのIncoming WebhookのURL取得

Lambda (Python)

  • TeamsのWebhook URL、CloudFrontのURLはLambdaの環境変数に設定しておく
  • Teamsに通知するためのAdaptive Cardの内容のひな型は別ファイル(template.json)にしておき、Python側のコードを少しスッキリさせる
  • Teamsの通知からすぐ開けるようにURLはハイパーリンクになるようにMarkDownにする
import json
import logging
import os
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError

import boto3

logger = logging.getLogger()
logger.setLevel(logging.INFO)

TEAMS_CHANNEL_WEBHOOK_URL = os.environ.get('TEAMS_CHANNEL_WEBHOOK_URL')
cloudfront_distribution = os.environ.get('cloudfront_distribution')

# template.json を読み込んでおく
with open("./template.json", 'r') as f:
    template_message = json.load(f)

def lambda_handler(event, context):
    # logger.info(event)
    logger.info('Start processing')
    # イベントからS3関連の部分のみ抜き出し
    s3_info = event['Records'][0]['s3']

    # S3の情報からCloudFrontのURLを生成
    object_key = s3_info['object']['key']
    url = cloudfront_distribution + '/' + object_key
    # logger.info(url)

    # template_message を読み込み、URL部分のみ書き換え
    teams_message = template_message
    teams_message['attachments'][0]['content']['body'][1]['items'][1]['text'] = '[{}]({})'.format(url, url)
    logger.info(teams_message)

    # メッセージをエンコードしてTeamsに投稿
    req = Request(TEAMS_CHANNEL_WEBHOOK_URL, json.dumps(teams_message).encode('utf-8'))
    try:
        response = urlopen(req)
        response.read()
        logger.info("Message posted to MicrosoftTeams")
    except HTTPError as e:
        logger.error("Request failed: %d %s", e.code, e.reason)
    except URLError as e:
        logger.error("Server connection failed: %s", e.reason)
template.json
{
    "type": "message",
    "attachments": [
        {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "content": {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.3",
                "body": [
                    {
                        "type": "Container",
                        "items": [
                            {
                                "type": "TextBlock",
                                "wrap": true,
                                "text": "S3ファイル生成、CloudFront公開のお知らせ",
                                "size": "Medium",
                                "weight": "Bolder"
                            }
                        ]
                    },
                    {
                        "type": "Container",
                        "items": [
                            {
                                "type": "TextBlock",
                                "text": "以下のCloudFrontのURLで公開しました。",
                                "wrap": true
                            },
                            {
                                "type": "TextBlock",
                                "wrap": true,
                                "text": ""
                            }
                        ]
                    }
                ]
            }
        }
    ]
}

トリガー設定

S3のイベント通知を作成し、作成したLambda関数を送信先として指定する。
想定外の処理が発生しないように、プレフィックスでいわゆるフォルダっぽいものを指定したり、サフィックスで拡張子を .html にしぼっておきましょう。

振り返り

やっぱりLambda便利よなー、という感想。お手軽過ぎる。
AWSを使うときは、マネージドなPaaSとLambdaだけ使っていたい。
あと、現時点ではTeamsのIncoming Webhookがメンションに対応していないので、通知があまり機能しないのも悲しいところ。
TeamsユーザーのみなさんはBacklog入りして1年以上経つ以下のUserVoiceに投票いただきたい。
https://microsoftteams.uservoice.com/forums/555103-public/suggestions/17153099-webhook-needs-to-support-forced-notification-a-la

Discussion