AWS SDK for Javaの高水準ラッパーAWS Resource APIs for Javaを使ってみた

よく訓練されたアップル信者、都元です。本日何かが発売しておりますが平常心で行きます。平常心です。Javaを使ってAWSのAPIを叩く時に使うのはAWS SDK for Javaですね。

AWS SDK for Java

このAWS SDK for Javaですが、APIを呼び出す際に、一般的にこのようなコードを各必要があります。

AmazonFooBar amazonFooBar = new AmazonFooBarClient();
BazQuxResult bazQuxResult = amazonFooBar.bazQux(new BazQuxRequest()
    .withCourge("...")
    .withGrault(10));
Garply garply = bazQuxResult.getGarply();

クライアントを作るところまでは良いでしょう。その後、リクエストオブジェクトを作って、クライアントに渡して、レスポンスオブジェクトを得て、その中から必要な何かを色々取り出すわけです。

AmazonEC2 amazonEC2 = new AmazonEC2Client();
amazonEC2.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));
DescribeInstancesResult describeInstancesResult = amazonEC2.describeInstances(new DescribeInstancesRequest()
    .withInstanceIds("i-...")
    .withMaxResults(10));
List<Reservation> reservations = describeInstancesResult.getReservations();
for (Reservation reservation : reservations) {
  List<Instance> instances = reservation.getInstances();
  for (Instance instance : instances) {
    // ...
  }
}

ほぼ全てのAPI呼び出しについて、この形式で記述する必要があります。まぁある意味正しい抽象化なのかもしれませんが、ちょっと低水準な感は否めません。

AWS Resource APIs for Java

といったまどろっこしさを解消する高水準なラッパーとしてAWS Resource APIs for Javaというものが発表されています。Maven的にはこんな所に置いてあります。

<dependency>
  <groupId>com.amazonaws.resources</groupId>
  <artifactId>aws-resources</artifactId>
  <version>0.0.1</version>
  <type>pom</type>
</dependency>

さてこのAPIですが、使い方はこんなかんじ。

EC2 ec2 = ServiceBuilder.forService(EC2.class)
    .withCredentials(new ProfileCredentialsProvider("default"))
    .withRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    .build();

InstanceCollection instances = ec2.getInstances();
for (Instance instance : instances) {
  System.out.printf("EC2 instance %s : %s%n", instance.getId(), instance.getState().getName());
}

クライアントを作るところは大して変わらないとして。その後のAPIがだいぶ抽象化されています。危険なので書きませんでしたがinstance.terminate();と書いたりすると、全インスタンスを片っ端からterminateしてくれたりします。

AMIとEBS snapshotを全部消す!

たまにお片付けが必要、ということで書いてみました。下記のコードはよく理解しないまま実行すると色々取り返しがつかないので、実行前に必ず全てを理解してくださいね。

EC2 ec2 = ServiceBuilder.forService(EC2.class)
    .withCredentials(new ProfileCredentialsProvider("default"))
    .withRegion(Region.getRegion(Regions.AP_NORTHEAST_1))
    .build();

ImageCollection images = ec2.getImages(new DescribeImagesRequest()
    .withOwners("self"));
for (Image image : images) {
  System.out.printf("AMI %s : %s - deleting...", image.getId(), image.getDescription());
  ResultCapture<Void> rc = new ResultCapture<>();
  try {
    image.deregister(rc);
    System.out.println(rc);
  } catch (Exception e) {
    System.out.printf("failed - %s%n", e.getMessage());
  }
}

SnapshotCollection snapshots = ec2.getSnapshots(new DescribeSnapshotsRequest().withOwnerIds("self"));
for (Snapshot snapshot : snapshots) {
  System.out.printf("EBS snapshot %s : %s - deleting... ", snapshot.getId(), snapshot.getDescription());
  ResultCapture<Void> rc = new ResultCapture<>();
  try {
    snapshot.delete(rc);
    System.out.println(rc);
  } catch (Exception e) {
    System.out.printf("failed - %s%n", e.getMessage());
  }
}

従来よりもだいぶ分かりやすいコードが書けるようになりました。ちなみに実行結果は下記のような感じでした。

AMI ami-xxxxxxxx : null - deleting...{reponseMetadata={RequestId=xxxxxxxx-7f3b-474c-8828-ed60543234d1}, clientResult=null}
AMI ami-xxxxxxxx : null - deleting...{reponseMetadata={RequestId=xxxxxxxx-5aaf-4c73-ac45-851170f0a5d8}, clientResult=null}
AMI ami-xxxxxxxx : null - deleting...{reponseMetadata={RequestId=xxxxxxxx-22f5-44cc-b9d4-402babe472b2}, clientResult=null}
AMI ami-xxxxxxxx : null - deleting...{reponseMetadata={RequestId=xxxxxxxx-cf7c-4869-890f-b7699d5a5762}, clientResult=null}
AMI ami-xxxxxxxx : null - deleting...{reponseMetadata={RequestId=xxxxxxxx-cba6-4c57-a6bb-ed4ad0fbe0ea}, clientResult=null}
EBS snapshot snap-xxxxxxxx : Created by CreateImage(i-xxxxxxxx) for ami-xxxxxxxx from vol-xxxxxxxx - deleting... {reponseMetadata={RequestId=xxxxxxxx-e198-4695-97ff-e46baeebde09}, clientResult=null}
EBS snapshot snap-xxxxxxxx : Created by CreateImage(i-xxxxxxxx) for ami-xxxxxxxx from vol-xxxxxxxx - deleting... {reponseMetadata={RequestId=xxxxxxxx-a800-461d-bba4-e4df348676d5}, clientResult=null}
EBS snapshot snap-xxxxxxxx : Created by CreateImage(i-xxxxxxxx) for ami-xxxxxxxx from vol-xxxxxxxx - deleting... {reponseMetadata={RequestId=xxxxxxxx-85a2-49bc-91cb-3af5aba8c9fd}, clientResult=null}
EBS snapshot snap-xxxxxxxx : Created by CreateImage(i-xxxxxxxx) for ami-xxxxxxxx from vol-xxxxxxxx - deleting... {reponseMetadata={RequestId=xxxxxxxx-c4f2-4022-8614-68778e1f2bc5}, clientResult=null}
EBS snapshot snap-xxxxxxxx : Created by CreateImage(i-xxxxxxxx) for ami-xxxxxxxx from vol-xxxxxxxx - deleting... {reponseMetadata={RequestId=xxxxxxxx-bc22-41c8-9089-2545305d180d}, clientResult=null}

まだバージョンは 0.0.1 ということで生まれたてのプロダクトですので、現時点で対応しているAWSプロダクトは、EC2・IAM・Glacierのみです。が、今後対応プロダクトは増えていくものと思います。素のSDKに嫌気がさしていた方は、こちらを使ってみると良いかもしれません。