1

我正在尝试使用 Azure Storage SDK for Java 将 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.0)。

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

我尝试将 blob 复制到同一订阅中的另一个存储帐户,这也给出了相同的错误。

更详细地查看异常,错误代码是“CannotVerifyCopySource”。

4

1 回答 1

3

副本发布在 azure-storage-java 库问题 59中。从那里复制我和 mirobers 的答案:

若要跨帐户复制 blob,您需要为源使用 SAS 令牌或标记源容器以供公共访问。请参阅以下页面的“授权”部分: 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 获取更新的副本信息。

于 2015-11-09T18:07:55.893 回答