4

複数の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がリクエストを処理する方法に関するある種の問題に直面しているということです。

4

2 に答える 2

5

解決しました。問題は、Snapshot.getState()呼び出しが実際にはAWSへの新しい呼び出しを行わないが、オブジェクトが作成されたときのオブジェクトの状態を返し続けることでした(これは常に保留中です)。

describeSnapshots()次の方法を使用して問題を修正しました。

String snapState = snap.getState();
System.out.println("snapState is " + snapState);

System.out.print("Waiting for snapshot to be created");
// Wait for the snapshot to be created
while (snapState.equals("pending"))
{
    Thread.sleep(500);
    System.out.print(".");
    DescribeSnapshotsResult describeSnapRes 
        = ec2.describeSnapshots(new DescribeSnapshotsRequest().withSnapshotIds(snap.getSnapshotId()));
snapState = describeSnapRes.getSnapshots().get(0).getState();
 }
 System.out.println("\nDone.");

これにより、毎回AWSが適切に呼び出され、機能します。

于 2012-08-22T21:13:39.190 に答える
0

getstate()の代わりに、getProgress()メソッドを使用してみてください。空白になっている場合は、EBSスナップショットの準備ができていません。文字列のパーセンテージ形式で出力します(スナップショットの準備ができたら100%)。うまくいけば、それはトリックを行う必要があります。動作するかどうか教えてください。

于 2012-08-22T03:48:23.333 に答える