我有多个运行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"));
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Caught Exception: Snapshot 'snap-8e822cfd' is not 'completed'.
Reponse Status Code: 400
Error Code: IncorrectState
Request ID: 40bc6bad-43e0-49e6-a89a-0489744d24e6
Run Code Online (Sandbox Code Playgroud)
为了解决这个问题,我显然需要等到快照完成后再从快照创建新的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.");
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我得到以下输出:
Snapshot request sent.
Waiting for snapshot to be created
snapState is pending
.............................................
Run Code Online (Sandbox Code Playgroud)
在我杀死程序之前,点继续打印.在AWS Web Console中,我可以看到快照已创建(它现在有一个绿色圆圈标记为"已完成"),但不知怎的,我的程序还没有收到消息.
当我用一个简单的等待一秒钟替换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.");
Run Code Online (Sandbox Code Playgroud)
我获得与使用时相同的输出getState().我认为我的问题是我的代码引用的快照对象没有正确更新.是否有更好的方法来刷新/更新该对象,而不是简单地重复调用其方法?我怀疑我正在遇到API处理请求的方式遇到的某种问题.
解决了它.我认为问题在于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.");
Run Code Online (Sandbox Code Playgroud)
这样每次都可以正确调用AWS,并且可以正常工作.