AWS ChatbotからのLambda起動をCloudFormationとSlackワークフローで使いやすくする

AWS CloudFormation を使って AWS Chatbot を実装し、入力コマンドは Slackワークフロー で簡略化して AWS Lambda を同期起動する。
2020.06.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

データアナリティクス事業本部、池田です。
少し前にGAされた AWS Chatbot を触ってみました。 Slackワークフローを使うことで、だいぶ使いやすくなりました。

やること

Slackから Chatbotのコマンド を発行することで、 AWS Lambdaを同期で起動 します。

最終的な結果はこんな感じ↓

Lambdaの作成

今回は、Chatbotには特定のLambda関数の実行権限だけ与える ので、 先にLambdaから作ります。 サンプルなのでLambdaの内容は何でも良いのですが、 特に面白いものも思いつかなかったのでFizzBuzzです。 ChatbotをAWS CloudFormationで作成するので、こちらもそうします。 ( ドキュメント

テンプレートはこんな感じ↓

AWSTemplateFormatVersion: 2010-09-09
Description: Dev.io Lambda Template

Resources:
  ChatbotSampleLambda:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      Handler: index.lambda_handler
      FunctionName: chatbot-sample
      Code:
        ZipFile: |
          def lambda_handler(event, context):
              print("param: {}".format(event["num"]))
              result = []
              for i in range(event["num"]):result.append(i%3//2*"Fizz"+i%5//4*"Buzz"or-~i)
              print(result)
              return result
      MemorySize: 128
      Timeout: 30
      Role: !GetAtt ChatbotSampleLambdaRole.Arn
  ChatbotSampleLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub chatbot-sample-lambda-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole

Lambdaのテンプレート初めて書きましたが、 Code の部分が独特に感じました…
こちらのPython3で最短と言われているFizzBuzz を参考にしています。

Chatbotの作成

CloudFormationの部分は こちらのブログ を参考に作成しました。 ( ドキュメント

  1. 初めにSlackワークスペースの登録をChatbotのコンソールから行ます。

    ※↑画像はすでに設定済みのものがあったため「設定済みチャンネル」が1になってまいます。

  2. Slackチャンネルにアプリをinviteします。 /invite @AWS

  3. CloudFormationでChatbotの設定を作成します。
    テンプレートはこんな感じ↓

    AWSTemplateFormatVersion: 2010-09-09
    Description: Dev.io Chatbot Template
    
    Parameters:
      FunctionName:
        Type: String
      TargetChannelId:
        Type: String
      TargetWorkspaceId:
        Type: String
    
    Resources:
      SampleChatbot:
        Type: AWS::Chatbot::SlackChannelConfiguration
        Properties:
          ConfigurationName: !Sub slack-invoke-fn-${TargetChannelId}
          IamRoleArn: !GetAtt SampleChatbotRole.Arn
          SlackWorkspaceId: !Ref TargetWorkspaceId
          SlackChannelId: !Ref TargetChannelId
      SampleChatbotRole:
        Type: AWS::IAM::Role
        Properties:
          RoleName: !Sub chatbot-invoke-fn-${TargetChannelId}-role
          AssumeRolePolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Principal:
                  Service: chatbot.amazonaws.com
                Action: sts:AssumeRole
          Policies:
            - PolicyName: chatbot-invoke-fn-policy
              PolicyDocument:
                Version: 2012-10-17
                Statement:
                  - Effect: Allow
                    Action:
                      - lambda:invokeFunction
                    Resource: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${FunctionName}

    パラメータにはそれぞれ「Lambda関数名(今回は chatbot-sample )」「SlackワークスペースID」「SlackチャンネルID」を 指定します。
    このテンプレートを使って複数SlackチャンネルのChatbotを作成した時に、リソース名がバッティングするのを避けるため、SlackチャンネルIDを設定名やロール名に含ませています。

作成した結果のChatbotのコンソール↓

実行してみる

Slackの設定したチャンネルからコマンドを発行します。(実行環境はWindows10のChromeです。)
今回であれば↓こんな感じのコマンドになります。
@aws lambda invoke --payload {"num": 20} --function-name chatbot-sample --region ap-northeast-1
--payload がLambda関数へのパラメータ、 --function-name が関数名です。 ちなみにリージョン名の --region は覚えてくれるので2回目からは省略可能だそうです。

確認されるのでYesを選択します。

実行されました。

ちょっとコマンド覚えるのしんどいですよね…
(私のPCはWindows10なので、 [Win]+[V]クリップボード履歴でピン留めで良いかとも思ったのですが、) 社内からSlackワークフローが使えるとのアドバイスをもらったので 次章からそちらで入力の簡略化をしていきます。 (本題と全く関係無いですが、 こちらのブログ で3位に輝いたチャンネルで教えてもらいました。)

余談(Chatbotの返信の内容について)

Lambda関数のランタイムがPython3.7だと、 print() した内容はChatbotからの返信には含まれず return した内容だけが Payload としてSlack上から確認できました。 (Node.js12でも試しましたが、 console.log() の内容は返信されませんでした。) たまたま気づいたのですが、カスタムランタイムで echo すると、 実行したechoが全てPayloadに含まれていました。
また、今回のサンプルコードで、Lambda関数内でエラーが発生した場合は、 ↓のように返信のPayloadがエラー内容になっていました。

Slackワークフローの作成

Slackワークフロー では、入力フォームの利用やチャンネルへ投稿ができるので、 Chatbotコマンド入力の簡略化に使えそうです。

  1. トリガーのステップを作成します。

  2. フォームのステップを作成します。
    今回のLambda関数はパラメータが1つなので、質問も1つ作ります。

  3. チャンネルへのChatbotコマンドの投稿のステップを 作成します。
    変数を使って、前手順のフォームの値をコマンドの雛形に埋め込みます。

    ここで送信先を間違うと、恥ずかしかったりChatbotに無視されて寂しかったりになると思います。

上記のワークフローを公開すると、↓ショートカットに追加されるので、

フォームに答えると、

ワークフローがコマンドを投稿してくれて、Chatbotが起動してくれます。

おわりに

ワークフローがすごく便利ですね。
Chatbotからの返信はSNSトピック経由でも良かったかもしれません。(きれいに表示されそう。)

参考文献