async Task ReScheduleSandboxResourceCreation(int sandboxId)
        {
            var sandbox = await _sandboxModelService.GetByIdForReScheduleCreateAsync(sandboxId);

            EnsureHasAllRequiredResourcesThrowIfNot(sandbox);

            var queueParentItem = QueueItemFactory.CreateParent($"Create basic resources for Sandbox (re-scheduled): {sandbox.Id}");

            foreach (var currentSandboxResource in sandbox.Resources.Where(r => r.SandboxControlled).OrderBy(r => r.Id))
            {
                var resourceCreateOperation = CloudResourceOperationUtil.GetCreateOperation(currentSandboxResource);

                if (resourceCreateOperation == null)
                {
                    throw new Exception(ReScheduleLogPrefix(sandbox.StudyId, sandbox.Id, $"Could not locate create operation for resource {currentSandboxResource.Id} - {currentSandboxResource.ResourceName}"));
                }

                if (resourceCreateOperation.Status == CloudResourceOperationState.ABANDONED)
                {
                    throw new Exception(ReScheduleLogPrefix(sandbox.StudyId, sandbox.Id, $"Create operation for resource {currentSandboxResource.Id} - {currentSandboxResource.ResourceName} was abandoned. Cannot proceed"));
                }

                await EnsureOperationIsReadyForRetryAndAddToQueueItem(currentSandboxResource, resourceCreateOperation, queueParentItem);
            }

            if (queueParentItem.Children.Count == 0)
            {
                throw new Exception(ReScheduleLogPrefix(sandbox.StudyId, sandbox.Id, $"Could not re-shedule creation. No relevant resource items found"));
            }
            else
            {
                await _provisioningQueueService.SendMessageAsync(queueParentItem);
            }
        }
        public async Task <CloudResource> CreateStudySpecificDatasetEntryAsync(int datasetId,
                                                                               int resourceGroupEntryId,
                                                                               string region,
                                                                               string resourceGroupName,
                                                                               string resourceName,
                                                                               Dictionary <string, string> tags)
        {
            var currentUser = await _userService.GetCurrentUserAsync();

            var sessionId = _requestIdService.GetRequestId();

            var resourceGroupEntry = await GetInternalWithoutAccessCheckAsync(resourceGroupEntryId);

            if (resourceGroupEntry == null)
            {
                throw new Exception("Could not find Resource Group entry");
            }

            var resourceGroupCreateOperation = CloudResourceOperationUtil.GetCreateOperation(resourceGroupEntry);

            if (resourceGroupCreateOperation == null)
            {
                throw new Exception("Could not find Resource Group create operation entry");
            }

            var resourceEntry =
                CloudResourceFactory.CreateStudySpecificDatasetStorageAccountEntry(
                    currentUser, sessionId, datasetId, region,
                    resourceGroupEntryId, resourceGroupName, resourceName, tags, resourceGroupCreateOperation.Id);

            await SaveToDb(resourceEntry);

            return(resourceEntry);
        }
        async Task ScheduleResourceGroupRoleAssignments(Study study, CloudResource resourceGroup, ProvisioningQueueParentDto queueParentItem)
        {
            var participants = await _db.StudyParticipants.Include(sp => sp.User).Where(p => p.StudyId == study.Id).ToListAsync();

            var desiredState = CloudResourceConfigStringSerializer.Serialize(new CloudResourceOperationStateForRoleUpdate(study.Id));

            var resourceGroupCreateOperation = CloudResourceOperationUtil.GetCreateOperation(resourceGroup);

            var roleAssignmentUpdateOperation = await _cloudResourceOperationCreateService.CreateUpdateOperationAsync(resourceGroup.Id, CloudResourceOperationType.ENSURE_ROLES, dependsOn : resourceGroupCreateOperation.Id, desiredState : desiredState);

            ProvisioningQueueUtil.CreateChildAndAdd(queueParentItem, roleAssignmentUpdateOperation);
        }
        async Task OrderCreationOfStudySpecificDatasetStorageAccount(Study study, Dataset dataset, CloudResource resourceGroup, string clientIp, ProvisioningQueueParentDto queueParent, CancellationToken cancellationToken)
        {
            try
            {
                if (resourceGroup == null)
                {
                    throw new ArgumentNullException("resourceGroup", "Resource group entry is null");
                }

                _logger.LogInformation($"CreateResourcesForStudySpecificDataset - Dataset Id: {dataset.Id}");

                var currentUser = await _userService.GetCurrentUserAsync();

                var tagsForStorageAccount = ResourceTagFactory.StudySpecificDatasourceStorageAccountTags(_config, study, dataset.Name);
                var storageAccountName    = AzureResourceNameUtil.StudySpecificDataSetStorageAccount(dataset.Name);

                var resourceEntry = await _cloudResourceCreateService.CreateStudySpecificDatasetEntryAsync(dataset.Id, resourceGroup.Id, resourceGroup.Region, resourceGroup.ResourceGroupName, storageAccountName, tagsForStorageAccount);

                ProvisioningQueueUtil.CreateChildAndAdd(queueParent, resourceEntry);

                var serverPublicIp = await _publicIpService.GetIp();

                DatasetFirewallUtils.EnsureDatasetHasFirewallRules(_logger, currentUser, dataset, clientIp, serverPublicIp);

                await _db.SaveChangesAsync();

                var stateForFirewallOperation = DatasetFirewallUtils.TranslateAllowedIpsToOperationDesiredState(dataset.FirewallRules.ToList());

                var createStorageAccountOperation = CloudResourceOperationUtil.GetCreateOperation(resourceEntry);
                var firewallUpdateOperation       = await _cloudResourceOperationCreateService.CreateUpdateOperationAsync(resourceEntry.Id, CloudResourceOperationType.ENSURE_FIREWALL_RULES, dependsOn : createStorageAccountOperation.Id, desiredState : stateForFirewallOperation);

                ProvisioningQueueUtil.CreateChildAndAdd(queueParent, firewallUpdateOperation);

                var stateForCorsRules   = DatasetCorsUtils.CreateDatasetCorsRules(_config);
                var corsUpdateOperation = await _cloudResourceOperationCreateService.CreateUpdateOperationAsync(resourceEntry.Id, CloudResourceOperationType.ENSURE_CORS_RULES, dependsOn : firewallUpdateOperation.Id, desiredState : stateForCorsRules);

                ProvisioningQueueUtil.CreateChildAndAdd(queueParent, corsUpdateOperation);
            }
            catch (Exception ex)
            {
                throw new Exception($"Failed to schedule creation of Azure Storage Account", ex);
            }
        }
        async Task <CloudResource> EnsureResourceGroupExists(Study study, Dataset dataset, ProvisioningQueueParentDto parentQueueItem)
        {
            try
            {
                var resourceGroupDb = GetResourceGroupForStudySpecificDataset(study);

                if (resourceGroupDb == null)
                {
                    resourceGroupDb = await CreateResourceGroupForStudySpecificDatasetsInternalAsync(study, parentQueueItem);
                }
                else
                {
                    if (String.IsNullOrWhiteSpace(resourceGroupDb.LastKnownProvisioningState))
                    {
                        var resourceGroupCreateOperation = CloudResourceOperationUtil.GetCreateOperation(resourceGroupDb);

                        //Old and failed, give it another try
                        if (resourceGroupCreateOperation != null &&
                            resourceGroupCreateOperation.Created.AddMinutes(10) <= DateTime.UtcNow &&
                            (resourceGroupCreateOperation.Status == CloudResourceOperationState.FAILED || resourceGroupCreateOperation.Status == CloudResourceOperationState.ABORTED))
                        {
                            ProvisioningQueueUtil.CreateChildAndAdd(parentQueueItem, resourceGroupDb);
                        }
                    }
                    else
                    {
                        if (resourceGroupDb.LastKnownProvisioningState == CloudResourceProvisioningStates.SUCCEEDED || resourceGroupDb.LastKnownProvisioningState == CloudResourceProvisioningStates.CREATING)
                        {
                            return(resourceGroupDb);
                        }
                    }
                }

                return(resourceGroupDb);
            }
            catch (Exception ex)
            {
                throw new Exception($"Failed to locate or ensure that resource group exist for storage account", ex);
            }
        }