【簡易版】AmazonConnectによる自動電話通知(まとめ)

【簡易版】AmazonConnectによる自動電話通知(まとめ)

監視サーバーで障害を検知した際に、自動で電話通知できるようにしていきます。ネットワークエンジニアも利用することの多い監視サーバー(Zabbix)で障害検知し、AWS上のAmazonConnectを利用し自動電話を発信します。

今回は下記の条件を満たせるようにAWSの各サービスを利用して自動電話通知の仕組みを導入します。

前提条件
  • 複数の通知先を登録した連絡先リストを持たせる。
  • 連絡先リストに優先度(通知順)を設定する。
  • 優先度が高い人に最初に電話する。
  • 応答が無かった場合、次の優先度の人に順番に電話する。
  • 連絡先リストの最後まで電話しても応答が無かった場合、最初に戻って継続する。
  • 最大周回数を指定する。

AmazonConnectによる自動電話通知の詳細な説明は下記を参照してください。

AmazonConnectによる自動電話通知(1.インスタンスの作成)

目次

自動電話通知フロー

電話に応答した場合のフロー

電話に応答した場合のフロー
  1. EC2上の監視サーバーで障害を検知し、S3へトリガーファイルを格納
  2. S3のイベント通知機能で、SQS_1にメッセージを送信
  3. SQS_1をトリガーとして、Lambda_1を起動
  4. Lambda_1がDynamoDB_1から連絡先を取得し、AmazonConnectを起動
  5. Lambda_1がAmazonConnectを起動すると同時に、SQS_2へメッセージを送信
  6. AmazonConnectがユーザーへ自動電話通知を実施
  7. ユーザが正常応答し、AmazonConnectがLambda_2を起動
  8. Lambda_2が応答結果をDynamoDB_2に保存(応答OK)
  9. 60秒後にSQS_2をトリガーとしてLambda_3を起動
  10. Lambda_3がDynamoDB_2の応答結果を確認(正常応答しているため、何もせずに処理完了)

電話に応答しなかった場合のフロー

電話に応答しなかった場合のフロー
  1. EC2上の監視サーバーで障害を検知し、S3へトリガーファイルを格納
  2. S3のイベント通知機能で、SQS_1にメッセージを送信
  3. SQS_1をトリガーとして、Lambda_1を起動
  4. Lambda_1がDynamoDB_1から連絡先を取得し、AmazonConnectを起動
  5. Lambda_1がAmazonConnectを起動すると同時に、SQS_2へメッセージを送信
  6. AmazonConnectがユーザーへ自動電話通知を実施
  7. ユーザが正常応答せず、AmazonConnectがLambda_2を起動
  8. Lambda_2が応答結果をDynamoDB_2に保存(応答NG ※実際にはステータスを変更しない)
  9. 60秒後にSQS_2をトリガーとしてLambda_3を起動
  10. Lambda_3がDynamoDB_2の応答結果を確認
  11. 正常応答していないため、再度AmazonConnectを起動(以降、5から繰り返し)

EC2上での監視サーバーの構築

EC2上でのZabbixの構築はこちらを参照してください。

AWS上での監視サーバー(Zabbix)構築

ZabbixからのAmazonConnectの起動についてはこちらを参照してください。

AmazonConnectによる自動電話通知(5.EC2/ZABBIXとの連携)

スクリプトは下記の通り作成します。

cd /usr/lib/zabbix/alertscripts/
sudo vi amazonconnect_notification.sh
(下記を記述)
-----------------------
#!/bin/sh

echo "`date` Amazon Connect Notification" >> /tmp/zabbix-amazonconnect.log

aws s3 cp /tmp/test.txt s3://amazonconnect-alert-notification-bucket
-----------------------

AmazonConnectのインスタンス作成・電話番号取得

下記を参照し、AmazonConnectのインスタンスを作成し、電話番号を取得します。

