はじめに
AMIのコピーをSDK for Javaで実装してみます。
AMIをリージョン間でコピーすることでちょっとしたDRが実現できますね。
まずは簡単なサンプル。次に、AMIのコピー機能ではコピーされないタグの情報・起動許可を合わせてコピーしてみます。
AMIのコピー
AMIはS3上に保管されます。S3間のリージョン間データ転送には費用がかかりますので、ここでは東京リージョン間でのコピーを実装してみました。
リージョン間にするにはcopyImageRequest#setSourceRegionに別リージョンを指定すれば対応できます。
また、別アカウントのAMIコピーは、別アカウントのcredentialをCopyImageRequestに与えてやれば実現可能です。
package aws.ec2.ami;
import java.util.List;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.CopyImageRequest;
import com.amazonaws.services.ec2.model.CopyImageResult;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeImagesRequest;
import com.amazonaws.services.ec2.model.DescribeImagesResult;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Tag;
public class Ec2AmiCopy {
/**
* 第一引数で指定されたAMI imageをリージョン間コピーします。<br>
* tagの情報についても合わせてコピーします。
*
* @param args
* AMI image id
*/
public static void main(String[] args) {
String sourceImageId = args[0];
if (sourceImageId == null || "".equals(sourceImageId)) {
throw new IllegalArgumentException("instance id is null or empty.");
}
AWSCredentialsProvider provider = new ProfileCredentialsProvider("uzr");
AmazonEC2 ec2ClientTokyo2 = Region.getRegion(Regions.AP_NORTHEAST_1)
.createClient(AmazonEC2Client.class, provider,
new ClientConfiguration());
// AMIをコピーするときのプロパティを設定します。コピー元のリージョンとAMIIDを指定しています。
CopyImageRequest copyImageRequest = new CopyImageRequest();
copyImageRequest.setDescription("copy sourceImageId:" + sourceImageId);
copyImageRequest.setSourceRegion(Regions.AP_NORTHEAST_1.getName());
copyImageRequest.setRequestCredentials(provider.getCredentials());
copyImageRequest.setSourceImageId(sourceImageId);
// AMIコピーの実行
CopyImageResult copyImageResult = ec2ClientTokyo2
.copyImage(copyImageRequest);
String copyImageId = copyImageResult.getImageId();
// この時点ではリクエストが受け付けられただけです。
System.out.println(sourceImageId + "から" + copyImageId + "を作成しました。");
}
}
ユーザ定義タグのコピー
ユーザ定義タグについては、AMIコピーではコピーされませんので、コピー後にユーザ定義タグもコピーしてあげます。
package aws.ec2.ami;
import java.util.List;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.CopyImageRequest;
import com.amazonaws.services.ec2.model.CopyImageResult;
import com.amazonaws.services.ec2.model.CreateTagsRequest;
import com.amazonaws.services.ec2.model.DescribeImagesRequest;
import com.amazonaws.services.ec2.model.DescribeImagesResult;
import com.amazonaws.services.ec2.model.Image;
import com.amazonaws.services.ec2.model.Tag;
public class Ec2AmiCopy {
/**
* 第一引数で指定されたAMI imageをリージョン間コピーします。<br>
* tagの情報についても合わせてコピーします。
*
* @param args
* AMI image id
*/
public static void main(String[] args) {
String sourceImageId = args[0];
if (sourceImageId == null || "".equals(sourceImageId)) {
throw new IllegalArgumentException("instance id is null or empty.");
}
AWSCredentialsProvider provider = new ProfileCredentialsProvider("uzr");
AmazonEC2 ec2ClientTokyo2 = Region.getRegion(Regions.AP_NORTHEAST_1)
.createClient(AmazonEC2Client.class, provider,
new ClientConfiguration());
// AMIをコピーするときのプロパティを設定します。コピー元のリージョンとAMIIDを指定しています。
CopyImageRequest copyImageRequest = new CopyImageRequest();
copyImageRequest.setDescription("copy sourceImageId:" + sourceImageId);
copyImageRequest.setSourceRegion(Regions.AP_NORTHEAST_1.getName());
copyImageRequest.setRequestCredentials(provider.getCredentials());
copyImageRequest.setSourceImageId(sourceImageId);
// AMIコピーの実行
CopyImageResult copyImageResult = ec2ClientTokyo2
.copyImage(copyImageRequest);
String copyImageId = copyImageResult.getImageId();
// この時点ではリクエストが受け付けられただけです。
System.out.println(sourceImageId + "から" + copyImageId + "を作成しました。");
// Tagの情報をコピー元から取得して、コピーした先のAMIに紐付けます。
AmazonEC2 ec2ClientTokyo = Region.getRegion(Regions.AP_NORTHEAST_1)
.createClient(AmazonEC2Client.class, provider,
new ClientConfiguration());
// Tagの情報を取得
DescribeImagesResult describeImagesResult = ec2ClientTokyo
.describeImages(new DescribeImagesRequest()
.withImageIds(sourceImageId));
List<Image> images = describeImagesResult.getImages();
if (images.size() != 1) {
throw new IllegalStateException("error:" + images.size());
}
Image image = images.get(0);
// AMIコピーしてできたイメージにタグを紐付けます。
for (Tag tag : image.getTags()) {
ec2ClientTokyo2.createTags(new CreateTagsRequest().withResources(
copyImageId).withTags(tag));
}
}
}
起動許可設定のコピー
起動許可についてもコピーされませんので調子に乗ってタグと一緒にコピーしてみました。
起動許可は、ManagementConsoleではPermissionタブに表示されます。Permissionタブに表示されている情報はSDKではLaunchPermissionクラスで表現されます。
package aws.ec2.ami;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DescribeImageAttributeRequest;
import com.amazonaws.services.ec2.model.DescribeImageAttributeResult;
import com.amazonaws.services.ec2.model.ImageAttributeName;
import com.amazonaws.services.ec2.model.LaunchPermission;
import com.amazonaws.services.ec2.model.LaunchPermissionModifications;
import com.amazonaws.services.ec2.model.ModifyImageAttributeRequest;
public class Ec2AmiLaunchPermissionCopy {
/**
* 第一引数で指定されたAMI imageに紐づく起動許可設定を<br>
* 第二引数で指定されたAMI imageにコピーします。
*/
public static void main(String[] args) {
String sourceImageId = args[0];
String destImageId = args[1];
if (sourceImageId == null || "".equals(sourceImageId)
|| destImageId == null || "".equals(destImageId)) {
throw new IllegalArgumentException("instance id is null or empty.");
}
AWSCredentialsProvider provider = new ProfileCredentialsProvider("uzr");
AmazonEC2 ec2ClientTokyo = Region.getRegion(Regions.AP_NORTHEAST_1)
.createClient(AmazonEC2Client.class, provider,
new ClientConfiguration());
// 起動許可(LaunchPermision)をコピーします。
DescribeImageAttributeResult describeImageAttributeResult = ec2ClientTokyo
.describeImageAttribute(new DescribeImageAttributeRequest(
sourceImageId, ImageAttributeName.LaunchPermission));
ModifyImageAttributeRequest modifyImageAttributeRequest = new ModifyImageAttributeRequest(
destImageId, ImageAttributeName.LaunchPermission.toString());
for (LaunchPermission permission : describeImageAttributeResult
.getImageAttribute().getLaunchPermissions()) {
modifyImageAttributeRequest
.setLaunchPermission(new LaunchPermissionModifications()
.withAdd(permission));
}
ec2ClientTokyo.modifyImageAttribute(modifyImageAttributeRequest);
}
}
実行してみます。
Exception in thread "main" com.amazonaws.AmazonServiceException: The AMI ID 'ami-eb3802ea' is currently pending and may not be used for this operation (Service: AmazonEC2; Status Code: 400; Error Code: InvalidAMIID.Unavailable; Request ID: 236e0f90-0d2e-47e7-b2cf-5d96e1ee450a)
at com.amazonaws.http.AmazonHttpClient.handleErrorResponse(AmazonHttpClient.java:1071)
at com.amazonaws.http.AmazonHttpClient.executeOneRequest(AmazonHttpClient.java:719)
at com.amazonaws.http.AmazonHttpClient.executeHelper(AmazonHttpClient.java:454)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:294)
at com.amazonaws.services.ec2.AmazonEC2Client.invoke(AmazonEC2Client.java:9393)
at com.amazonaws.services.ec2.AmazonEC2Client.modifyImageAttribute(AmazonEC2Client.java:3929)
at aws.ec2.ami.Ec2AmiCopy.main(Ec2AmiCopy.java:98)
AMIのコピーリクエスト送信後、ステータスがpendingの間は起動許可設定はコピーできません。threadを待たせてavailableの状態までまってコピーするしかないですね。