AWS Chatbotのカスタム通知機能で通知内容をいい感じにする。

# はじめに
`AWS Chatbot`で`Slack`等に送信する通知内容をカスタマイズできるようになり、通知内容をいい感じにして送信することができるようになったようなので、試してみたいと思います。

- [Custom notifications are now available for AWS Chatbot](https://aws.amazon.com/jp/about-aws/whats-new/2023/09/custom-notifications-aws-chatbot/)

# AWS Chatbotによるメッセージの送信
以前は`Chatbot`を使って送信されるメッセージに加工を加えることが出来なかったため、どうしても加工を加えて`Slack`等に送信したい場合は、`Chatbot`を使わずに`Lambda`でコードを書いて送信する必要がありました。

しかし、今回のアップデートで`EventBridge`のターゲット入力トランスフォーマーを使って`Chatbot`にわたすメッセージを加工することで`Slack`等に送信するメッセージに加工を加えることができるようになったようです。

今回はクラスメソッド様の以下の記事を参考にさせて頂きました。

- [[アップデート]AWS Chatbotの通知内容をカスタマイズできるカスタム通知がサポートされました](https://dev.classmethod.jp/articles/aws-chatbot-custom-notification/)

# 今回のテスト構成
参考にさせて頂いた記事では`CloudWatch Alarm`を使っていましたが、手元に`Systems Manager Change Calendar`を使った環境があったので、カレンダーのステータスが変わったら`EventBridge`経由で`Slack`通知する構成を組んでみようと思います。

```plantuml
@startuml
!define AWSPuml https://raw.githubusercontent.com/awslabs/aws-icons-for-plantuml/v16.0/dist
!include AWSPuml/AWSCommon.puml
!include AWSPuml/Groups/AWSCloud.puml
!include AWSPuml/Groups/Generic.puml
!include AWSPuml/ManagementGovernance/SystemsManagerChangeCalendar.puml
!include AWSPuml/ManagementGovernance/Chatbot.puml
!include AWSPuml/ApplicationIntegration/EventBridge.puml
!include AWSPuml/ApplicationIntegration/SimpleNotificationService.puml
!include AWSPuml/AWSSimplified.puml
!include <logos/slack>

left to right direction
title カレンダーのステータスが変更されたらSlackに通知する構成

skinparam shadowing false
hide stereotype
skinparam rectangle {
    BackgroundColor AWS_BG_COLOR
    BorderColor transparent
}

AWSCloudGroup(cloud){
  rectangle "<font color=white>right" as right {
    rectangle "$SystemsManagerChangeCalendarIMG()\nChange Calendar" as calendar
    rectangle "$EventBridgeIMG()\nEvent Bridge" as eventbridge
    rectangle "$SimpleNotificationServiceIMG()\nSNS" as sns
    rectangle "$ChatbotIMG()\nChatbot" as chatbot
  }
}
rectangle "<$slack>" as slack

calendar-d->eventbridge: イベント通知
eventbridge-d->sns: トリガー実行
sns-d->chatbot: パブリッシュ
chatbot-d->slack: Slack通知

@enduml
```

通知に必要となる`SNS`と`Chatbot`の設定は以下で紹介しているので、参考にしてください。

- [AnsibleをAWS Systems Managerから実行するCI/CDを構築する。（その３：SNS、Chatbotの準備）
](https://qiita.com/sakai00kou/items/b75e763aef0af475dfb2)

# 事前準備
前述の通り`Simple Notification Service`（以下`SNS`）と`Chatbot`は上記で作成済みのものとして進めますが、足りていない`Change Calendar`と`EventBridge`を作成します。

## Change Calendarの作成
`Change Calendar`とは、`AWS`の`Systems Manager`のサービスの中の一つで、カレンダー形式で日時のイベントを作成すると、イベント開始時、終了時に`OPEN`、`CLOSED`といったステータスを通知できるサービスです。

他のサービスと連携すると、`cron`形式では実現が難しい祝日含む定期実行の処理を行えたりする便利なサービスです。

今回は`Change Calendar`が主題ではないのでサラッと作成してしまいますが、「**AWS Systems Manager**」のダッシュボードから「**Change Calendar**」→「**カレンダーを作成**」で適当なカレンダー名をつけて、他はデフォルトのまま作成します。

作ったカレンダーに対してイベントを作成すれば`Change Calendar`の作成は完了です。

|項目|設定|
|:--|:--|
|スケジュールされたイベントの名前|Chatbot_Custom_Notification|
|説明|空欄|
|Advisory|チェックなし|
|イベント開始日|2023/09/18 12:00:00|
|イベント終了日|2023/09/18 12:15:00|
|タイムゾーンをスケジュール|(GMT+09:00) Asia/Tokyo|

上記の場合、「**2023/09/18 12:00:00**」になると`CLOSED`というステータスが通知され、「**2023/09/18/ 12:15:00**」になると`OPEN`というステータスが通知されるので、今回はこの通知を`EventBridge`でキャッチして、`SNS`経由で`Chatbot`に通知します。
※デフォルトOPENカレンダーの場合

## EventBridgeの作成
入力トランスフォーマーを使ったカスタム通知を行う前に、ひとまず通常の通知ができるよう設定を行います。

以下内容で`EventBridge`ルールを作成しました。

- **ルールの詳細設定**

|項目|設定|
|:--|:--|
|名前|Chatbot_Custom_Notification_EB_Rule|
|説明|空欄|
|イベントバス|default|
|ルールタイプ|イベントパターンを持つルール|

- **イベントパターン設定**

|項目|設定|
|:--|:--|
|イベントソース|AWSイベントまたはEventBridgeパートナーイベント|
|メソッド|カスタムパターン(JSONエディタ)|
|イベントパターン|※以下参照|

```json:Change Calendarイベント受信用イベントパターン
{
  "source": ["aws.ssm"],
  "detail-type": ["Calendar State Change"],
  "detail": {
    "state": ["CLOSED", "OPEN"]
  }
}
```

- **ターゲット設定**

|項目|設定|
|:--|:--|
|ターゲットタイプ|AWSのサービス|
|ターゲットを選択|SNSトピック|
|トピック|※事前に作成済みのSNSトピックを選択|
|追加設定|※一旦デフォルトのままで設定|

今回は詳しく解説しませんが、上記の設定を行うことで、`Change Calendar`から`OPEN`、または`CLOSED`の通知がきた場合に、トリガーとして設定している`SNS`に通知されるようになります。

# デフォルトの通知メッセージの確認
`EventBridge`の入力トランスフォーマーを使ったカスタム通知設定を行う前に、現時点での通知メッセージを確認してみようと思います。

設定ができていれば、先程設定した`Change Calendar`のイベント作成した時間になれば`Slack`等にメッセージが通知されます。

`Change Calendar`からの通知の場合は、`OPEN`時でも`CLOSED`時でもどちらも以下のようなメッセージが通知されるようです。

![Monosnap_20230918_122921.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/71bf1821-9972-730c-c1e5-146d14d386dd.png)

# 入力トランスフォーマーによるカスタム通知
いよいよ本題となる`EventBridge`の入力トランスフォーマーを使用したカスタム通知を行っていきたいと思います。

入力トランスフォーマーは、初見ではとっつきにくく、どう設定したら良いか途方に暮れてしまうので、順に解説しながら進めていきます。

## 入力トランスフォーマーについて
先程設定した`EventBridge`ルールの「**ターゲット**」タブから「**編集**」に入り、先程設定を飛ばした「**追加設定**」の「**ターゲット入力を設定**」で「**入力トランスフォーマー**」を選択、「**入力トランスフォーマーを設定**」で、ターゲット指定しているサービスに送る入力値を編集できます。

入力トランスフォーマーの設定画面では、大きく分けて、「**サンプルイベント**」、「**入力パス、テンプレート、および出力の例**」、「**ターゲット入力トランスフォーマー**」の項目があり、ターゲット入力トランスフォーマーの項目は更に「**入力パス**」、「**テンプレート**」、「**出力**」に分かれます。

項目は色々とありますが、設定に関係する項目は「**入力パス**」と「**テンプレート**」のみで、それ以外は設定をする上での例が表示されているだけです。

### サンプルイベント
`EventBridge`にどのようなイベントが通知されるのか、本来であれば実際にイベントを実行し、`CloudTrail`やその他ログ等から確認することになりますが、AWS側でどのようなイベントが通知されるのかといったサンプルを用意してくれており、サンプルを選択することでわざわざ実際にイベントを発生させて確認しなくても良いようになっています。

![Monosnap_20230918_130156.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/6e47dffd-bc8b-e77c-e6c3-45509a768da1.png)

実際のイベント通知の内容が分かれば、「**ご自身名前を入力**」から直接入力することもできます。

サンプルイベントはサービスごとにいくつかあるので、実際のイベントに近いサンプルを選びましょう。

ちなみに、サンプルイベントはただのサンプルなので、設定上は何も選択しなくても問題ありません。

### 入力パス、テンプレート、および出力の例
後述のターゲット入力トランスフォーマーで設定する際の設定例が書かれているだけの例となります。

![Monosnap_20230918_131452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/ba59d8fa-1f28-ba0b-47e0-76ffc6d2780e.png)

変数等の解説は後述しますが、「**入力パス**」は`EventBridge`で受け取ったイベント通知のうち、どの部分を使用するのかといった設定で、「**テンプレート**」はターゲットに対して出力する際の書式を設定するテンプレート、「**出力**」は入力パス、テンプレートで設定した内容で出力した場合の出力例となります。

### ターゲット入力トランスフォーマー入力パス
「**入力パス**」で`EventBridge`が受け取るイベントからどの部分を使いたいかを設定します。

サンプルイベントを見ると様々な情報が書かれていますが、トリガーとなるサービスにメッセージを送信する際に、不要な情報も多く、一部のみ使いたいといった場合に設定します。
※そもそもターゲットのサービスを実行したいだけで、送信するメッセージは何でもいいといった場合は加工不要。

「**入力パス**」は任意の変数名（`Key`）とJSON形式のイベントのどの部分を取得するか（`Value`）を示すことで、次のテンプレートで変数として使用できます。

`Value`の指定方法は、先頭に「**$**」をつけて、JSONの階層ごとに「**.**」で区切って場所を示します。

例えば先程紹介した`Change Calendar`のサンプルイベントから、`CalendarState`という任意の変数名で`state`を指定する場合、「**$.detail.state**」となります。

また、以下「**resources**」のような「**[ ]**」で括られている設定はリスト型で何番目の要素を取得するかを指定する必要があり、0番目〜n番目で指定します。（すべての要素を取得するのであれば「**\***」でもいけるはず）

以下「**resources**」では要素が１つしか無いので、「**$.resources[0]**」のようにします。

![TargetInputTransformer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/db065a0c-62b1-d7d8-7ac9-523562be1870.png)

`Chatbot`用にメッセージを編集するため、今回は以下の変数の設定、パスの取得を行いたいと思います。

|変数名|JSONパス|備考|
|:--|:--|:--|
|DetailType|$.detail-type|Chatbotメッセージに埋め込みたいため指定|
|AccountID|$.account|リンク生成やメッセージ内で使用するため指定|
|Region|$.region|リンク生成やメッセージ内で使用するため指定|
|CalendarARN|$.resources[0]|カレンダー名を表示させたいため指定|
|CalendarState|$.detail.state|カレンダーのステータスを表示させるため指定|
|CalendarAtTime|$.detail.atTime|カレンダーイベントの開始時刻を表示させるため設定|
|CalendarNextTransitionTime|$.detail.nextTransitionTime|次にカレンダーイベントの状態が遷移する時刻を表示させるため設定|
|CalendarEvent|$.detail.event|カレンダーのイベント名を表示させるため指定|

上記の表の通り「**入力パス**」に設定した内容。

```json:入力パスに設定する内容
{
  "DetailType": "$.detail-type",
  "AccountID": "$.account",
  "Region": "$.region",
  "CalendarARN": "$.resources[0]",
  "CalendarState": "$.detail.state",
  "CalendarAtTime": "$.detail.atTime",
  "CalendarNextTransitionTime": "$.detail.nextTransitionTime",
  "CalendarEvent": "$.detail.event"
}
```

### ターゲット入力トランスフォーマーテンプレート
先程入力パスに設定した変数設定を使って、テンプレートに`Chatbot`へ通知するための書式を設定していきます。

- [Custom notifications](https://docs.aws.amazon.com/chatbot/latest/adminguide/custom-notifs.html)

上記`Chatbot`のカスタム通知のドキュメントを見ると、カスタム通知で`Chatbot`に送るには以下のような書式で設定する必要があるようです。

```json:イベントスキーマ
{
    "version": String, 
    "source": String, 
    "id": String,    
    "content": {
        "textType": String, 
        "title": String,  
        "description": String, 
        "nextSteps": [ String, String, ... ], 
        "keywords": [ String, String, ... ] 
        },
        "metadata": {                     
            "threadId": String,
            "summary": String,
            "eventType": String,
            "relatedResources": [ String, String, ... ],
            "additionalContext" : {
                "customerProvidedKey1": String,
                "customerProvidedKey2": String
                ...
            }
        }
}
```

上記のうち、必須項目になるものは「**version**」（2023年9月現在、1.0固定）と「**source**」（custom固定）のみで、その他は任意となるようです。

イベントスキーマを参考に作成したテンプレートは以下となります。

```json:テンプレートに設定する内容
{
  "version": "1.0",
  "source": "custom",
  "content": {
    "title": ":mega:<https://<Region>.console.aws.amazon.com/systems-manager/home?region=<Region>#|Systems Manager Event | <Region> | Account: <AccountID>>",
    "textType": "client-markdown",
    "description": "*カレンダー状態遷移(<DetailType>)*",
    "nextSteps": [
      "カレンダーARN： *<CalendarARN>*",
      "イベント名： *<CalendarEvent>*",
      "カレンダーの状態： *<CalendarState>*",
      "状態遷移開始時間： *<CalendarAtTime>*",
      "次回状態遷移時間： *<CalendarNextTransitionTime>*"
    ]
  }
}
```

先程設定した変数は「**<変数名>**」で指定することで値を呼び出す事ができ、リンク表示や太文字表記は`Slack`等の各種仕様に従います。

### テンプレートで設定した内容について
デフォルトでの通知時と同じように、`Change Calendar`へのリンクを表示させたかったので、「**title**」部分はリンクURLと文言をコピーして、同じような出力になるように調整しました。

「**textType**」は`client-markdown`固定のようなのでそのまま指定。

「**description**」は、せっかくなので日本語メッセージと`DetailType`を指定。

「**nextSteps**」は本文の部分として、表示させたい情報を日本語の説明付きで設定しました。

また、「**title**」はデフォルトで太文字になりますが、それ以外はデフォルトで太文字にならないので、各種状態値は太文字で指定しています。

ちなみに、「**title**」で指定しているような書式等は、`Slack`の場合、`Slack API`の「**Block Kit**」の「**Build and prototype visually**」より、「**Block Kit Builder**」（要Slackアカウント）で画面構成のサンプルを作成したり、サンプルから書式を確認したりできるので、参考にしてみると良いです。

- [Block Kit](https://api.slack.com/block-kit)

![Monosnap_20230918_151050.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/28580bfe-a5d5-56ce-62b1-6ee9844ba50a.png)

## カスタム通知での通知結果
先程の設定で`Chatbot`で通知したところ以下のようにカスタマイズされたメッセージが通知されました。

カスタム通知で編集して送信した場合、以下のように「**Custom notification delivered by AWS Chatbot**」と表示されるようです。

加工しているメッセージなのかがひと目で分かり、いい感じですね。

- **ClOSEDへの状態遷移**
![Monosnap_20230918_163028.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/6dca1c9f-8ab9-29a5-04ca-567eb55ab6f6.png)

- **OPENへの状態遷移**
![Monosnap_20230918_164026.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/821abe67-8a34-be38-5f5a-e10d1fc9412f.png)


## カスタム通知でもできないこと
`CloudWatch Alarm`で`SNS`→`Chatbot`で通知した場合、以下のようにボタンが表示されていたり、フィールドが分かれて項目表示されていたりしますが、`Chatbot`のカスタム通知で用意されているイベントスキーマは特定のフィールドの設定のみとなるので、以下のような凝った内容の通知を行いたい場合は今までと同様`Lambda`で好きなように加工して通知する必要があります。

![スクリーンショット 2023-09-18 16.16.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/f8d96b0f-b1f8-e072-0b2d-482572d8f594.png)

# おわりに
AWSから送信されるメッセージは基本英語ということもあり、通知メッセージをパッと見でわかるようにしたいなぁと思っていましたが、カスタム通知機能により、簡単なメッセージであれば`EventBridge`のターゲット入力トランスフォーマーで加工することで日本語での通知もできるようになったというのは嬉しいアップデートだと感じました。