4

我有多个 EBS 支持的 EC2 实例正在运行,我希望能够拍摄其中一个背后的 EBS 卷的快照,从该快照创建一个新的 EBS 卷,然后将该新的 EBS 卷挂载到另一个上作为附加驱动器. 我知道如何通过 AWS Web 控制台执行此操作,但我想通过使用 AWS Java API 来自动化该过程。

如果我只是一个接一个地调用以下命令:

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 卷。根据亚马逊文档,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 控制台中,我可以看到快照已创建(现在有一个绿色圆圈将其标记为“已完成”),但不知何故我的程序没有收到消息。

当我用简单的等待一秒钟替换 while 循环时(在第一个代码片段中插入该行Thread.sleep(1000)Snapshot snap = snapRes.getSnapshot();,程序通常会创建一个新的 EBS 卷而没有抱怨(然后当我尝试将卷附加到新的实例)。但是,有时即使等待一秒钟,我也会收到 IncorrectState 错误。我假设这意味着创建快照(即使是相同的 EBS 卷)所需的时间存在一些差异,并且一秒钟足以解决部分但不是全部可能的延迟时间。

我可以将硬编码延迟增加到肯定比预期时间更长的时间,但是这种方法有很多错误(它在我将使用它的大多数时间都不必要地等待,它仍然不能保证足够长,并且它不会很好地转化为第二步的解决方案,将 EBS 卷安装到实例上)。

我真的很希望能够定期检查 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 回答