Slash CommandsとAWS Lambdaで作るChatOpsの基本機能

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

モバイルアプリサービス部の五十嵐です。

SlackでChatOpsを始めようと思い、SlackのSlashCommandsという機能とAWS Lambdaを使って基本的な機能を作ってみました。

はじめに

Slash Commandsは、 /command のフォーマットで任意のコマンド機能を作成できる機能です。

まずは以下の記事を参照いただくと、基本的な仕組みが理解できると思います。

【新機能】AWS LambdaにSlack連携のBluePrintが登場。ChatOpsがより手軽に | Developers.IO

注意点としては、Slash Commandsには以下の制約があります。

  • Slash Commandsのレスポンスは、Slash Commandsはの実行者にしか見えない。 <2016-09-08 20:23:32 訂正>
    • デフォルトではSlash Commandsはの実行者にしか見えないのですが、レスポンスのオプションで "response_type": "in_channel" を付けることで見るようになります。
  • Slash Commandsのリクエストは3秒でタイムアウトする。

実際に何かの処理をするのにはたいてい3秒以上かかりますし、ログが実行者にしか見えないのも困ります。これらを解決するために、チャンネルへのログ出力はSlack Botを使い、時間のかかる処理は非同期実行で行う方法を以下に紹介します。

Slack Bot

Slack Botを使うには、Slash Commandsのリクエストパラメータに含まれる response_url にメッセージをPostします。以下はリクエストパラメータのサンプルです。

token=MXTo9FagJ91hN2crCGgZifNe
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
user_id=U2147483697
user_name=Steve
command=/weather
text=94070
response_url=https://hooks.slack.com/commands/1234/5678

このURLは、Slash Commandsがリクエストされてから 30分間有効で、5回まで使うことができます。 6回目は 404 Not Found になります。メッセージのフォーマットは Message Formatting | Slack などを参照してください。

非同期実行

Slash Commandsのリクエストは3秒以内に返す必要があるので、リクエストを受け付けるLambdaから更に非同期で後続の何かに処理を渡す必要があります。最初は後続の処理もAPI Gateway+Lambdaという構成にしてHTTPリクエストで処理を渡そうとしたんですが、Lambdaの起動にわずかながら時間がかかることがあるのでトータルで3秒を超えてしまうことがありました。

そこで後続の処理はHTTPリクエストではなく直接Lambdaを非同期でinvokeすることにしました。以下はリファレンスのスニペットですが、 InvocationTypeEvent にすることで終了を待たずに実行することができます。

Class: AWS.Lambda — AWS SDK for JavaScript

var params = {
  FunctionName: 'STRING_VALUE', /* required */
  ClientContext: 'STRING_VALUE',
  InvocationType: 'Event | RequestResponse | DryRun',
  LogType: 'None | Tail',
  Payload: new Buffer('...') || 'STRING_VALUE',
  Qualifier: 'STRING_VALUE'
};
lambda.invoke(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

シーケンス図にすると以下の様なイメージです。

slash_command_sequence

実行例

実際に動作させた画像がこちらです。

今回は /echo という、入力したコマンドとパラメータをBOTがオウム返しするだけのコマンドです。

slash_command_request

このように入力すると...

slash_command_sample

BOTが入力したコマンドの情報をまとめてオウム返ししています。 Only visible to you と書かれたメッセージは、SlashCommandsリクエストに対するレスポンスに設定したメッセージです。

サンプルコード

Node.jsの書き方が拙いですが、サンプルコードをGistに公開しました。

Lambda1

Lambda2

注意点としては、slackCommandEntry.jsのLambdaからslackCommandProcess.jsのLambdaを起動するため、slackCommandEntry.jsのLambdaには以下の様なLambdaの実行権限が必要です。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1472382370000",
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeAsync",
                "lambda:InvokeFunction"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

余談

なぜChatOpsが必要かを書いておきたいと思います。

システムを運用するにはたくさんのツール(例えばデプロイツールや運用オペレーションツールなど)が使われます。それらは要望によりどんどん増えていくものです。またツールによって依存する言語環境やライブラリが違うということも良くあります。このような状況になってくると、エンジニア以外の人が使うためのハードルが高くなったり、引き継ぎが大変になるなどの問題が出てきます。

このような問題への対処の一つとしてChatOpsが使えると思います。ChatOpsならチャット画面にコマンドを打つだけなので、誰でも操作ができて環境依存がありません(もちろんバックエンドはありますが、それを知る必要があるのは一部のエンジニアだけです)。また、ログがチャット上に残るので誰がどのような操作を行ったか一目でわかるのも大きなメリットです。

まとめ

この基本機能を使用すれば、AWS SDKを使ってAWS上のリソースの操作を行ったり、HTTPリクエストで外部のサービスの操作を行ったり、LambdaでできることならChatOpsに置き換えられると思います。ChatOpsの導入にぜひご活用ください。

参考