private async Task <HttpResponseMessage> SetContainerAcl(CloudBlobContainer container) { var formatter = GlobalConfiguration.Configuration.Formatters.XmlFormatter; var stream = await Request.Content.ReadAsStreamAsync(); SharedAccessBlobPolicies policies = (SharedAccessBlobPolicies)await formatter.ReadFromStreamAsync(typeof(SharedAccessBlobPolicies), stream, null, null); string accessLevel = Request.Headers.GetValues("x-ms-blob-public-access").FirstOrDefault(); BlobContainerPublicAccessType access = BlobContainerPublicAccessType.Off; if (!String.IsNullOrWhiteSpace(accessLevel)) { if (accessLevel.ToLower() == "blob") { access = BlobContainerPublicAccessType.Blob; } else if (accessLevel.ToLower() == "container") { access = BlobContainerPublicAccessType.Container; } } BlobContainerPermissions perms = new BlobContainerPermissions() { PublicAccess = access }; foreach (var policy in policies) { perms.SharedAccessPolicies.Add(policy); } var status = await ContainerHandler.DoForAllContainersAsync(container.Name, HttpStatusCode.OK, async containerObj => await containerObj.SetPermissionsAsync(perms), true); HttpResponseMessage response = new HttpResponseMessage(status.StatusCode); await AddBasicContainerHeaders(response, container); return(response); }
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); } }
public static async Task ImportAccountAsync(string accountName) { await OperationRunner.DoActionAsync(String.Format("Importing data account: {0}", accountName), async() => { // This method will only import the blobs into the namespace. A future task may be // to redistribute the blobs to balance the entire virtual account. var account = DashConfiguration.GetDataAccountByAccountName(accountName); if (account == null) { DashTrace.TraceWarning("Failure importing storage account: {0}. The storage account has not been configured as part of this virtual account", accountName); return; } // Check if we've already imported this account var accountClient = account.CreateCloudBlobClient(); var namespaceClient = DashConfiguration.NamespaceAccount.CreateCloudBlobClient(); var accountContainers = await ListContainersAsync(accountClient); var status = await AccountStatus.GetAccountStatus(accountName); await status.UpdateStatusInformation(AccountStatus.States.Healthy, "Importing storage account: {0} into virtual account", accountName); bool alreadyImported = false; await GetAccountBlobs(accountClient, async(blobItem) => { var blob = (ICloudBlob)blobItem; var namespaceBlob = await NamespaceBlob.FetchForBlobAsync( (CloudBlockBlob)NamespaceHandler.GetBlobByName(DashConfiguration.NamespaceAccount, blob.Container.Name, blob.Name, blob.IsSnapshot ? blob.SnapshotTime.ToString() : String.Empty)); alreadyImported = await namespaceBlob.ExistsAsync(true) && namespaceBlob.DataAccounts.Contains(accountName, StringComparer.OrdinalIgnoreCase); return(false); }); if (alreadyImported) { await status.UpdateStatusWarning("Importing storage account: {0} has already been imported. This account cannot be imported again.", accountName); return; } // Sync the container structure first - add containers in the imported account to the virtual account await status.UpdateStatusInformation("Importing storage account: {0}. Synchronizing container structure", accountName); int containersAddedCount = 0, containersWarningCount = 0; var namespaceContainers = await ListContainersAsync(namespaceClient); await ProcessContainerDifferencesAsync(accountContainers, namespaceContainers, async(newContainerName, accountContainer) => { var createContainerResult = await ContainerHandler.DoForAllContainersAsync(newContainerName, HttpStatusCode.Created, async newContainer => await CopyContainer(accountContainer, newContainer), true, new[] { account }); if (createContainerResult.StatusCode < HttpStatusCode.OK || createContainerResult.StatusCode >= HttpStatusCode.Ambiguous) { await status.UpdateStatusWarning("Importing storage account: {0}. Failed to create container: {1} in virtual account. Details: {2}, {3}", accountName, newContainerName, createContainerResult.StatusCode.ToString(), createContainerResult.ReasonPhrase); containersWarningCount++; } else { containersAddedCount++; } }, (newContainerName, ex) => { status.UpdateStatusWarning("Importing storage account: {0}. Error processing container {1}. Details: {2}", accountName, newContainerName, ex.ToString()).Wait(); containersWarningCount++; }); // Sync the other way await ProcessContainerDifferencesAsync(namespaceContainers, accountContainers, async(newContainerName, namespaceContainer) => { await CopyContainer(namespaceContainer, accountClient.GetContainerReference(newContainerName)); }, (newContainerName, ex) => { status.UpdateStatusWarning("Importing storage account: {0}. Error replicating container {1} to imported account. Details: {2}", accountName, newContainerName, ex.ToString()).Wait(); containersWarningCount++; }); DashTrace.TraceInformation("Importing storage account: {0}. Synchronized containers structure. {1} containers added to virtual account. {2} failures/warnings.", accountName, containersAddedCount, containersWarningCount); // Start importing namespace entries await status.UpdateStatusInformation("Importing storage account: {0}. Adding blob entries to namespace", accountName); int blobsAddedCount = 0, warningCount = 0, duplicateCount = 0; await GetAccountBlobs(accountClient, async(blobItem) => { var blob = (ICloudBlob)blobItem; try { var namespaceBlob = await NamespaceBlob.FetchForBlobAsync( (CloudBlockBlob)NamespaceHandler.GetBlobByName(DashConfiguration.NamespaceAccount, blob.Container.Name, blob.Name, blob.IsSnapshot ? blob.SnapshotTime.ToString() : String.Empty)); if (await namespaceBlob.ExistsAsync()) { if (!String.Equals(namespaceBlob.PrimaryAccountName, accountName, StringComparison.OrdinalIgnoreCase)) { await status.UpdateStatusWarning("Importing storage account: {0}. Adding blob: {1}/{2} would result in a duplicate blob entry. This blob will NOT be imported into the virtual account. Manually add the contents of this blob to the virtual account.", accountName, blob.Container.Name, blob.Name); duplicateCount++; } } else { namespaceBlob.PrimaryAccountName = accountName; namespaceBlob.Container = blob.Container.Name; namespaceBlob.BlobName = blob.Name; namespaceBlob.IsMarkedForDeletion = false; await namespaceBlob.SaveAsync(); blobsAddedCount++; } } catch (StorageException ex) { status.UpdateStatusWarning("Importing storage account: {0}. Error importing blob: {0}/{1} into virtual namespace. Details: {3}", accountName, blob.Container.Name, blob.Name, ex.ToString()).Wait(); warningCount++; } return(true); }); if (status.State < AccountStatus.States.Warning) { await status.UpdateStatus(String.Empty, AccountStatus.States.Unknown, TraceLevel.Off); } DashTrace.TraceInformation("Successfully imported the contents of storage account: '{0}' into the virtual namespace. Blobs added: {1}, duplicates detected: {2}, errors encountered: {3}", accountName, blobsAddedCount, duplicateCount, warningCount); }, ex => { var status = AccountStatus.GetAccountStatus(accountName).Result; status.UpdateStatusWarning("Error importing storage account: {0} into virtual account. Details: {1}", accountName, ex.ToString()).Wait(); }, false, true); }