[ConoHa API] 起動・停止機能の追加

## 起動・停止機能

前回はVMの作成・削除機能を実装しようと考えていましたが、ちょっと大変そうなので[起動](https://www.conoha.jp/docs/compute-power_on_vm.html)・[停止](https://www.conoha.jp/docs/compute-stop_cleanly_vm.html)機能を実装します。


## APIの動作
$.ajaxはレスポンスコードが200の時sucess、それ以外の時errorが実行されるのでした。そして、ConoHaのAPIドキュメントを見てみると、VMの起動・停止APIでは"Nomal response code 202"　とあります。

つまり、$.ajaxを実行した際にコマンドが成功してもerror関数が呼ばれることになります。この辺り、[server detailコマンド](https://www.conoha.jp/docs/compute-get_vms_detail.html)等とは動作が違います。

なので、今まではerrorの処理をaccess関数の中で記述していたのですが、API毎に定義できたほうが便利そうです。

では早速access関数を変更してerror関数を外部から設定できるようにしましょう。

```js
var access = function(url, data, type, onSuccess, onError, key) {                              
    return $.ajax({                                                                            
      url: url,
      data: JSON.stringify(data),                                                              
      type: type,                                                                              
      headers: {
        'X-Auth-Token' : window.localStorage["token_" + key]
      },
      context: key,
      success: onSuccess,
      error: onError
    });
}
```

そして既存のtokenおよびserver detailにonError関数を追加します。

```js
var tokenOnError =  function(XMLHttpRequest, textStatus, errorThrown) {
  console.log("$.ajax error. " + textStatus);
}
```

```js
var serversDetailOnError =  function(XMLHttpRequest, textStatus, errorThrown) {
  console.log("$.ajax error. " + textStatus);
  console.log("removing token in local storage.");
  window.localStorage.removeItem("token_" + key);
}
```

# 起動・停止APIの定義
以下のように定義します。ポイントはserver_idもパラメータにとることです。

```js
//                                                                                             
// start API information                                                                       
//                                                                                             
var getStartUrl = function (region, server_id){                                                
  return "https://compute." + region + ".conoha.io/v2/" + tenant_id + "/servers/" + server_id + "/action";
};
var start_data = { "os-start": null };                                                         
var start_type = "POST";
var startOnSuccess = function(data) {                                                          
  console.log(data);
}
var startOnError =  function(XMLHttpRequest, textStatus, errorThrown) {                        
    var status = XMLHttpRequest.status;
    console.log(status);
}
```

```js
//                                                                                             
// stop API information                                                                        
//
var getStopUrl = function (region, server_id){                                                 
  return "https://compute." + region + ".conoha.io/v2/" + tenant_id + "/servers/" + server_id + "/action";
};
var stop_data = { "os-stop": null };                                                           
var stop_type = "POST";                                                                        
var stopOnSuccess = function(data) {                                                           
  console.log(data);
}
var stopOnError =  function(XMLHttpRequest, textStatus, errorThrown) {                         
    var status = XMLHttpRequest.status;                                                        
    console.log(status);
}
```

## アクションの追加

次に、サーバーテーブルの列をタップすると現在の状態に合わせて起動・停止するようなアクションを追加します。

```js
var serversDetailOnSuccess = function(data) {
  for (var i = 0; i < data.servers.length; i++) {
    var tr = $('<tr>').attr('class', 'server_item').attr('server_id', data.servers[i].id);
    var td_index = $('<td>').text(i);
    var td_status = $('<td>').text(data.servers[i].status);
    var td_name = $('<td>').text(data.servers[i].metadata.instance_name_tag);
    var td_region = $('<td>').text(this);
    tr.append(td_index).append(td_status).append(td_name).append(td_region);
    $('#server_table').append(tr);

    tr.click(function(){
      var server_id = $(this).attr('server_id');
      var status = $($(this).children()[1]).text();
      var key = $($(this).children()[3]).text();
      switch(status) {
        case "ACTIVE":
          access(getStopUrl(regions[key], server_id), stop_data, stop_type, stopOnSuccess, stopOnError, key); 
        break;
        case "SHUTOFF":
          access(getStartUrl(regions[key], server_id), start_data, start_type, startOnSuccess, startOnError, key);  
        break;
        default:
        break;
      }
    });
  }
}
```

起動・停止コマンドはserver_idが必要なのでtr要素にserver_idという属性を付加します。さらにtrがタッチされたタイミングで子要素からステートとregion情報を取得し、access関数で起動・停止を呼び出します。


## 動作確認
停止状態からテーブルの行をタップし、しばらくしてからリロードすると。。。

![ios21.png](https://qiita-image-store.s3.amazonaws.com/0/85105/fea5b5a6-223e-ff39-fbd4-b269ddf7cffb.png)

さらに起動後にテーブルの行をタップし、しばらくしてからリロードすると。。。

![ios22.png](https://qiita-image-store.s3.amazonaws.com/0/85105/7209b742-1e8d-c07b-c89d-ee3268377989.png)

いい感じに動いていますね。

動作するコードはこちら
[単体](https://github.com/OttyLab/ConoHa_sample/blob/master/servers06.html)
[PhoneGap](https://github.com/OttyLab/Conoha_cordova_sample)

だた、テーブルの行をタップすると起動・停止されるというのはUI的にかなりあやしい動きです。手抜きしないでボタン等追加したほうが良かったですね。

以上でConoHa APIを操作するスマホアプリの制作を終了します。


## 全体を通して

### API
APIドキュメントはしっかりとまとめられていて、更にコマンド例まで載っているので理解しやすかったです。

欲張りを言うなら、以下の記述があるとよりわかりやすいと思いました。

- リージョン毎にアドレスが異なる事を注意喚起
- パラメータや戻り値の各値が何を意味しているかの説明


### スマホアプリ
PhoneGapを使うことでギリギリまでブラウザ上でデバッグし、最後だけ実機検証というフローになったのでとても楽でした。また、手元の端末でクラウドサーバがON/OFFするというのもなかなかおもしろかったです。


### 検討事項
今回はサンプル作成ということでひとつのファイルにすべての記述を行いましたが、実際には機能毎に分けたほうがよいでしょう。また、APIも一個のAPIを１クラスとして定義し、1ファイル1APIで作成していくとスケールすると思います。

さらに、user_id等の保存方法も要件等です。例えば、androidではlocal storageの値がsqliteに生の値で保存されているようです。できればsqlcipher等で暗号化処理を施したいのですが、たぶんOSのweb viewの標準実装なのでできないかと思います。となると、自分のJSで頑張るしかないのかもしれません。