AndroidからAWSのEC2インスタンスをON/OFFする


AWSのEC2インスタンスを
Androidから自動的にON/OFFするアプリを作りました。
そのメモとして、AWSのAndroid版SDKの利用方法をメモしておきます。

##0.前提
AndroidStudioをセットアップ済みと仮定します。
また、これらの知識で作ったアプリは以下になります。
参考としてどうぞ。

GooglePlay : [AWS EC2 Scheduler](https://play.google.com/store/apps/details?id=jp.chau2chaun2.ec2scheduler)（無料）

##1.準備
まずは開発環境に「AWS Mobile SDK」を導入しましょう。

###1-1.SDK用意
[こちら](https://aws.amazon.com/jp/mobile/sdk/)にSDKがありますのでダウンロードしましょう。
ちなみにリファレンスもあります。量が多く読み辛いですが…

###1-2.プロジェクト作成
通常手順通り、普通に作成します。

###1-3.ライブラリ参照
今回はEC2インスタンスの参照と操作を行います。
２つのライブラリをlibsフォルダに格納し、build.gradleに参照先として追加します。

> aws-android-sdk-core-2.2.5.jar
> aws-android-sdk-ec2-2.2.5.jar

```bin:build.gradle
dependencies {
    /*
      途中省略
     */
    compile files('libs/aws-android-sdk-ec2-2.2.5.jar')
    compile files('libs/aws-android-sdk-core-2.2.5.jar')
}
```

これで利用準備は完了です。簡単ですねー！

##2.コード上から操作

###2-1.必要な情報
端末からアクセスするためには、以下情報が必要になります。

|名前 |概要 |
|:--|:--|
|アクセスキー（Acccess Key）|ユーザが発行する、AWSサービスにアクセスするためのアクセスキー|
|シークレットキー（Secret Key）|同上。こちらは作成時にのみ参照可能。取り扱い注意。|
|リージョン情報（Region）|そのサーバ、どこにあんの？という情報。<br>AWSコンソールではアベイラビリティーゾーンと表現されているもの。|

それぞれの取得・参照方法は割愛します。

###2-2.インスタンス取得

では先に挙げた３つの必要な情報からインスタンスを取得しましょう。
インスタンスIDと、インスタンスのタグ名（任意で付けられる名称）を取得してログ出力します。

```java:get_EC2_instance.java
    // アクセスキー
    String accessKey = "***********";
    // シークレットキー
    String secretKey = "***********";
    // リージョン
    Region region = Region.getRegion(Regions.AP_NORTHEAST_1);

    try{
        BasicAWSCredentials basiAwsCredentials = new BasicAWSCredentials(accessKey, secretKey);

        AmazonEC2Client amazonEC2Client = new AmazonEC2Client(basiAwsCredentials);
        amazonEC2Client.setRegion(region);

        DescribeInstancesResult describeInstancesResult
                = amazonEC2Client.describeInstances();

        for (Reservation reservation : describeInstancesResult.getReservations()) {
            //EC2のInstanceのListを取得
            List<Instance> instanceList = reservation.getInstances();
            if (instanceList != null) {
                for (Instance instance : instanceList) {
                    List<Tag> tag = instance.getTags();
                    String tagName = "";
                    for (int ii = 0; ii < tag.size(); ii++) {
                        if (tag.get(ii).getKey().equals("Name")) {
                            // インスタンス名を取得
                            tagName = tag.get(ii).getValue();
                            break;
                        }
                    }
                    Log.e("HONKOT_TEST", "### found instance : "
                            + tagName + " " + instance.getInstanceId());
                }
            }
        }
    } catch ( AmazonServiceException exception) {
        Log.e("HONKOT_TEST", exception.getMessage());
        exception.printStackTrace();
    }
```

なお、リージョンはひとまずnorth-eastにしていますが、
他のリージョン一覧はRegions.values() で配列を取得可能です。

###2-3.インスタンス操作

では実際にON/OFFしていきましょう。

```java:action_EC2_instance.java
    // アクセスキー
    String accessKey = "***********";
    // シークレットキー
    String secretKey = "***********";
    // リージョン
    Region region = Region.getRegion(Regions.AP_NORTHEAST_1);
    
    try{
        BasicAWSCredentials basiAwsCredentials =
                new BasicAWSCredentials(accessKey, secretKey);

        AmazonEC2Client amazonEC2Client = new AmazonEC2Client(basiAwsCredentials);
        Region region = Region.getRegion(Regions.fromName(instanceData.getRegion()));
        amazonEC2Client.setRegion(region);

        List instanceIds = new ArrayList();
        instanceIds.add(instanceData.getInstanceId());

        switch (action) {
            case ACTION_SHUTDOWN:
                StopInstancesRequest stopInstancesRequest = new StopInstancesRequest(instanceIds);
                amazonEC2Client.stopInstances(stopInstancesRequest);
                break;
            case ACTION_RUNNING:
                StartInstancesRequest startInstancesRequest = new StartInstancesRequest(instanceIds);
                amazonEC2Client.startInstances(startInstancesRequest);
                break;
        }
    } catch ( AmazonServiceException exception) {
        Log.e("HONKOT_TEST", exception.getMessage());
        exception.printStackTrace();
    }
```

やってみれば簡単ですね。

###2-4.AmazonServiceException
インスタンスがなかったときや、
認証が失敗したときに発生します。

##備考

###NetworkOnMainThreadExceptionについて

実は2-2,2-3のまま実行すると上記Exceptionが発生します。

これはAndroid3.0から発生するもので、
ネットワーク接続はバックグラウンドで行わないといけないのです。
ということで、AsyncTask等を使わないとこのエラーで先に進みません。

ご注意を。

###アクセスキーの扱いについて
これはAWS上でも注意事項として挙げられていますが、
これあるとなんでもできちゃいます。

個人のアプリであれば別にいいですが、
公開する場合は取り扱いに十分注意する必要があります。

私のアプリでは、一度設定したアクセスキーは伏字にしたり、
再編集にはパスワード入力を必要としています。

##参考

[AWS mobile ADK Android Reference](http://docs.aws.amazon.com/AWSAndroidSDK/latest/javadoc/)

[AWS SDK for Android EC2を扱う 接続編](http://blog.cloudpack.jp/2011/07/26/aws-news-aws-for-sdk-android-ec2/)