private async Task<HttpResponseMessage> SetContainerLease(CloudBlobContainer container) { IEnumerable<string> action; string leaseId = null; string proposedLeaseId = null; HttpResponseMessage response = new HttpResponseMessage(); AccessCondition condition; string serverLeaseId; await AddBasicContainerHeaders(response, container); //If an action is not provided, it's not a valid call. if (!Request.Headers.TryGetValues("x-ms-lease-action", out action)) { response.StatusCode = HttpStatusCode.BadRequest; return response; } if (Request.Headers.Contains("x-ms-lease-id")) { leaseId = Request.Headers.GetValues("x-ms-lease-id").FirstOrDefault(); } if (Request.Headers.Contains("x-ms-proposed-lease-id")) { proposedLeaseId = Request.Headers.GetValues("x-ms-proposed-lease-id").FirstOrDefault(); } switch (action.First().ToLower()) { case "acquire": int leaseDuration = Int32.Parse(Request.Headers.GetValues("x-ms-lease-duration").First()); TimeSpan? leaseDurationSpan; if (leaseDuration == -1) { leaseDurationSpan = null; } else if (leaseDuration >= 15 && leaseDuration <= 60) { leaseDurationSpan = new TimeSpan(0, 0, leaseDuration); } else { response.StatusCode = HttpStatusCode.BadRequest; return response; } serverLeaseId = await container.AcquireLeaseAsync(leaseDurationSpan, proposedLeaseId); response = new DelegatedResponse(await ContainerHandler.DoForDataContainersAsync(container.Name, HttpStatusCode.Created, async containerObj => await containerObj.AcquireLeaseAsync(leaseDurationSpan, serverLeaseId), true)).CreateResponse(); await AddBasicContainerHeaders(response, container); response.Headers.Add("x-ms-lease-id", serverLeaseId); return response; case "renew": condition = new AccessCondition() { LeaseId = leaseId }; response = new DelegatedResponse(await ContainerHandler.DoForAllContainersAsync(container.Name, HttpStatusCode.OK, async containerObj => await containerObj.RenewLeaseAsync(condition), true)).CreateResponse(); await AddBasicContainerHeaders(response, container); response.Headers.Add("x-ms-lease-id", leaseId); return response; case "change": condition = new AccessCondition() { LeaseId = leaseId }; serverLeaseId = await container.ChangeLeaseAsync(proposedLeaseId, condition); response = new DelegatedResponse(await ContainerHandler.DoForDataContainersAsync(container.Name, HttpStatusCode.OK, async containerObj => await containerObj.ChangeLeaseAsync(proposedLeaseId, condition), true)).CreateResponse(); await AddBasicContainerHeaders(response, container); response.Headers.Add("x-ms-lease-id", container.ChangeLease(proposedLeaseId, condition)); return response; case "release": condition = new AccessCondition() { LeaseId = leaseId }; response = new DelegatedResponse(await ContainerHandler.DoForAllContainersAsync(container.Name, HttpStatusCode.OK, async containerObj => await containerObj.ReleaseLeaseAsync(condition), true)).CreateResponse(); await AddBasicContainerHeaders(response, container); return response; case "break": int breakDuration = 0; if (Request.Headers.Contains("x-ms-lease-break-period")) { breakDuration = Int32.Parse(Request.Headers.GetValues("x-ms-lease-break-period").FirstOrDefault()); } TimeSpan breakDurationSpan = new TimeSpan(0, 0, breakDuration); TimeSpan remainingTime = await container.BreakLeaseAsync(breakDurationSpan); response = new DelegatedResponse(await ContainerHandler.DoForDataContainersAsync(container.Name, HttpStatusCode.Accepted, async containerObj => await containerObj.BreakLeaseAsync(breakDurationSpan), true)).CreateResponse(); await AddBasicContainerHeaders(response, container); response.Headers.Add("x-ms-lease-time", remainingTime.Seconds.ToString()); return response; default: //Not a recognized action response.StatusCode = HttpStatusCode.BadRequest; return response; } }
/// <summary> /// Puts the lease on the given container in a leased state. /// </summary> /// <param name="container">The container with the lease.</param> /// <param name="leaseTime">The amount of time on the new lease.</param> /// <returns>The lease ID of the current lease.</returns> internal static async Task<string> SetLeasedStateAsync(CloudBlobContainer container, TimeSpan? leaseTime) { string leaseId = Guid.NewGuid().ToString(); await SetUnleasedStateAsync(container); return await container.AcquireLeaseAsync(leaseTime, leaseId); }
private async Task<IEnumerable<IListBlobItem>> TransferBlobs( bool rename, CloudBlobContainer fromContainer, CloudBlobContainer toContainer, CancellationToken cancellationToken) { var requestOptions = new BlobRequestOptions() { RetryPolicy = new LinearRetry(TimeSpan.FromSeconds(2), 5) }; var leaseId = Guid.NewGuid().ToString(); var leaseResult = string.Empty; var autoEvent = new AutoResetEvent(false); var waitEvent = new AutoResetEvent(false); var leaseTimer = new Timer( async s => { try { if (string.IsNullOrEmpty(leaseResult)) { leaseResult = await fromContainer.AcquireLeaseAsync( TimeSpan.FromSeconds(60), leaseId, null, requestOptions, null, cancellationToken); waitEvent.Set(); } else { await fromContainer.RenewLeaseAsync( AccessCondition.GenerateLeaseCondition(leaseId), requestOptions, null, cancellationToken); } } catch (StorageException exception) { if (exception.RequestInformation.HttpStatusCode == (int)HttpStatusCode.Conflict) { this.logger.LogInformation("Staging container already has a lease."); } } }, autoEvent, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(50)); waitEvent.WaitOne(); try { BlobContinuationToken token = null; var blobList = new List<CopySpec>(); do { var result = await fromContainer.ListBlobsSegmentedAsync(token, cancellationToken); token = result.ContinuationToken; blobList.AddRange(result.Results.OfType<CloudBlob>().Select(b => new CopySpec() {SourceBlob = b})); } while (token != null); // Copy var copiedBlobList = new List<CopySpec>(); foreach (var blob in blobList) { var srcBlobName = blob.SourceBlob.Uri.Segments[2]; var blobName = rename ? $"{Path.GetFileNameWithoutExtension(srcBlobName)}{Guid.NewGuid().ToString().Replace("-", "")}{Path.GetExtension(srcBlobName)}" : srcBlobName; var destBlobRef = toContainer.GetBlobReference(blobName); blob.DestBlob = destBlobRef; try { await destBlobRef.StartCopyAsync( blob.SourceBlob.Uri, AccessCondition.GenerateEmptyCondition(), AccessCondition.GenerateEmptyCondition(), requestOptions, null, cancellationToken); copiedBlobList.Add(blob); } catch (Exception e) { this.logger.LogError($"Error while copying {blobName}. {e.ToString()}"); } } this.logger.LogInformation($"Started copying {copiedBlobList.Count} blobs"); var blobsToRemove = new List<CopySpec>(); var blobsToCheck = copiedBlobList.Select(b => b.SourceBlob.Uri.AbsoluteUri).ToList(); do { var withProperties = copiedBlobList.Select(b => { b.DestBlob.FetchAttributes(AccessCondition.GenerateEmptyCondition(), requestOptions, null); return b; }).ToList(); foreach (var blob in withProperties) { if (blob.DestBlob.CopyState.Status == CopyStatus.Aborted || blob.DestBlob.CopyState.Status == CopyStatus.Failed) { this.logger.LogError($"Cannot copy {blob.DestBlob.Uri}"); blobsToCheck.Remove(blob.SourceBlob.Uri.AbsoluteUri); } if (blob.DestBlob.CopyState.Status != CopyStatus.Success) continue; blobsToRemove.Add(blob); blobsToCheck.Remove(blob.SourceBlob.Uri.AbsoluteUri); } } while (blobsToCheck.Any()); this.logger.LogInformation($"{blobsToRemove.Count} blobs copied."); foreach (var blob in blobsToRemove) { try { await blob.SourceBlob.DeleteAsync( DeleteSnapshotsOption.IncludeSnapshots, AccessCondition.GenerateEmptyCondition(), requestOptions, null, cancellationToken); this.logger.LogInformation($"Deleted {blob.SourceBlob.Uri.AbsoluteUri}"); } catch (StorageException e) { if (e.RequestInformation.HttpStatusCode == (int)HttpStatusCode.NotFound) { this.logger.LogInformation($"Blob not found {blob.SourceBlob.Uri}"); } else { this.logger.LogError(e.ToString()); } } catch (Exception exception) { this.logger.LogError(exception.ToString()); } }; leaseTimer.Dispose(); await fromContainer.ReleaseLeaseAsync(AccessCondition.GenerateLeaseCondition(leaseId), requestOptions, null, cancellationToken); this.logger.LogInformation($"{blobsToRemove.Count} blobs deleted."); return copiedBlobList.Where(b => b.DestBlob.CopyState.Status == CopyStatus.Success).Select(b => b.DestBlob); } catch (Exception exception) { this.logger.LogCritical(exception.ToString()); return default(IEnumerable<IListBlobItem>); } }