1. Cisco Spark Bot の概要
Cisco Spark には Bot 機能が用意されている。人にメンションして話かける代わりに、Bot にメンションして話しかけると、Bot はそれをコマンドとして理解して処理を行い、結果のメッセージを返す(実際には Bot は中継をするだけで実処理は別のプログラムが行う)。
「どんな処理」をして「どんな結果」を返すかはアイデア次第。ここでは最も単純な処理として、ping というメッセージに対して pong と返答する Bot を作ってみる。実処理の部分は AWS Lambda + Amazon API gateway を使うこととする。
1-1. 処理の全体像
- Bot にメンションしてメッセージを投稿
- Bot が Target URL 宛てに次の形式に従って送信(中継):
- 必ず HTTP POST を使う
- ペイロードは定型のフォーマット(Envelop と呼ぶ)が使われる
- 非定型のデータは Envelop の中の ‘data’ へ入れられる
- Target URL を持つのは API Gateway の役割
- Lambda は API Gateway の受信を「トリガー」として起動
- Bot からの POST に対するリアクションは Lambda にて自分でプログラミングする必要がある
注意点として、2. で Bot が Target URL に HTTP POST する際、ペイロードは メッセージそのものを含まず、メッセージ ID しか含まない。メッセージそのものを取得するには Lambda から Cisco Spark に対して HTTP GET を実施し、ID に対応するメッセージを取得する必要がある。このプログラムは自分で用意する(図中の 6)。また、結果を Cisco Spark で表示するプログラム(HTTP POST)も用意が必要(図中の 7)。
2. Cisco Spark 側の設定手順
2-1. Bot の作成
Bot を作成するには実ユーザでログインする必要がある。Bot は実ユーザに紐づいて登録されるため。
以下のサイトへアクセスして「Create a Bot」をクリックする:
https://developer.ciscospark.com/add-app.html
続く画面で以下の三項目を全て埋める:
- Display Name:Bot の名前
- Bot Username:識別子。Bot の名前と同じでも良いが他の人と重複してはならない
- Icon:画像の URL を入力
正しく入力すると Bot 用の Access Token が表示されるのでメモする。失効はしない。取り扱いに注意。
2-2. Room へ Bot を追加
Cisco Spark を開いて任意の Room へ行き、人を Room へ加えるのと同じ要領で Bot を Room へ追加する(Bot の名前で検索した後、追加)。
2-3. Webhook について
Cisco Spark へメッセージを投稿すると、Bot はそれを中継し、HTTP POST で別のプログラムへ渡す。プログラムの処理方法は様々だが通常結果は Bot へ戻され(いわゆるコールバック)Cisco Spark 上に表示する。HTTP によるコールバックの仕組みを Webhook と呼ぶ。
Webhook を設定する上で特に重要なのが Target URL である。インターネット上に存在する指定の URL で Bot が HTTP POST を投げる宛先となる。
Target URL 及びプログラムは Bot を作る人が用意しなければならない。そのために、例えば・・・サーバを準備して、OS をインストールして、Web サーバを稼働させ、IPアドレスを割り当てた後、URL を割り当てる・・・等と従来の方法を使っても良いが、相当な手間がかかるので、ここでは API Gateway を使って Target URL を用意し、実プログラムを Lambda で動作させる。
Target URL を決定するには Lambda + API Gateway の設定を先に行う必要がある。Cisco Spark の Webhook の設定は 4-1. で行う。
3. AWS Lambda + Amazon API Gateway 側の設定
※ この項は Amazon API Gateway での AWS Lambda の使用 (オンデマンド HTTPS 経由) のチュートリアルを基本情報として、Cisco Spark Bot へ対応するよう必要に応じて手順をカスタマイズしています。
※ AWS マネジメントコンソール、及び、AWS CLI の設定が完了しアクセス可能であることが前提です。完了していない場合はこちらの記事の「ステップ 1: 準備」等を参考に設定を完了して下さい。
3-1. Python 用デプロイパッケージを作成する
デプロイパッケージとは以下の二つを zip ファイルとして圧縮したもの:
- Lambda のプログラム(今回は Python3.6)
- 上記が使用するライブラリ
作成は以下の手順で行う:
1.AWS CLI へログインする。
2.Lambda 用の Python プログラムを作成する。ファイル名は Lambda 関数名と同じにする(LF4CiscoSpark)。ここでは以下のサンプルプログラムを作成する:
$ vi LF4CiscoSpark.py
---
from __future__ import print_function
import boto3
import json
import requests
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
access_code = '' # BotのAccess Codeを入力
botDisplayName = '' # Bot名を入力
def sendSparkGET(event):
url = 'https://api.ciscospark.com/v1/messages/{0}'.format(event.get('data')['id'])
headers = {
'Authorization' : 'Bearer ' + access_code,
'Content-Type' : 'application/json'
}
r1 = requests.get(url, headers = headers)
return json.loads(r1.text)
def sendSparkPOST(event, message_detail):
url = 'https://api.ciscospark.com/v1/messages/'
headers = {
'Authorization' : 'Bearer ' + access_code,
'Content-Type' : 'application/json'
}
payload = {
"roomId" : event.get('data')['roomId'],
"text" : 'pong'
}
r1 = requests.post(url, headers = headers, data = json.dumps(payload))
return True
def handler(event, context):
print("Received event: " + json.dumps(event, indent=2))
message_detail = sendSparkGET(event)
bot_command = message_detail['text']
bot_commands = {
botDisplayName + 'ping' : lambda x, y : sendSparkPOST(x, y)
}
if bot_command in bot_commands:
return bot_commands[bot_command](event, message_detail)
else:
raise ValueError('Unrecognized operation')
---
3.上記プログラム中で requests を import しているが、Lambda の実行環境には標準で含まれていない。標準外ライブラリを使いたい場合、デプロイパッケージへ該当ライブラリ( requests)のファイルを含める必要がある。対応ファイルは通常 site-packages の中にあるはずなので、まず site-packages/requests ディレクトリを zip する:
$ zip LF4CiscoSpark.zip -r /(path-to-site-packages)/site-packages/requests
4.次に、今作成した LF4CiscoSpark.py を zip ファイルへ追加する:
$ zip -g LF4CiscoSpark.zip LF4CiscoSpark.py
プログラムについて
Bot にメンションして "ping" とメッセージを送ると、Bot が "pong" と返信してくれる。 "ping" 以外のコマンドを使いたい場合は bot_commands に処理を記述すればよい。
- sendSparkGET() … 「1-1. 処理の全体像」の図中 6 に対応
- sendSparkPOST() … 「1-1. 処理の全体像」の図中 7 に対応
3-2. 実行ロール (IAM role) を作成する
IAM はユーザーがどの AWS リソースへアクセスできるか、そのリソースをどのような方法で使用できるかを制御する仕組み。一般的な設定手順としては、1)ロールの作成 2)ポリシーの作成 3)ロールへポリシーをアタッチ、の3ステップを行う。今回ポリシーは標準ポリシーを使うので2)は行わなくてよい。手順が完了すると ロール ARN と呼ばれる文字列が表示される。これは次の手順で Lambda 関数を作成するのに必要。
- IAM コンソール (https://console.aws.amazon.com/iam/) にサインインする。
- 「ロール」をクリック。
- 「新しいロールの作成」をクリック。
- 「AWS サービスロール」が選択されていることを確認。
- 「AWS Lambda」の横の「選択」をクリック。
- 「フィルター」と記載されたフィールドに lambda と入力
- 表示された標準ポリシーから適切なポリシーにチェックを入れる。ここでは AWSLambdaBasicExecutionRole を選択する。注)セキュリティ上適切なポリシーを選択することは重要。こちらに AWS 標準ポリシーの一覧があるので "AWSLambda" でポリシー名を検索して AWSLambdaBasicExecutionRole より適切なものがあればそちらを選択する。"Action" に注目して比較するとよい。
- 「ロール名」は lambda-gateway-execution-role とする。
- 「ロールの作成」をクリック。
- 今作成した lambda-gateway-execution-role (チェックを入れるのではなくロール名)をクリック
- ロール ARN をメモする(arn:で始まる文字列)。これは次のステップで Lambda 関数を作るのに必要
3-3. Lambda 関数を作成する
1.AWS CLI へログインする。
2.以下のコマンドで lambda 関数を作成する。arn: には前の手順で取得したものを、region と profile には適切なものを指定する。zip-file 名と handler 名は function-name と同じにする必要がある模様。
$ aws lambda create-function --region us-west-2 \
--function-name LF4CiscoSpark \
--zip-file fileb://LF4CiscoSpark.zip \
--role arn:xxxxxxxxxxxxxxxxxx \
--handler LF4CiscoSpark.handler \
--runtime python3.6 \
--profile adminuser
※ なお、コードを update するときは以下:
$ aws lambda update-function-code \
--function-name LF4CiscoSpark \
--zip-file fileb://LF4CiscoSpark.zip
3-4. API Gateway を作成する
今回 API Gateway の作成には AWS CLI を使う。少々ステップが多いが、CLI での作業結果を逐一 AWS コンソールで確認しながら作業を行うとわかりやすい。
3-4-1. API の作成
1.AWS CLI へログインする。
2.以下のコマンドで API4CiscoSpark という名の API を作成する。作成に成功すると API を識別するための API ID が生成される。
※ API が生成されるとルートリソースも同時に生成される。次の手順でルートリソースの子リソースを作成するが、そのためのはルートリソースの ID も必要。
$ aws apigateway create-rest-api \
--name API4CiscoSpark \
--region us-west-2 \
--profile adminuser
(以下実行結果)
{
"name": "API4CiscoSpark",
"createdDate": 1501839827,
"id": "" # API ID
}
AWS コンソールの表示結果(API Gateway):
3.API のルートリソースの ID を調べる:
$ aws apigateway get-resources \
--rest-api-id (API ID)
(以下実行結果)
{
"items": [
{
"path": "/",
"id": "" # ROOT RESOURCE ID
}
]
}
3-4-2. API 子リソースの作成
1.以下のコマンドで API4CiscoSpark API の子リソース Resource4CiscoSpark を作成する:
$ aws apigateway create-resource \
--rest-api-id (API ID) \
--parent-id (ROOT RESOURCE ID) \
--path-part Resource4CiscoSpark
(以下実行結果)
{
"pathPart": "Resource4CiscoSpark",
"parentId": "",
"path": "/Resource4CiscoSpark",
"id": "" # RESOURCE ID
}
AWS コンソールの表示結果(API Gateway):
3-4-3. メソッドの作成
1.以下のコマンドで Resource4CiscoSpark リソースに POST メソッドを追加する:
$ aws apigateway put-method \
--rest-api-id (API ID) \
--resource-id (RESOURCE ID) \
--http-method POST \
--authorization-type NONE
AWS コンソールの表示結果:
3-4-4. Lambda 関数を POST メソッドの送信先に設定
1.以下のコマンドで Lambda 関数を POST メソッドの送信先に設定する。(アカウント番号) には AWS のアカウント番号12桁の数字を入れる:
$ aws apigateway put-integration \
--rest-api-id (API ID) \
--resource-id (RESOURCE ID) \
--http-method POST \
--type AWS \
--integration-http-method POST \
--uri arn:aws:apigateway:(region):lambda:path/2015-03-31/functions/arn:aws:lambda:(region):(アカウント番号):function:LF4CiscoSpark/invocations
AWS コンソールの表示結果(API Gateway):
3-4-5. POST メソッドのレスポンスを JSON に設定
1.以下のコマンドで POST メソッドのレスポンスを JSON に設定する。この設定により API メソッドが返すレスポンスのタイプが指定される。
$ aws apigateway put-method-response \
--rest-api-id (API ID) \
--resource-id (RESOURCE ID) \
--http-method POST \
--status-code 200 \
--response-models "{\"application/json\": \"Empty\"}"
3-4-6. POST メソッドの統合レスポンスを JSON に設定
1.以下のコマンドで POST メソッドの統合レスポンスを JSON に設定する。この設定により
Lambda 関数が返すレスポンスのタイプを指定している。
$ aws apigateway put-integration-response \
--rest-api-id (API ID) \
--resource-id (RESOURCE ID) \
--http-method POST \
--status-code 200 \
--response-templates "{\"application/json\": \"\"}"
AWS コンソールの表示結果(API Gateway):
3-4-7. API をデプロイする
1.次のコマンドで、作成した API を prod (プロダクション=本番環境)というステージにデプロイする:
$ aws apigateway create-deployment \
--rest-api-id (API ID) \
--stage-name prod
AWS コンソールの表示結果(API Gateway):
「URL の呼び出し」の右側に記載されている URL が Cisco Spark の Webhook 用 Target URL となる。
3-4-8. Lambda のトリガーとして API Gateway を指定する
$ aws lambda add-permission \
--function-name LF4CiscoSpark \
--statement-id apigateway \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:us-west-2:(アカウント番号):(API ID)/prod/POST/Resource4CiscoSpark"
AWS コンソールの表示結果(AWS Lambda):
4. 設定の完了と動作確認
4-1. Cisco Spark で Webhook を設定
Webhook を設定するには、HTTP PUT を以下の条件で実行すればよい:
- URL:
- ヘッダ
- 'Authorization' : 'Bearer ' + Bot のアクセスコード
- 'Content-Type' : 'application/json' を指定
- ペイロード
- 'name' : webhook の名前を任意でつける
- 'targetUrl' : Amazon API Gateway で設定した Target URL
- 'resource' : 'message' を指定する
- 'event' : 今回は webhook を作るので 'created' を指定する
- 'filter' : 'roomId=' に続けて Bot の所属する roomId を指定する
roomId はこちらから調査可能。
import requests
access_code = '' # ここに Access Code を入力
url = 'https://api.ciscospark.com/v1/webhooks'
headers = {
'Authorization' : 'Bearer ' + access_code,
'Content-Type' : 'application/json'
}
r = requests.put(url, headers = headers)
{
'name' : 'My Awesome Webhook',
'targetUrl' : 'https://example.com/mywebhook',
'resource' : 'messages',
'event' : 'created',
'filter' : 'roomId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
}
4-2. 動作確認
Cisco Spark にて Bot にメンションして "ping" と入力すると、Bot が "pong" と返してくれる。
(補足)API Gateway のログを生成するには
1.AWS コンソールで API Gateway サービスを開く。
2.「API名(API4CiscoSpark)」>「ステージ」>「prod」とクリックして「設定」タブを表示する。
3.「CloudWatch ログを有効化」にチェックを入れる。「ログレベル」を設定する。
4.「変更を保存」
5.CloudWatch にてログを確認可能