使用 Azure Storage SDK for Java 将 VM 页面 blob 从一个 Azure 订阅复制到另一个

Use Azure Storage SDK for Java to copy VM page blob from one Azure subscription to another

我正在尝试使用 Java 的 Azure 存储 SDK 将 Azure VM(已停止和解除分配)的页面 blob 从一个 Azure 订阅复制到另一个。

这是我使用的代码:

public class BlobCopyExampleClean {

    public static final String sourceStorageConnectionString =
            "DefaultEndpointsProtocol=https;"
            + "AccountName=sourceStorageAccount;"
            + "AccountKey=key123";

    public static final String destinationStorageConnectionString =
            "DefaultEndpointsProtocol=https;"
            + "AccountName=destinationStorageAccount;"
            + "AccountKey=key321";

    public static void main(String[] args) {

        try {
            CloudStorageAccount srcAccount = CloudStorageAccount.parse(sourceStorageConnectionString);
            CloudBlobClient srcSrvClient = srcAccount.createCloudBlobClient();
            CloudBlobContainer srcContainer = srcSrvClient.getContainerReference("vhds");

            CloudStorageAccount destAccount = CloudStorageAccount.parse(destinationStorageConnectionString);
            CloudBlobClient destSrvClient = destAccount.createCloudBlobClient();
            CloudBlobContainer destContainer = destSrvClient.getContainerReference("vhds");

            boolean result = destContainer.createIfNotExists();

            CloudBlob srcBlob = srcContainer.getPageBlobReference("testvm-2015-11-06.vhd");
            if (srcBlob.exists()) {
                CloudBlob destBlob = destContainer.getPageBlobReference("testvm-2015-11-06-copied.vhd");
                System.out.println("Starting blob copy...");
                String copyJobId = destBlob.startCopyFromBlob(srcBlob);

                CopyState copyState = destBlob.getCopyState();

                while (copyState.getStatus().equals(CopyStatus.PENDING)) {
                    System.out.println("... copying ...");
                    Thread.sleep(30000);
            }

                System.out.println("Copy complete, status was: " + copyState.getStatus() + "!");
            } else {
                System.out.println("Source blob does not exist!");
            }
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (StorageException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

无论我尝试什么,我总是收到以下错误:

Starting blob copy...
com.microsoft.azure.storage.StorageException: The specified resource does not exist.
    at com.microsoft.azure.storage.StorageException.translateException(StorageException.java:89)
    at com.microsoft.azure.storage.core.StorageRequest.materializeException(StorageRequest.java:305)
    at com.microsoft.azure.storage.core.ExecutionEngine.executeWithRetry(ExecutionEngine.java:175)
    at com.microsoft.azure.storage.blob.CloudBlob.startCopy(CloudBlob.java:883)
    at com.microsoft.azure.storage.blob.CloudBlob.startCopyFromBlob(CloudBlob.java:788)
    at com.company.azure.storage.BlobCopyExampleClean.main(BlobCopyExampleClean.java:44)

我尝试使用 SDK 库的 v1.3.1、v3.1.0 和 v4.0.0,但使用 blob.startCopyFromBlob()(v1.3.1 和 v3.1.0)和 blob.startCopy() (v4.0.0).

有问题的页面 blob 没有租约,因为 Azure 管理门户显示租约状态为 "Unlocked" 并且它确实存在,甚至 Azure API 通过在以下位置输入代码块来确认这一点第 42 行。

我尝试将 blob 复制到同一订阅内的另一个存储帐户,但也出现了同样的错误。

更详细地查看异常,错误代码为 "CannotVerifyCopySource"。

重复发布在 azure-storage-java 库 issue 59 中。从那里复制我和 mirobers 的回答:

要跨帐户复制 blob,您需要对源使用 SAS 令牌或将源容器标记为 public 访问。请参阅下一页的 "Authorization" 部分: https://msdn.microsoft.com/en-us/library/azure/dd894037.aspx

例如,您的代码可以生成一个 SAS 令牌,授予对源 blob 的读取访问权限,将其附加到源 blob URL 的查询字符串,然后从 URL.如果您正在寻找特定的 API,请查看 blob 对象上的 generateSharedAccessSignature。您可以使用由此返回的令牌创建一个新的 CloudStorageAccount 并按照上面的代码流从中获取 blob 引用,或者将其附加到 blob URL 并使用 CloudBlockBlob(URL)直接获取 blob 引用的构造函数。

您的代码还有一个问题,那就是 getCopyState 没有进行服务调用。这只是获取之前由 startCopy 设置的 blob 复制状态。在你的 while 循环中,你应该尝试使用 downloadAttributes 而不是它实际上会执行服务调用以从 blob 获取更新的副本信息。