1
votes

I'm trying to use the Azure Storage SDK for Java to copy the page blob of an Azure VM (that is Stopped and Deallocated) from one Azure subscription to another.

Here's the code I'm using:

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();
        }
    }
}

No matter what I try I always get the following error returned to me:

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)

I've tried using v1.3.1, v3.1.0 & v4.0.0 of the SDK library and get the same error using both blob.startCopyFromBlob() (v1.3.1 & v3.1.0) and blob.startCopy() (v4.0.0).

The page blob in question has no lease, as the Azure Management Portal says the lease status is "Unlocked" and it does exist, even the Azure API confirms this by entering the code block at line 42.

I've tried copying the blob to another storage account within the same subscription and that gives the same error too.

Looking at the exception in more detail the error code is "CannotVerifyCopySource".

1
I looked up the REST API documentation for this error code here (msdn.microsoft.com/en-us/library/azure/dd179439.aspx) and it says Could not verify the copy source within the specified time. Examine the HTTP status code and message for more information about the failure.. Can you please check the message? It should give you more information.Gaurav Mantri

1 Answers

3
votes

Duplicate is posted in the azure-storage-java library issue 59. Copying my and mirobers answer from there:

To copy a blob across accounts, you need to use a SAS token for the source or mark the source container for public access. See the "Authorization" section of the following page: https://msdn.microsoft.com/en-us/library/azure/dd894037.aspx

So for example your code could generate a SAS token granting read access to the source blob, append it to the source blob URL's query string, and then start the copy from the URL. If you're looking for the specific APIs, check out generateSharedAccessSignature on the blob object. You can use the token returned by this to either make a new CloudStorageAccount and follow the code flow above to get a blob reference from that, or append it to the blob URL and use the CloudBlockBlob(URL) constructor to directly get a blob reference.

Your code has one additional problem in that getCopyState does not make a service call. This is just getting the blob copy state previously set by startCopy. Inside your while loop you should try using downloadAttributes instead which will actually do a service call to get the updated copy information from the blob.