アラート発生時に AWS Lambda を使って音声電話をかける


続編：[SNS + Lambda + Twilio で音声電話をかける v2](http://qiita.com/u-minor/items/d72e77e79203aab6ca70)

CloudWatch や独自ツールから Amazon SNS に Notification を飛ばすと、subscribe しているメールアドレスにメール通知が行えます。

サービスの監視を行ってアラートをメールで受信しているケースが多いと思いますが、深夜等でメールを受信しても気づかないケースがあり、障害検知が遅れてしまう、という問題があります。
これを回避するために、電話をかけることにしてみました。

電話をかけるのに使うサービスは [Twilio](http://twilio.kddi-web.com/)。日本ではKDDIが業務提携してサービスを提供しています。

Amazon SNS から AWS Lambda への通知が可能になっていますので、Lambda を使って実装します。

> ~~Lambda は現時点で東京リージョンでは使えないため、N.Virginia を使います。~~
> 7/1 修正: 東京リージョンでも利用可能になりました。

## Twilio の設定

### 電話番号の購入

[Twilio](http://twilio.kddi-web.com/) にサインアップし、発信用の電話番号を購入します。

「VOICE, SMS & MMS」から「電話番号」に進み、電話番号を購入します。
購入した電話番号は後で使うので、メモしておきます。

![Twilio_User_-_Account_Phone_Numbers_Incoming.png](https://qiita-image-store.s3.amazonaws.com/0/15611/50d34fa3-559d-e929-e2b0-f248e511ca49.png "Twilio_User_-_Account_Phone_Numbers_Incoming.png")

050から始まる番号であれば、月額108円で安いです。監視用なので、これで十分です。

### API 用認証情報の確認

アカウントメニューから「アカウント」を選択すると、REST API 用の認証情報が表示されます。
ここに表示される `AccountSID` および `AuthToken` は後で使うので、メモしておきます。

![Twilio_User_-_Account_Settings.png](https://qiita-image-store.s3.amazonaws.com/0/15611/4e1cec9c-377b-a2b5-e690-0e699014a299.png "Twilio_User_-_Account_Settings.png")

## Lambda function の作成

リージョンを N.Virginia に切り替え、Lambda で新規に function を作成します。

![AWS_Lambda.png](https://qiita-image-store.s3.amazonaws.com/0/15611/ce888149-0ed0-9081-6713-a2d2e86b1cb8.png "AWS_Lambda.png")

Role には、特にこれまでに作成していなければ、「Basic execution role」を選択して新規に作成します。

以下、Twilio API を呼び出す JS コードです。
先ほどメモした発信用の電話番号および、認証情報を埋めてください。

```javascript
var accountSid = 'YOUR_TWILIO_ACCOUNT_SID';
var authToken = 'YOUR_TWILIO_AUTH_TOKEN';
var fromNumber = '+81XXXXXXXXXX';
var toNumber = '+81XXXXXXXXXX';
var configUrl = 'http://YOUR.HOST/PATH/TO/TwiML.xml';

var https = require('https');
var queryString = require('querystring');

exports.handler = function (event, context) {
  console.log('Start twilio call');

  callTwilio(function(status) {
    context.done(null, status);
  });
};

function callTwilio(callback) {
  var messageString = queryString.stringify({
    From: fromNumber,
    To: toNumber,
    Url: configUrl,
    Method: 'GET'
  });

  var options = {
    host: 'api.twilio.com',
    port: 443,
    path: '/2010-04-01/Accounts/' + accountSid + '/Calls.json',
    method: 'POST',
    headers: {
      'Authorization': 'Basic ' + new Buffer(accountSid + ':' + authToken).toString('base64'),
      'Content-Type': 'application/x-www-form-urlencoded',
      'Content-Length': Buffer.byteLength(messageString)
    }
  };

  var req = https.request(options, function(res) {
    res.setEncoding('utf-8');

    var responseString = '';
    res.on('data', function(data) {
      responseString += data;
    });

    res.on('end', function() {
      console.log('Twilio Response: ' + responseString);
      callback('API request sent successfully.');
    });
  });

  req.on('error', function(e) {
    console.error('HTTP error: ' + e.message);
    callback('API request completed with error(s).');
  });

  console.log('Twilio API call: ' + messageString);
  req.write(messageString);
  req.end();
}
```

`configUrl` で指定する TwiML は、こんな感じで。

```TwiML.xml
<Response>
<Say language="ja-JP" voice="alice">これはアラート通知テストです。</Say>
<Pause length="1"/>
<Say language="ja-JP" voice="alice">詳細は XXXX までお問い合わせください。</Say>
</Response>
```

`voice="alice"` だと女性の声で喋ってくれます。日本語文章も問題なく喋ってくれますが、クオリティはまだ低いのであまり嬉しくはありません。。

## Amazon SNS との連携

Lambda の Function list に戻ると、作成した fcuntion が現れています。ARN をコピーし、Amazon SNS の管理画面に移動します。

~~恐らく同一リージョンであれば「Actions」の「Add event source」から SNS の Topic を選べるのでしょうが、Lambda と SNS のリージョンが異なるからか、候補リストに何も表示されないため、SNS 側から設定します。~~

7/1 追記：東京リージョンで Function を作成すれば、「Add event source」で SNS の Topic を割り当てられます。

![AWS_Lambda.png](https://qiita-image-store.s3.amazonaws.com/0/15611/c036199b-b8de-7b8b-74fb-36762fa50873.png "AWS_Lambda.png")

SNS の管理画面から「Create Subscription」を選び、Protocol を「AWS Lambda」に、Endpoint にコピーした Function ARN を入れれば完了です。

![AWS_SNS.png](https://qiita-image-store.s3.amazonaws.com/0/15611/35012848-08a0-ad6f-9cb6-ec9e78f2ace5.png "AWS_SNS.png")

これで、Amazon SNS に通知が来ると、AWS Lambda の function が実行され、Twilio API が呼び出されて電話がかかってきます。

## 応用

Twilio で電話をかけるには、TwiML で記述された XML を準備する必要があります。
この例では固定の文言を喋らせていますが、動的なメッセージを喋らせる場合は、S3 にメッセージを都度出力し、その URL を渡すようにするなどの工夫が必要です。
また、Twilio はステータス受信用のコールバック API を定義できますので、電話に出なかった場合などは次の人に電話をかける、等の処理を行ってみるのもいいかと思います。

続編：[SNS + Lambda + Twilio で音声電話をかける v2](http://qiita.com/u-minor/items/d72e77e79203aab6ca70)

--------
- 7/1
  - AWS Lambda が東京リージョンで利用可能になったので、一部修正