GroovyでAWS SDK for Javaを使う #gadvent

このエントリは G*Advent Calendar(Groovy,Grails,Gradle,Spock...) Advent Calendar 2014 - Qiita の12/13担当分です。

AWS SDK for Javaとは?

パブリッククラウドサービスであるAmazon Web ServicesにはWebAPIが提供されていますが、生のAPIでは使いにくいため、各言語用からAPIを利用するためのライブラリが提供されています。
AWS SDK for Javaは読んで字のごとくJava用のライブラリです。
AWS SDK for Java | アマゾン ウェブ サービス(AWS 日本語)

Groovyから使うと何が嬉しいの?

http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/index.html を眺めてみていただくとわかりますが、AWS SDK for JavaAPIドメイン指向に設計されておりクラス構造が複雑です。
実際に使おうとするといろいろ試行錯誤が必要になるので、Groovyを使ってあらかじめAPIの挙動を調べておくと便利です。(もちろん、そのままGroovyでプロダクションコードを書いてもいいでしょう。)

例) EC2のインスタンス一覧を取得する

簡単な例として、EC2の指定リージョンのインスタンス一覧を取得してみましょう。
いろいろ試行錯誤するにはインタラクティブシェルの方がやりやすいので、
Gradle Groovy Shellプラグインを使って依存ライブラリ込みのREPLを起動する #gadvent - nobusueの日記
で紹介したGradle Groovy Shellプラグインを利用します。

事前準備

AWSAPIを利用するためには、Access KeyとSecret Keyを取得しておく必要があります。APIからのアクセス専用にIAMアカウントを新しく作成し、EC2のみ権限を与えておくとよいかと思います。

ビルドスクリプト作成

適当なディレクトリで build.gradle 作成します。

apply plugin: 'com.github.tkruse.groovysh'
apply plugin: 'java'

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.tkruse.gradle:gradle-groovysh-plugin:1.0.2'
    }
}

repositories {
    jcenter()
}

dependencies {
  compile 'com.amazonaws:aws-java-sdk:1.9.10'
}

Groovy Shell起動

以下のコマンドでGroovy Shellを起動します。

$ gradle -q shell
This is a gradle Application Shell.
You can import your application classes and act on them.
Groovy Shell (2.3.6, JVM: 1.7.0_72)
Type ':help' or ':h' for help.
-------------------------------------------------------------------------------
groovy:000>

このGroovy ShellはAWS SDK for Javaのライブラリがダウンロードされ、クラスパスに追加された状態になっています。

EC2インスタンス一覧取得

Groovy Shellで以下を入力します。ここでは例としてOregonリージョン(us-west-2)を指定しています。

groovy:000> import com.amazonaws.services.ec2.*
groovy:000> import com.amazonaws.auth.*
groovy:000> import com.amazonaws.regions.*
groovy:000> credentials = new BasicAWSCredentials("<YOUR_ACCESS_KEY>","<YOUR_SECRET_KEY>")
groovy:000> ec2 = new AmazonEC2Client(credentials)
groovy:000> ec2.setRegion(Region.getRegion(Regions.US_WEST_2))
groovy:000> result = ec2.describeInstances()
groovy:000> result.each{ println "Instance ID: ${it.reservations.instances.instanceId}" }
Instance ID: [[i-50aaf05b]]

実際には実行毎に結果(レスポンス)がダンプされますので、見失わないようにしてください。例えば、最後の行の実行結果の後には以下が出力されます。

===> {Reservations: [{ReservationId: r-a8f079a3,OwnerId: 574167580182,Groups: [],GroupNames: [],Instances: [{InstanceId: i-50aaf05b,ImageId: ami-d13845e1,State: {Code: 16,Name: running},PrivateDnsName: ip-10-0-0-200.us-west-2.compute.internal,PublicDnsName: ec2-xx-xx-xx-xx.us-west-2.compute.amazonaws.com,StateTransitionReason: ,KeyName: xxx,AmiLaunchIndex: 0,ProductCodes: [],InstanceType: t2.micro,LaunchTime: Sun Aug 31 09:12:33 JST 2014,Placement: {AvailabilityZone: us-west-2a,GroupName: ,Tenancy: default},Monitoring: {State: disabled},SubnetId: subnet-xxxxxxx,VpcId: vpc-xxxxxx,PrivateIpAddress: 10.0.0.200,PublicIpAddress: xx.xx.xx.xx,Architecture: x86_64,RootDeviceType: ebs,RootDeviceName: /dev/xvda,BlockDeviceMappings: [{DeviceName: /dev/xvda,Ebs: {VolumeId: vol-eb315aea,Status: attached,AttachTime: Sun Aug 31 09:12:36 JST 2014,DeleteOnTermination: true}}],VirtualizationType: hvm,ClientToken: xxxxxxxxxx,Tags: [{Key: Name,Value: jenkins}],SecurityGroups: [{GroupName: xxx,GroupId: sg-xxxxxxxx}, {GroupName: xxx,GroupId: sg-xxxxxxx}],SourceDestCheck: true,Hypervisor: xen,NetworkInterfaces: [{NetworkInterfaceId: eni-34684351,SubnetId: subnet-xxxxxx,VpcId: vpc-xxxxxx,Description: Primary network interface,OwnerId: 574167580182,Status: in-use,MacAddress: 02:7b:60:ba:d1:ee,PrivateIpAddress: 10.0.0.200,PrivateDnsName: ip-10-0-0-200.us-west-2.compute.internal,SourceDestCheck: true,Groups: [{GroupName: xxx,GroupId: sg-xxxxxxx}, {GroupName: xxx,GroupId: sg-xxxxxxx}],Attachment: {AttachmentId: eni-attach-5aafb86d,DeviceIndex: 0,Status: attached,AttachTime: Sun Aug 31 09:12:33 JST 2014,DeleteOnTermination: true},Association: {PublicIp: xx.xx.xx.xx,PublicDnsName: ec2-xx-xx-xx-xx.us-west-2.compute.amazonaws.com,IpOwnerId: amazon},PrivateIpAddresses: [{PrivateIpAddress: 10.0.0.200,PrivateDnsName: ip-10-0-0-200.us-west-2.compute.internal,Primary: true,Association: {PublicIp: xx.xx.xx.xx,PublicDnsName: ec2-xx-xx-xx-xx.us-west-2.compute.amazonaws.com,IpOwnerId: amazon}}]}],EbsOptimized: false,}]}],}

毎回ダンプが出るのはややうっとおしいですが、レスポンスのどこに必要な情報が含まれているか確認するだけなら、これを眺めるだけで問題が解決する場合もあったりします。

Groovy Shellは「Ctrl+D」で終了します。

Groovy Shell以外で実行する場合の注意事項

「ec2 = new AmazonEC2Client(credentials)」のように変数定義を省略しているのはGroovy Shellの制約によるものです。
通常のGroovyスクリプトで実行する場合は「def ec2 = new AmazonEC2Client(credentials)」のようにしてください。

2015/1/29追記

Groovy2.4でgroovyshのinterpreterModeが追加されました。
http://jira.codehaus.org/browse/GROOVY-6623

groovysh起動後に

:set interpreterMode true

を実行すれば、groovysh上でも普通に「def x=3」とかで変数定義できるようになりました。めでたい。

まとめ

AWS SDKで悩んだら、とりあえずGroovyで試してみるのがおすすめです。