Amazon Connectを使って電話からEC2を再起動する

2017.03.31

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

はじめに

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です。 amazon-connect-contact-flow 下記のような処理を行っています。 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」から作成を開始します。 Screen Shot 2017-03-30 at 6.14.55 PM

発信元チェック

「Check contact attributes」ブロックで電話の発信元をチェックしています。 知らない人が僕のサーバを再起動するのは避けたいからです。 caller-check

僕の電話番号以外から電話がかけられた場合、「Play prompt」ブロックでメッセージを流して「Disconnect / hang up」ブロックで電話を切ります。 deny-call

EC2インスタンスリストの取得

発信元の電話番号に問題がない場合、「Invoke AWS Lambda function」ブロックでAWS Lambdaファンクションを呼び出し、インスタンスIDのリストを受け取ります。 Screen Shot 2017-03-30 at 6.28.59 PM このブロックで指定するのはLambdaファンクションのARNとLambdaに渡すパラメータです。ここでは"Action: List"というパラメータを渡しています。 注意が必要なのはTimeoutの最大値が8秒と短い点です。なので、時間がかかる処理には向きません。 list-instances

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」ブロックを使います。 select-instance 先ほどの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: (ユーザの入力した番号)

Screen Shot 2017-03-30 at 6.54.27 PM 画像からは見切れていますが、ARNは先ほどのLambdaファンクションと同じにしています。 なので、先ほどのLambdaファンクションが上記パラメータを受け取り、指定されたインスタンスをリブートします。

終了

リブート開始後、LambdaからAmazon Connectに

{
  'RebootInstance': u'<speak><say-as interpret-as="characters">i-zzzz</say-as> is rebooting now.</speak>'
}

のような値が返されるので「Play prompt」ブロックでユーザに伝えます。 Screen Shot 2017-03-30 at 7.17.43 PM

電話を切るために「Disconnect / hang up」ブロックにつなげて終了です。 Screen Shot 2017-03-30 at 7.19.06 PM

最後に

Amazon Connectを使って電話からEC2を再起動する仕組みを作りました。 読み上げのリプレイやユーザ選択の確認、エラー処理等、実際はもっと作り込みが必要ですが基本的なフローであればあっという間に作ることができます。 Amazon Connectはコールセンター以外の用途としても便利なのでぜひ使って見てください。

参考URL