AmazonConnectによる自動電話通知(1.インスタンスの作成)
AmazonConnectによる自動電話通知(2.電話番号の取得)

SQSの作成

SQS_1を作成(S3からイベント通知を受け取るキュー)

下記の通り選択・入力し、SQS_1を作成します。

タイプ:「標準」を選択
名前:任意の名前を入力 ※ここでは、”amazonconnect-queue-trriger”としています。
設定:デフォルト
アクセスポリシー:「アドバンスト」を選択し、以下を記載します。

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__owner_statement",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": "SQS:*",
      "Resource": "arn:aws:sqs:ap-northeast-1:XXXXXXXXXXXXX:amazonconnect-queue-trriger",
      "Condition": {
        "ArnLike": {
          "aws:SourceArn": "arn:aws:s3:*:*:amazonconnect-alert-notification-bucket"
        }
      }
    }
  ]
}
SQSの作成

SQS_2を作成(Lambda_3を起動するキュー)

下記の通り選択・入力し、SQS_2を作成します。

タイプ:「標準」を選択
名前:任意の名前を入力 ※ここでは、”amazonconnect-queue-confirm”としています。
設定:配信遅延を「1分」に設定

SQS作成

S3の作成

S3のバケット作成

バケット名を入力し、それ以外はデフォルトのままでバケットを作成します。

S3のイベント通知設定

作成したS3バケットのイベント通知を作成します。

イベント名:任意の名前を入力 ※ここでは、”amazonconnect-launch”としています。
イベントタイプ:「すべてのオブジェクト作成イベント」にチェック
送信先:「SQSキュー」を選択
SQSキューを特定:「SQSキューから選択する」を選択
SQSキュー:作成したSQS_1を選択

イベント通知の作成

DynamoDBの作成

DynamoDB_1を作成(連絡先情報を格納するDB)

下記の通り入力し、テーブルを作成します。

テーブル名::任意の名前を入力 ※ここでは、”amazonconnect-contact-list”としています。
パーティションキー:「No」と入力し、「数値」を選択
ソートキー:「Name」と入力し、「文字列」を選択

テーブルの作成

以下の通り、項目を作成します。

No:通番を入力
Name:通知先名を入力
Phone:電話番号を入力 ※新しい属性を文字列で追加
Priority:連絡順を入力 ※新しい属性を数値で追加

DynamoDB_1の項目

DynamoDB_2を作成(通知結果を保存するDB)

下記の通り入力し、テーブルを作成します。

テーブル名::任意の名前を入力 ※ここでは、”amazonconnect-response-status”としています。
パーティションキー:「No」と入力し、「数値」を選択
ソートキー:「Name」と入力し、「文字列」を選択

DynamoDB_2の作成

以下の通り、項目を作成します。

No:”1″を入力
Name:”Response”を入力
CallStatus:”NG”を入力 ※新しい属性を文字列で追加

DynamoDB_2の項目

Lambdaの作成

Lambda_1を作成

Lambda_1を下記の通り作成します。(最大周回数を2としています。)

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

# boto3からDynamoDBへアクセスするためのオブジェクトを取得
dynamodb = boto3.resource('dynamodb')

# "amazonconnect-contact-list"へアクセスするためのオブジェクトを取得
contactlist = dynamodb.Table("amazonconnect-contact-list")

# "amazonconnect-response-status"へアクセスするためのオブジェクトを取得
responsestatus = dynamodb.Table("amazonconnect-response-status")

# CallStatusを"NG"に変更する関数
def status_ng():
    response = responsestatus.update_item(
        Key={
            'No': 1,
            'Name': "Response"
        },
        UpdateExpression="set CallStatus=:c",
        ExpressionAttributeValues={
            ':c': "NG"
        },
        ReturnValues="UPDATED_NEW"
    )
    return response


# "amazonconnect-contact-list"の内容を返す関数
def operation_scan():

    scanData = contactlist.scan()
    items=scanData['Items']

    return scanData["Items"]


