Step Functionsからchatbot経由でslack連携してみた

# 初めに
chatbotってLambdaがイベントソースの場合はslack連携してくれず、いけているのかいけていないのかよく分からないサービスですよね

step functionsだと、実行ステータスの変更イベントでEventBridgeが発火してSNSからslack連携することが出来ました
slack連携は出来ましたが、デフォルトのメッセージ内容が実行ステータスしか読み取れない状態でしたので、そこら辺に一工夫必要でした
断片的な情報はWebや生成AIから拾えましたが、欲しい情報に辿り着くまで苦労したので、ここに纏めておきます

# コンテンツ
## SFnの実行ステータス遷移イベント
[step functionsのイベント例]((https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/cw-events.html)) と [interface EventPattern](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.EventPattern.html) からセットしていきます

下のようになりました
```sfn_event.ts
    const rule = new Rule(this, this.SFnName, {
      eventPattern: {
        source: ["aws.states"],
        detailType: ["Step Functions Execution Status Change"],
        detail: {
          status: ["SUCCEEDED", "FAILED", "TIMED_OUT", "ABORTED"],
          // status: ["FAILED", "TIMED_OUT", "ABORTED"],
        },
      },
      ruleName: `${this.SFnName}-event`,
    });
```

## データ連携SNS Topic
適当にTopicを作成します
```topic.ts
  createTopic(): Topic {
    const topicName = `${this.SFnName}-topic`;
    return new Topic(this, topicName, { topicName: topicName });
  }
```
## Slack連携メッセージの整形
slackで知りたい内容は、どのSFnなのかと実行ステータスなので、下のようにしました

[AWSのイベントのサンプル](https://docs.aws.amazon.com/ja_jp/step-functions/latest/dg/cw-events.html)を参照に必要なもののみをInputPathsMapにセットします

InputTemplateは文字列を渡す必要があるため、Objectを文字列化しています
slackのmarkdownを使いたかったので、「_」(イタリック)や「*」（ボールド）で囲んでいます
[AWSのドキュメント](https://docs.aws.amazon.com/chatbot/latest/adminguide/custom-notifs.html)からフォーマットや必須の内容を確認してセットします
```transform.ts
    makeTransformer() {
        return {
              InputPathsMap: {
                account: '$.account',
                sfnName: '$.detail.stateMachineArn',
                execArn: '$.detail.executionArn',
                status: '$.detail.status',
                time: '$.time',
              },
              InputTemplate: JSON.stringify({
                  version: '1.0',
                  source: 'custom',
                  content: {
                      textType: 'client-markdown',
                      title: '<status>: _<sfnName>_',
                      description: 'Finished at *<time>*\nAccount: *<account>*\nexecArn: *<execArn>*',
                  },
              }),
        };
    }
```

## トランスフォーマーのセット
Ruleへのトランスフォーマーの適用メソッドとかオプションのプロパティは、通常触るL2には提供されていないので、L1に変更して適用します
AWSのドキュメントは[こちら](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-target.html)。ArnとIdが必須ですね
```ruleL1.ts
 const cfnEventRule = rule.node.defaultChild as CfnRule;
    cfnEventRule.addPropertyOverride('Targets', [
          {
              Arn: topic.topicArn,
              Id: 'SNS-Topic',
              InputTransformer: tfr,
          },
    ]);
```

上記で良さそうでしたが、L2でもターゲットを追加しないとダメでした
```ruleL2.ts
    rule.addTarget(new SnsTopic(topic, {message: RuleTargetInput.fromObject(tfr)}));
```

### 参考資料
L1, L2の説明
https://docs.aws.amazon.com/ja_jp/cdk/v2/guide/constructs.html

L2からL1へのキャスト
https://docs.aws.amazon.com/cdk/api/v2/docs/constructs.Node.html#defaultchild


## Chatbotの設定
特に変わったところはないかと思います
```chatbot.ts
    new SlackChannelConfiguration(this, this.chatbotName, {
      slackChannelConfigurationName: this.chatbotName,
      slackChannelId: props.channelID,
      slackWorkspaceId: this.workspaceID,
      notificationTopics: [topic],
    });
```
# 追記
普段はL2しか使っていないため、L1へのキャストは中々敷居が高かったです
ですが、CDKの理解につながる良いきっかけを頂きました

slack連携用のLambdaを作らず、CDKへの追記のみでslack連携出来るのはありがたいものです

この記事がどなたかの参考になると嬉しいです