Amazon Connectを使って電話からEC2を再起動する
はじめに
Amazon Connectでは、事前に用意された処理を組み合わせることで、自由に電話応対フロー(Contact Flow)を作成することができます。 例えば、通話中にユーザがプッシュした番号によって案内の内容を変えたり、ユーザの電話番号によってどのオペレータにつながるか指定することができます。 事前に用意された処理はブロックと呼ばれていますが、その中にはAWS Lambdaを実行するブロックも含まれています。 なので、電話でAWSリソースの参照や操作ができます。 今回はAmazon ConnectをつかってEC2インスタンスを再起動する仕組みを作りました。
概要
電話をかけると次のようなやりとりが発生します。 (Amazon Connect)
You have 3 instances. Which one do you want to reboot? i-xxxxxx is number 0. i-yyyyyyy is number 1. i-zzzzzzz is number 2.
(ユーザ) "1#"と押す
(Amazon Connect) 指定されたi-yyyyyyyの再起動を開始した後
i-yyyyyyy is rebooting now.
電話切れる。
今回作ったContact Flowです。 下記のような処理を行っています。
処理の単位であるブロックの一覧はこちらをご覧ください。 現時点で30個近いブロックが用意されていますが、今回利用するのは次の5つです。
- Check contact attributes: 電話番号等ユーザ情報を元に処理を分岐させる
- Play prompt: ユーザにメッセージを返す
- Store customer input: ユーザにメッセージを返した後、ユーザから入力(プッシュ番号)を受け取り、保存する
- Invoke AWS Lambda function: Lambdaファンクションを実行する
- Disconnect / hang up: 電話を切る
Contact Flowの作成
Contact Flowの作成はVirtual contact center instanceの管理ページから行います。 https://{エンドポイント}/connect/contact-flows Virtual contact center instanceの作成方法はこちらのエントリーを参照ください。 AWSのコールセンターサービス Amazon Connectの試し方
画面右上にある「Create contact flow」から作成を開始します。
発信元チェック
「Check contact attributes」ブロックで電話の発信元をチェックしています。 知らない人が僕のサーバを再起動するのは避けたいからです。
僕の電話番号以外から電話がかけられた場合、「Play prompt」ブロックでメッセージを流して「Disconnect / hang up」ブロックで電話を切ります。
EC2インスタンスリストの取得
発信元の電話番号に問題がない場合、「Invoke AWS Lambda function」ブロックでAWS Lambdaファンクションを呼び出し、インスタンスIDのリストを受け取ります。 このブロックで指定するのはLambdaファンクションのARNとLambdaに渡すパラメータです。ここでは"Action: List"というパラメータを渡しています。 注意が必要なのはTimeoutの最大値が8秒と短い点です。なので、時間がかかる処理には向きません。
AWS Lambdaファンクション側のコードです。
import boto3 def lambda_handler(event, context): ec2 = boto3.client("ec2") resultMap = {} action = event['Details']['Parameters']['Action'] if action == 'List': instances = ec2.describe_instances() if len(instances['Reservations']) == 0: resultMap['NumInstances'] = '0' else: instance_ids = [i['InstanceId'] for r in instances['Reservations'] for i in r['Instances']] resultMap['NumInstances'] = str(len(instance_ids)) resultMap['InstanceIds'] = ','.join(instance_ids) resultMap['InstanceIdList'] = '<speak>You have %s instances. Which one do you want to reboot?' % len(instance_ids) for i, instance_id in enumerate(instance_ids): resultMap['InstanceIdList'] += '<say-as interpret-as="characters">%s</say-as> is number %s.' % (instance_id, i) resultMap['InstanceIdList'] += '</speak>' elif action == 'Reboot': instance_ids = event['Details']['Parameters']['InstanceIds'].split(',') instance_id = instance_ids[int(event['Details']['Parameters']['InstanceIndex'])] ec2.reboot_instances(InstanceIds=[instance_id]) resultMap['RebootInstance'] = '<speak><say-as interpret-as="characters">%s</say-as> is rebooting now.</speak>' % (instance_id) return resultMap
「Invoke AWS Lambda function」ブロックから渡されたパラメータは"event['Details']['Parameters']"で受け取ります。 また、Lambdaからの返り値はAWS Connectで利用できます。 Lambdaファンクションには必要な権限を持ったIAMロールを割り当ててください。
LambdaがAWS Connectから受け取る値や返り値の制限等、詳しい説明は下記ページを参照ください。 Granting Amazon Connect Access to AWS Lambda Functions AWS ConnectからLambdaを呼び出すために、リソースポリシーの設定も必要です。その設定方法もこのページに記載されています。
ユーザによるインスタンスの選択
Lambdaから返されたEC2インスタンスのリストをユーザに提示し、リブートするインスタンスを選択させましょう。 「Store customer input」ブロックを使います。 先ほどのLambdaファンクションのレスポンスはこんな感じなので、InstanceIdListの内容をユーザに伝えます。
{ 'InstanceIdList': '<speak>You have 3 instances.Which one do you want to reboot?<say-as interpret-as="characters">i-xxxx</say-as> is number 0.<say-as interpret-as="characters">i-yyyy</say-as> is number 1.<say-as interpret-as="characters">i-zzzz</say-as> is number 2.</speak>', 'InstanceIds': 'i-xxxx,i-yyyy,i-zzzz' }
ここでユーザが入力した数字はシステムに保存されます。
インスタンス再起動
リブートするインスタンスが選択されたので、「Invoke AWS Lambda function」ブロックで指定のインスタンスを再起動します。 今回は3つのパラメータを送っています。
- Action: Reboot
- InstanceIds: (先ほどLambdaからかえされたInstanceId)
- InstanceIndex: (ユーザの入力した番号)
画像からは見切れていますが、ARNは先ほどのLambdaファンクションと同じにしています。 なので、先ほどのLambdaファンクションが上記パラメータを受け取り、指定されたインスタンスをリブートします。
終了
リブート開始後、LambdaからAmazon Connectに
{ 'RebootInstance': u'<speak><say-as interpret-as="characters">i-zzzz</say-as> is rebooting now.</speak>' }
のような値が返されるので「Play prompt」ブロックでユーザに伝えます。
電話を切るために「Disconnect / hang up」ブロックにつなげて終了です。
最後に
Amazon Connectを使って電話からEC2を再起動する仕組みを作りました。 読み上げのリプレイやユーザ選択の確認、エラー処理等、実際はもっと作り込みが必要ですが基本的なフローであればあっという間に作ることができます。 Amazon Connectはコールセンター以外の用途としても便利なのでぜひ使って見てください。