# 指定されたプライオリティの電話番号を返す関数
def get_phone_number(json_contactinfo, now_priority):
    
    for line in json_contactinfo:
        if line['Priority']==now_priority:
            phone_number = line['Phone']

    return phone_number


def lambda_handler(event, context):
    
    # 応答結果を初期化
    status_ng()
    
    # 電話番号リストを取得
    contactinfo = operation_scan()

    # 初回のプライオリティを"1"に設定
    priority = 1

    # 周回数を"2"に設定
    cycle = 2

    # 指定したプライオリティの電話番号を取得
    phone_number = get_phone_number(contactinfo, priority)

    # boto3からAmazonConnectへアクセスするためのオブジェクトを取得
    connect = boto3.client('connect')

    # AmzaonConnectの問い合わせフローを呼び出し電話発信
    connect.start_outbound_voice_contact(
        DestinationPhoneNumber=phone_number,
        ContactFlowId='************************************',
        InstanceId='************************************',
        SourcePhoneNumber='+81**********',
    )

    # boto3からSQSへアクセスするためのオブジェクトを取得
    sqs = boto3.resource('sqs')

    # "amazonconnect-queue-confirm"へアクセスするためのオブジェクトを取得
    name = 'amazonconnect-queue-confirm'
    queue = sqs.get_queue_by_name(QueueName=name)

    # 現在のプライオリティと周回数をセットしてステータス確認用のキューにメッセージ送信
    response = queue.send_message(MessageBody=json.dumps({"priority": priority, "cycle": cycle}))

ContactFlowId:問い合わせフローID
InstanceId:インスタンスID
SourcePhoneNumber:発信元の電話番号
※国番号をつけて記述(日本の050の番号の場合、+8150********)

Lambda_1のコード修正

Lambda_2を作成

Lambda_2を下記の通り作成します。

import boto3
import json
from boto3.dynamodb.conditions import Key, Attr

# boto3からDynamoDBへアクセスするためのオブジェクトを取得
dynamodb = boto3.resource('dynamodb')

# "amazonconnect-response-status"へアクセスするためのオブジェクトを取得
responsestatus = dynamodb.Table("amazonconnect-response-status")

# CallStatusを"OK"に変更する関数
def status_ok():
    response = responsestatus.update_item(
        Key={
            'No': 1,
            'Name': "Response"
        },
        UpdateExpression="set CallStatus=:c",
        ExpressionAttributeValues={
            ':c': "OK"
        },
        ReturnValues="UPDATED_NEW"
    )
    return response


def lambda_handler(event, context):
    
    # 通知先の電話番号を取得
    destphone = event['Details']['ContactData']['CustomerEndpoint']['Address']

    # ユーザーの応答結果を取得
    pressnum = event['Details']['ContactData']['Attributes']['pressnum']

    # ユーザーの応答結果がOKの場合、CallStatusをOKに変更し、通知成功のログを出力
    if pressnum == "1":
        status_ok()
        print(destphone + "への通知に成功しました。")

    # ユーザーの応答結果がOKの場合、通知失敗のログを出力
    else:
        print(destphone + "への通知に失敗しました。")

    return {
        'statusCode': 200
    }
Lambda_2のコード

Lambda_3を作成

Lambda_3を下記の通り作成します。

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr

# boto3からDynamoDBへアクセスするためのオブジェクトを取得
dynamodb = boto3.resource('dynamodb')

# "amazonconnect-contact-list"へアクセスするためのオブジェクトを取得
contactlist = dynamodb.Table("amazonconnect-contact-list")

# "amazonconnect-response-status"へアクセスするためのオブジェクトを取得
responsestatus = dynamodb.Table("amazonconnect-response-status")

# 残り周回数を取得する関数
def get_cycle(sqs_event):

    record = sqs_event['Records'][0]
    json_record = json.loads(record["body"])
    cycle = json_record["cycle"]

    return cycle


