Help us understand the problem. What is going on with this article?

AMIのコピーを行う[SDK for Java]

More than 5 years have passed since last update.

はじめに

AMIのコピーをSDK for Javaで実装してみます。
AMIをリージョン間でコピーすることでちょっとしたDRが実現できますね。
まずは簡単なサンプル。次に、AMIのコピー機能ではコピーされないタグの情報・起動許可を合わせてコピーしてみます。

http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/CopyingAMIs.html

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の状態までまってコピーするしかないですね。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away