電話をかけるとサーバーが削除される（ConoHa API + Twilio）

この記事は、[ConoHa Advent Calendar2016](http://qiita.com/advent-calendar/2016/conoha)の18日目くらいの記事です。

どうも、ConoHa愛好会の皆様。

旧ConoHaのアカウントから新アカウントに
簡単にサーバー紐付けを移せるだろうと余裕ぶっこいてたら
普通にサーバー移管させられて悲しかったです。

それはさておき、スパイ映画をよくみる僕は
緊急時に大事な情報は削除出来るようにしなければと考えている訳ですが
諸兄らにおいても、敵スパイに拘束されたり
FBIが家に突入してきそうだったり
突然海外逃亡を余儀なくされるケースが有るかと思います。

そんなとき！！
ConoHaにデータを残したままにしておくわけにはいかない…！
もしこのはちゃんが勝手にいじられるなんて事が起きたら…！

困るよね？
（ここまで前置き）

なので、電話でサーバーを削除出来るようにしておきたいと思います。
（技術的にはブームが過ぎ去ったし実用性が皆無の話が以下続きます）

ConoHa API + Twilio の話なので、ご存知の方には何も面白くありませんが
一応軽い説明程度と一緒に、書いていきます。

# 今回のフロー
![フローチャート](https://qiita-image-store.s3.amazonaws.com/0/25480/f901f18c-ab71-d340-e5b4-db15db371532.png)


# サーバーの作成
まず、削除されるためだけに、サーバーを生み出します。
せっかくなので、テストに最適な新しい512MBプランで！

![サーバー作成](https://qiita-image-store.s3.amazonaws.com/0/25480/80a77d76-66a4-bd56-8f40-8ec4946b9d71.png)
こんな感じのを２〜３個適当に。

```
$ ssh ConoHaAC2016

================================================
Welcome LAMP application!

DocumentRoot: /var/www/html
URL:          http://xxx.xxx.xxx.xxx/
phpinfo:      http://xxx.xxx.xxx.xxx/phpinfo.php
MySQL root password: xxxxxx

Enjoy!

To delete this message: rm -f /etc/motd
================================================
[root@xxx-xxx-xxx-xxx ~]# 
```
初めてLAMPで作りました。
こんな表示出してくれるんですね〜。

# Twilioの設定
まずアカウントを適当に作成し、電話番号を取得して下さい。

この画面のサイドバーから、「ツール」を選んで
![電話番号一覧](https://qiita-image-store.s3.amazonaws.com/0/25480/f94c5606-e368-a47e-dd36-bb3f903cdcbb.png)


TwiML Apps の設定に入るので、新規作成。
![TwiML Apps](https://qiita-image-store.s3.amazonaws.com/0/25480/002962f7-6fca-a365-9beb-91e327a83e4c.png)


適当な名前と、最初に作成した（複数作成した場合はそのうちの１つの）サーバーのIPアドレスと
適当なファイル名のPHPを指定（後で設置します。）
![TwiML Appsの作成](https://qiita-image-store.s3.amazonaws.com/0/25480/57a79c5b-ab2d-e04b-eb9b-40f819c1a382.png)


最初の画面に戻り、電話番号をクリックすると
![電話番号選択](https://qiita-image-store.s3.amazonaws.com/0/25480/f94c5606-e368-a47e-dd36-bb3f903cdcbb.png)


電話番号の設定が開くので、「音声通話」をTwiML Appsで先ほど作成したAppを選択。
![TwiML Appsを設定](https://qiita-image-store.s3.amazonaws.com/0/25480/89f6a1ea-e018-ed6c-adbf-0e585cd9ab1d.png)


これで、Twilioの設定はとりあえずOK。


# Twilio応答用のファイル設置

```php:conoha-delete.php
<?php
//ini_set('display_errors', true);
//error_reporting(E_ALL);

/* // // // // // // // // *
 *     設定
 */
// アカウントの設定
$ConoHa_username = 'gncuXXXXXXXX';
$ConoHa_password = 'Password';
$ConoHa_tenantId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX';

// 着信・プッシュ操作設定
$ConoHa_Incoming_authorization = '0000'; // 承認コード

$ConoHa_Incoming_numDigits = mb_strlen($ConoHa_Incoming_authorization);
// 入力桁数。指定した桁数入力すると自動的に終了。サンプルでは承認コードの桁数をカウント

$ConoHa_Incoming_finishOnKey = '#'; // 数字の桁数に関わらず入力する事で終了

/* --- 削除対象 server_id(UUID)で指定 --- */
$ConoHa_Delete_ServerList[] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
$ConoHa_Delete_ServerList[] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';

/* // // // // // // // // */


// もし、このファイルにむやみにアクセスされそうな環境であれば
// ここで何かしらの処理で弾いても良いと思います。（下記は例）
//if ($_GET['c_un'] != $ConoHa_username || $_GET['c_tid'] != $ConoHa_tenantId) {
//    exit;
//}

if (empty($_POST["Digits"])) {
    // 初回/Digits無し
    header("content-type: text/xml");
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";;
    echo '<Response><Gather numDigits="' . $ConoHa_Incoming_numDigits . '" finishOnKey="' . $ConoHa_Incoming_finishOnKey . '" timeout="30"><Say language="ja-jp">承認コードを入力して下さい</Say></Gather></Response>';
} elseif ($_POST["Digits"] == $ConoHa_Incoming_authorization) {
    // Digits入力有り/承認コード一致

    /* Debug */
    //var_dump($ConoHa_Delete_ServerList);
    //exit;

    /* Digits match */
    $ConoHa_identity_senddata = [
        "auth" => [
            "passwordCredentials" => [
                "username" => $ConoHa_username,
                "password" => $ConoHa_password
            ],
            "tenantId" => $ConoHa_tenantId
        ]
    ];
    $ConoHa_identity_endpoint = 'https://identity.tyo1.conoha.io/v2.0/tokens';
    $ConoHa_identity_detail = conoha_post_api($ConoHa_identity_endpoint, $ConoHa_identity_senddata);

    //var_dump($ConoHa_identity_detail);

    $ConoHa_compute_senddata = [];
    $ConoHa_Delete_endpoint = 'https://compute.tyo1.conoha.io/v2/' . $ConoHa_tenantId . '/servers';
    foreach ($ConoHa_Delete_ServerList as $ConoHa_Delete_Server) {
        $result[] = conoha_post_api(
            $ConoHa_Delete_endpoint . '/' . $ConoHa_Delete_Server,
            $ConoHa_compute_senddata,
            $ConoHa_identity_detail['access']['token']['id'],
            'DELETE');
    }

} else {
    // Digits入力有り/承認コード不一致
    header("content-type: text/xml");
    echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
    echo '<Response><Gather numDigits="' . $ConoHa_Incoming_numDigits . '" finishOnKey="' . $ConoHa_Incoming_finishOnKey . '" timeout="30"><Say language="ja-jp">承認に失敗しました。再度入力を行って下さい。</Say></Gather></Response>';
}

// Functions
function conoha_get_api($url, $query, $token = '')
{
    $header = ['Content-Type: application/json', 'Accept: application/json'];
    if (!empty($token)) {
        $header[] = "X-Auth-Token: $token";
    }
    if (!empty($query) && is_array($query) && count($query) > 0) {
        $url .= '?' . http_build_query($query);
    }
    $context = stream_context_create(array('http' => array('method' => 'GET', 'header' => implode(PHP_EOL, $header),)));
    $response = file_get_contents($url, false, $context);
    if ($response === false) {
        return false;
    } else {
        return json_decode($response, true);
    }
}

function conoha_post_api($url, $data, $token = '', $method = 'POST')
{
    $header = ['Content-Type: application/json', 'Accept: application/json'];
    if (!empty($token)) {
        $header[] = "X-Auth-Token: $token";
    }
    $context = stream_context_create(array('http' => array('method' => $method, 'header' => implode(PHP_EOL, $header), 'content' => json_encode($data),)));
    $response = file_get_contents($url, false, $context);
    if ($response === false) {
        return false;
    } else {
        return json_decode($response, true);
    }
}

?>

```
PHP参考： [ConoHa の API を使ってみる、ついでに、ISOイメージを使って Ubuntu Server 14.04 をインストールしてみる。](http://server-setting.info/blog/conoha-api-iso-ubuntu-server.html)
Twilio/Gather参考: [Twilioの人気動詞Gather、電話器のプッシュ音を認識し、いろんな処理を簡単に実現させます。](http://qiita.com/joohounsong/items/e1ca8270eaee395616ed)


まずは設定から。
### 管理画面でAPIを選択。（まだAPIを使ったことが無い場合はここで新規作成）

「APIユーザー」の「ユーザー名」「パスワード」と、「テナント情報」の「テナントID」を設定する。
![APIユーザーの取得](https://qiita-image-store.s3.amazonaws.com/0/25480/72104212-dd6a-0d7a-de16-5a79ed38fda1.png)

```php:conoha-delete.php
// アカウントの設定
$ConoHa_username = 'gncuXXXXXXXX';
$ConoHa_password = 'Password';
$ConoHa_tenantId = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
```



### 次に、UUIDを取得し、削除対象を設定する。
![UUIDの位置](https://qiita-image-store.s3.amazonaws.com/0/25480/9a41aaf2-cd6b-69a8-b66f-e071c9be53bc.png)

```php:conoha-delete.php
/* --- 削除対象 server_id(UUID)で指定 --- */
$ConoHa_Delete_ServerList[] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
$ConoHa_Delete_ServerList[] = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
```
複数削除のため、配列に入れて後から回す。
<font color="red">なお、上から順に回すので、当ファイルが設置されたサーバーは
最後の配列に入れないと、その後のサーバーの削除処理が行えない</font>

```php:conoha-delete.php

// もし、このファイルにむやみにアクセスされそうな環境であれば
// ここで何かしらの処理で弾いても良いと思います。（下記は例）
if ($_GET['c_un'] != $ConoHa_username || $_GET['c_tid'] != $ConoHa_tenantId) {
    exit;
}
```
コメントの通りだが、`$_POST['Digits']`が一致していれば削除が行えてしまうので
何かしらの処理で、弾くようにしても良いと思う。
ここは個人の好みで、好きなやり方をどうぞ。
例では付与されたパラメータが、APIの各値と一致するかを判断している。
これを入れる場合は、TwilioのURL設定でGETの値を付与してあげる必要がある。


これを、先ほど「TwiML Apps」に指定したパスと合致するよう設置する。

# 実際にかけてみると…
問題なければ、メッセージが流れて承認コードの入力を求められるので
入力してあげれば処理が実行される。

そして、最後の応答が行われる頃には削除が完了し
Twilioへ応答が行えないので
Twilioの「アプリケーションのエラーが発生しました」というメッセージで成功となる。

最後はサーバーからの応答は貰えずに、消えていくのだ…
（応答する方法が思い付かなかっただけです）

なお、このスクリプトを別サーバーに設置すれば、普通に応答も行えますが
<font color="red">このスクリプトが存在したという証拠ごと消え行く</font>というロックさでこっちを選びました

### <font color="red">注意点まとめ</font>
- 削除されるサーバーの、配列の順番に注意
- スクリプトにアクセスされるような環境であれば対策を。
- 削除が成功したらメッセージ（及びTwilioのログ）はエラー扱いになる



`$ConoHa_Incoming_numDigits`で桁数制限してるけど
勢いで設定桁以上数字押しまくったらどうなる？
→超えた分は無視される。頭から設定桁数で一致してれば実行される。
（例では`0000`に設定しているが、`000012345`と入力しても4桁の時点で入力の受付が終了しており、`12345`は無視されている）

あとは応答メッセージを

```xml:conoha-delete.php
<Say language="ja-jp">予約サービスです。お客様番号をどうぞ</Say>
```

とかにしたら、敵を欺きながらコールが可能…！とか。
そんな所で、おわり。

## あとがき
テストでいっぱいサーバー作っては消してをやったので
地味に課金が積まれてる( 'ω')

一応、そんな人居ないと思いますけど本当にマジで
たまに居そうな世の中だから書いておきますけど
ここで削除しても、ちゃんとConoHaに何かしらの
VMのログが残ってると思いますので
本当に全く見られなくなる訳じゃないからね！
プロバイダ責任制限法に基き発信者開示請求されたら連絡来るからね！

そんなわけで
あと、時間があればやりたい事一覧

- LINE BOT APIで特定のワードに反応して削除
- Gatherで番号選択して、サーバーの指定削除
- 削除結果のメール(SMS)送信
- データをAWSに退避して削除（AWSも電話で削除するか…）

<font color="White">ConoHaは中の人含めみんなおっさんや…</font>

それではまた来年〜。