複数のEBSバックアップEC2インスタンスを実行していて、そのうちの1つの背後にあるEBSボリュームのスナップショットを取得し、そのスナップショットから新しいEBSボリュームを作成してから、その新しいEBSボリュームを追加のドライブとして別のインスタンスにマウントできるようにしたい。AWS Webコンソールを介してこれを行う方法を知っていますが、AWSJavaAPIを使用してプロセスを自動化したいと思います。
次のコマンドを次々に呼び出すだけの場合:
CreateSnapshotResult snapRes
= ec2.createSnapshot(new CreateSnapshotRequest(oldVolumeID, "Test snapshot"));
Snapshot snap = snapRes.getSnapshot();
CreateVolumeResult volRes
= ec2.createVolume(new CreateVolumeRequest(snap.getSnapshotId(), aZone));
String newVolumeID = volRes.getVolume().getVolumeId();
AttachVolumeResult attachRes
= ec2.attachVolume(new AttachVolumeRequest(newVolumeID, instanceID, "xvdg"));
次のエラーが発生します。
Caught Exception: Snapshot 'snap-8e822cfd' is not 'completed'.
Reponse Status Code: 400
Error Code: IncorrectState
Request ID: 40bc6bad-43e0-49e6-a89a-0489744d24e6
これを回避するには、スナップショットから新しいEBSボリュームを作成する前に、スナップショットが完了するまで待つ必要があります。Amazonのドキュメントによると、Snapshot.getState()の可能な値は「保留中、完了、またはエラー」であるため、AWSにチェックインして、スナップショットがまだ「保留中」の状態であるかどうかを確認することにしました。次のコードを書きましたが、機能しませんでした。
CreateSnapshotResult snapRes
= ec2.createSnapshot(new CreateSnapshotRequest(oldVolumeID, "Test snapshot"));
Snapshot snap = snapRes.getSnapshot();
System.out.println("Snapshot request sent.");
System.out.println("Waiting for snapshot to be created");
String snapState = snap.getState();
System.out.println("snapState is " + snapState);
// Wait for the snapshot to be created
while (snapState.equals("pending"))
{
Thread.sleep(1000);
System.out.print(".");
snapState = snapRes.getSnapshot().getState();
}
System.out.println("Done.");
これを実行すると、次の出力が得られます。
Snapshot request sent.
Waiting for snapshot to be created
snapState is pending
.............................................
プログラムを終了するまでドットが印刷され続ける場所。AWS Web Consoleで、スナップショットが作成されたことがわかります(これで、「完了」としてマークされた緑色の円が表示されます)が、どういうわけか、プログラムはメッセージを受け取りません。
whileループを1秒待つだけで置き換えると(最初のコードスニペットのThread.sleep(1000)
後Snapshot snap = snapRes.getSnapshot();
に行を挿入)、プログラムは文句なしに新しいEBSボリュームを作成することがよくあります(ボリュームを新しいものに接続しようとすると終了します)実例)。ただし、1秒待ってもIncorrectStateエラーが発生する場合があります。これは、スナップショットの作成にかかる時間にある程度のばらつきがあり(同じEBSボリュームであっても)、考えられる遅延時間のすべてではなく一部を説明するのに1秒で十分であることを意味すると思います。
ハードコードされた遅延を予想よりも確実に長くなるように増やすこともできますが、そのアプローチには多くの欠点があります(使用するほとんどの時間、不必要に待機しますが、それでも十分な長さは保証されません。また、EBSボリュームをインスタンスにマウントするという2番目のステップのソリューションにはうまく変換されません)。
定期的にAWSにチェックインし、スナップショットの状態が変更されているかどうかを確認して、変更されたら続行できるようにしたいと考えています。何が間違っているのでしょうか。また、スナップショットが完全に作成されたことをプログラムが動的に判断できるように、コードを修正するにはどうすればよいですか。
編集:私は提案に従ってgetProgress()
ではなく、使用してみました。getState()
変更したコードは次のようになります。
String snapProgress = snap.getProgress();
System.out.println("snapProgress is " + snapProgress);
// Wait for the snapshot to be created
while (!snapProgress.equals("100%"))
{
Thread.sleep(1000);
System.out.print(".");
snapProgress = snapRes.getSnapshot().getProgress();
}
System.out.println("Done.");
を使用したときと同じ出力が得られますgetState()
。私の問題は、コードが参照するスナップショットオブジェクトが正しく更新されていないことだと思います。そのオブジェクトを単に繰り返し呼び出すよりも、そのオブジェクトを更新/更新するためのより良い方法はありますか?私の疑いは、APIがリクエストを処理する方法に関するある種の問題に直面しているということです。