///<summary> /// Used to a copy a blob to a particular blob destination endpoint - this is a blocking call /// </summary> public int CopyBlobTo(BlobEndpoint destinationEndpoint) { var now = DateTime.Now; // get all of the details for the source blob var sourceBlob = GetCloudBlob(this); var signature = sourceBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy() { Permissions = SharedAccessBlobPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(10) }); // get all of the details for the destination blob var destinationBlob = GetCloudBlob(destinationEndpoint); // check whether the blob should be copied or not - if it has changed then copy if (!EndpointState.Force) { if (AreBlobsIdentical(destinationEndpoint)) { System.Diagnostics.Trace.TraceWarning("Skipping: {0}", sourceBlob.Uri.AbsoluteUri); return 0; } } // copy from the destination blob pulling the blob try { destinationBlob.StartCopyFromBlob(new Uri(sourceBlob.Uri.AbsoluteUri + signature)); System.Diagnostics.Trace.TraceInformation("Copying: {0}", destinationEndpoint.EndpointState.BlobName); } catch (Exception ex) { var we = ex.InnerException as WebException; if (we != null && we.Status == WebExceptionStatus.ProtocolError) { // TODO: replace this with a tracelistener System.Diagnostics.Trace.TraceError("conflict with blob copy for blob {0} - you currently have a pending blob already waiting to be copied", sourceBlob.Uri.AbsoluteUri); return 0; } } // make this call block so that we can check the time it takes to pull back the blob // this is a regional copy should be very quick even though it's queued but still make this defensive const int seconds = 1800; int count = 0; if (EndpointState.Async) return 0; while ((count * 10) < seconds) { // if we succeed we want to drop out this straight away if (destinationBlob.CopyState.Status == CopyStatus.Success) break; Thread.Sleep(100); count++; } //calculate the time taken and return return (int)DateTime.Now.Subtract(now).TotalSeconds; }
/// <summary> /// All the blobs are being copied from endpoint to another /// </summary> /// <param name="destinationEndpoint">the destination endpoint to copy to</param> /// <returns>A total of the number of seconds taken</returns> public int CopyAllBlobsTo(BlobEndpoint destinationEndpoint) { var container = GetCloudBlobContainer(this); var items = container.ListBlobs(useFlatBlobListing: true); return items.Sum(item => { EndpointState.BlobName = destinationEndpoint.EndpointState.BlobName = ((CloudBlockBlob) item).Name; return CopyBlobTo(destinationEndpoint); }); }
private static void Main(string[] args) { var program = new Program(); bool parse = program.ParseTokens(args); if (!parse) return; var sourceEndpointState = new BlobEndpointState() { AccountName = program.SourceCopyAccount, AccountKey = program.SourceAccountKey, ContainerName = program.SourceCopyContainer, BlobName = program.BlobName, Async = program.DoAsync, Force = program.Force }; var destinationEndpointState = new BlobEndpointState() { AccountName = program.DestinationCopyAccount, AccountKey = program.DestinationAccountKey, ContainerName = program.DestinationCopyContainer, BlobName = program.BlobName, Async = program.DoAsync, Force = program.Force }; var source = new BlobEndpoint(sourceEndpointState); var destination = new BlobEndpoint(destinationEndpointState); int timeTaken = program.BlobName != null ? source.CopyBlobTo(destination) : source.CopyAllBlobsTo(destination); if (program.DoAsync) Console.WriteLine("All blobs copied asynchronously"); else Console.WriteLine("All blobs copied in {0} seconds", timeTaken); Console.WriteLine("Press [q] to exit"); ConsoleKeyInfo info; do { info = Console.ReadKey(); } while (info.Key != ConsoleKey.Q); }
/// <summary> /// Used to get the blob client /// </summary> /// <param name="endpoint">the blob endpoint</param> /// <returns>A CloudBlobClient instance</returns> private CloudBlobContainer GetCloudBlobContainer(BlobEndpoint endpoint) { if (endpoint._endpoint != null) return null; string blobClientConnectString = String.Format("http://{0}.blob.core.windows.net", endpoint.EndpointState.AccountName); CloudBlobClient blobClient = null; if (endpoint.EndpointState.AccountKey == null) blobClient = new CloudBlobClient(new Uri(blobClientConnectString)); else { var account = new CloudStorageAccount(new StorageCredentials(endpoint.EndpointState.AccountName, endpoint.EndpointState.AccountKey), false); blobClient = account.CreateCloudBlobClient(); } var containerRef = blobClient.GetContainerReference(endpoint.EndpointState.ContainerName); containerRef.CreateIfNotExists(); return containerRef; }
///<summary> /// Used to pull back the cloud blob that should be copied from or to /// </summary> private ICloudBlob GetCloudBlob(BlobEndpoint endpoint) { if (endpoint.EndpointState.BlobName == null) { throw new ApplicationException("unknown blob name - please ensure this value is set"); } var containerRef = GetCloudBlobContainer(endpoint); return containerRef.GetBlockBlobReference(endpoint.EndpointState.BlobName); }
/// <summary> /// Shortcut for the source blob to check whether the blob can copy /// </summary> /// <param name="destinationBlobEndpoint">the destination endpoint</param> /// <returns>True if the blobs are identical</returns> private bool AreBlobsIdentical(BlobEndpoint destinationBlobEndpoint) { return AreBlobsIdentical(this, destinationBlobEndpoint); }
/// <summary> /// Used to determine whether the blobs are the same or not before copying /// </summary> /// <param name="sourceEndpoint">the endpoint of the source blob</param> /// <param name="destinationEndpoint">the endpoint of the destination blob</param> /// <returns>Checks whether the blobs are identical</returns> private bool AreBlobsIdentical(BlobEndpoint sourceEndpoint, BlobEndpoint destinationEndpoint) { bool exists = sourceEndpoint.BlobExists(sourceEndpoint.EndpointState.BlobName) && destinationEndpoint.BlobExists(destinationEndpoint.EndpointState.BlobName); if (!exists) return false; var sourceBlob = GetCloudBlob(sourceEndpoint); var destinationBlob = GetCloudBlob(destinationEndpoint); //need to fetch the attributes to get the md5 content tags sourceBlob.FetchAttributes(); destinationBlob.FetchAttributes(); // check to see whether the md5 content tags are the same return sourceBlob.Properties.ContentMD5 == destinationBlob.Properties.ContentMD5 && sourceBlob.Properties.Length == destinationBlob.Properties.Length; }