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);
            }
        }
Exemple #3
0
        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);
        }