# "amazonconnect-response-status"の内容を返す関数
def status_scan():
    
    scanData = responsestatus.scan()
    items=scanData['Items']

    return scanData["Items"]


# "amazonconnect-contact-list"の内容を返す関数
def operation_scan():

    scanData = contactlist.scan()
    items=scanData['Items']

    return scanData["Items"]


# 電話番号リストの行数を返す関数
def get_contactinfo_item_number(json_contactinfo):

    count = 0
    
    for line in json_contactinfo:
        count += 1

    return count


# 前回のプライオリティを返す関数
def get_before_priority(sqs_event):

    record = sqs_event['Records'][0]
    json_record = json.loads(record["body"])
    priority = json_record["priority"]

    return priority


# 指定されたプライオリティの電話番号を返す関数
def get_phone_number(json_contactinfo, now_priority):
    
    for line in json_contactinfo:
        if line['Priority']==now_priority:
            phone_number = line['Phone']

    return phone_number


def lambda_handler(event, context):

    # 残り周回数を取得
    now_cycle = get_cycle(event)

    # 応答結果を確認
    statustinfo = status_scan()

    # 応答結果がNGの場合
    if statustinfo[0]['CallStatus'] == "NG":
        
        # 電話番号リストを取得
        contactinfo = operation_scan()

        # 電話番号リストの行数を取得
        contactinfo_item_number = get_contactinfo_item_number(contactinfo)

        # 前回のプライオリティを取得
        before_priority = get_before_priority(event)

        # 前回のプラオリティが電話番号リストの行数と同じ場合(リストの最後まで通知した場合)
        if before_priority == contactinfo_item_number:
            
            # プライオリティを1に設定(最初に戻る)
            priority = 1

            # 残り周回数を1減らす
            now_cycle -= 1

        # 前回のプラオリティが電話番号リストの行数と異なる場合(リストの最後まで通知していない場合)
        else:

            # プライオリティに1を足す(次のプライオリティを設定)
            priority = before_priority + 1

        # 残り周回数が0以外の場合
        if now_cycle != 0:

            # 指定したプライオリティの電話番号を取得
            phone_number = get_phone_number(contactinfo, priority)
    
            # boto3からAmazonConnectへアクセスするためのオブジェクトを取得
            connect = boto3.client('connect')
    
            # AmzaonConnectの問い合わせフローを呼び出し電話発信
            connect.start_outbound_voice_contact(
                DestinationPhoneNumber=phone_number,
                ContactFlowId='************************************',
                InstanceId='************************************',
                SourcePhoneNumber='+81**********',
            )
    
            # boto3からSQSへアクセスするためのオブジェクトを取得    
            sqs = boto3.resource('sqs')
    
            # "amazonconnect-queue-confirm"へアクセスするためのオブジェクトを取得
            name = 'amazonconnect-queue-confirm'    
            queue = sqs.get_queue_by_name(QueueName=name)
    
            # 現在のプライオリティと周回数をセットしてステータス確認用のキューにメッセージ送信
            response = queue.send_message(MessageBody=json.dumps({"priority": priority, "cycle": now_cycle}))

ContactFlowId:問い合わせフローID
InstanceId:インスタンスID
SourcePhoneNumber:発信元の電話番号
※国番号をつけて記述(日本の050の番号の場合、+8150********)

Lambda_3のコード修正

AmazonConnectの問い合わせフロー作成

下記を参照し問い合わせフローを作成します。

AmazonConnectによる自動電話通知(7.複数連絡先への電話通知〈構築③〉)
AmazonConnectによる自動電話通知(7.複数連絡先への電話通知〈構築⑥〉)

以上で、【簡易版】AmazonConnectによる自動電話通知(まとめ)の説明は完了です!

  • URLをコピーしました!
  • URLをコピーしました!
目次