async Task <string> CreateVmSettingsString(string region, int vmId, int studyId, int sandboxId, VirtualMachineCreateDto userInput)
        {
            var vmSettings = _mapper.Map <VmSettingsDto>(userInput);

            var availableOs = await _virtualMachineOperatingSystemService.AvailableOperatingSystems(region);

            vmSettings.OperatingSystemCategory = AzureVmUtil.GetOsCategory(availableOs, vmSettings.OperatingSystem);

            vmSettings.Password = await StoreNewVmPasswordAsKeyVaultSecretAndReturnReference(studyId, sandboxId, vmSettings.Password);

            var diagStorageResource = await CloudResourceQueries.GetDiagStorageAccountEntry(_db, sandboxId);

            vmSettings.DiagnosticStorageAccountName = diagStorageResource.ResourceName;

            var networkResource = await CloudResourceQueries.GetNetworkEntry(_db, sandboxId);

            vmSettings.NetworkName = networkResource.ResourceName;

            var networkSetting = CloudResourceConfigStringSerializer.NetworkSettings(networkResource.ConfigString);

            vmSettings.SubnetName = networkSetting.SandboxSubnetName;

            vmSettings.Rules = VmRuleUtils.CreateInitialVmRules(vmId);
            return(CloudResourceConfigStringSerializer.Serialize(vmSettings));
        }
예제 #2
0
        public async Task <ResourceProvisioningResult> EnsureCreated(ResourceProvisioningParameters parameters, CancellationToken cancellationToken = default)
        {
            _logger.LogInformation($"Creating virtual network {parameters.Name} in resource Group: {parameters.ResourceGroupName}");

            var networkSettings = CloudResourceConfigStringSerializer.NetworkSettings(parameters.ConfigurationString);

            var virtualNetwork = await GetResourceInternalAsync(parameters.ResourceGroupName, parameters.Name, false);

            if (virtualNetwork == null)
            {
                virtualNetwork = await CreateInternalAsync(GetRegionFromString(parameters.Region), parameters.ResourceGroupName, parameters.Name, networkSettings.SandboxSubnetName, parameters.Tags, cancellationToken);
            }

            if (!parameters.TryGetSharedVariable(AzureCrudSharedVariable.NETWORK_SECURITY_GROUP_NAME, out string networkSecurityGroupName))
            {
                throw new ArgumentException("AzureVirtualNetworkService: Missing network security group name from input");
            }

            await EnsureNetworkSecurityGroupIsAddedToSubnet(virtualNetwork, networkSecurityGroupName, networkSettings.SandboxSubnetName);

            _logger.LogInformation($"Done creating virtual network {parameters.Name}");

            var crudResult = CreateResult(virtualNetwork);

            return(crudResult);
        }
예제 #3
0
        public async Task Handle(
            CloudResourceOperationDto operation,
            IHasCorsRules corsRuleService)
        {
            try
            {
                var cancellation = new CancellationTokenSource();

                if (string.IsNullOrWhiteSpace(operation.DesiredState))
                {
                    throw new NullReferenceException($"Desired state empty on operation {operation.Id}: {operation.Description}");
                }

                var rulesFromOperationState = CloudResourceConfigStringSerializer.DesiredCorsRules(operation.DesiredState);

                var setRulesTask = corsRuleService.SetCorsRules(operation.Resource.ResourceGroupName, operation.Resource.ResourceName, rulesFromOperationState, cancellation.Token);

                while (!setRulesTask.IsCompleted)
                {
                    operation = await _cloudResourceOperationUpdateService.TouchAsync(operation.Id);

                    if (await _cloudResourceReadService.ResourceIsDeleted(operation.Resource.Id) || operation.Status == CloudResourceOperationState.ABORTED || operation.Status == CloudResourceOperationState.ABANDONED)
                    {
                        _provisioningLogService.OperationWarning(operation, $"Operation aborted, cors rule assignment will be aborted");
                        cancellation.Cancel();
                        break;
                    }

                    Thread.Sleep((int)TimeSpan.FromSeconds(3).TotalMilliseconds);
                }

                if (setRulesTask.IsCompletedSuccessfully)
                {
                }
                else
                {
                    if (setRulesTask.Exception == null)
                    {
                        throw new Exception("cors rule assignment task failed");
                    }
                    else
                    {
                        throw setRulesTask.Exception;
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null && ex.InnerException.Message.Contains("A task was canceled"))
                {
                    throw new ProvisioningException($"Resource provisioning (Ensure cors rules) aborted.", logAsWarning: true, innerException: ex.InnerException);
                }
                else
                {
                    throw new ProvisioningException($"Resource provisioning (Ensure cors rules) failed.", CloudResourceOperationState.FAILED, postponeQueueItemFor: 10, innerException: ex);
                }
            }
        }
예제 #4
0
        public async Task <List <VmRuleDto> > GetRules(int vmId, CancellationToken cancellationToken = default)
        {
            var vm = await GetVirtualMachineResourceEntry(vmId, UserOperation.Study_Read);

            //Get config string
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(vm.ConfigString);

            return(vmSettings.Rules != null ? vmSettings.Rules : new List <VmRuleDto>());
        }
예제 #5
0
        public async Task Handle(CloudResourceOperationDto operation)
        {
            try
            {
                var cancellation = new CancellationTokenSource();

                if (string.IsNullOrWhiteSpace(operation.DesiredState))
                {
                    throw new NullReferenceException($"Desired state empty on operation {operation.Id}: {operation.Description}");
                }

                var operationStateDeserialized = CloudResourceConfigStringSerializer.DesiredRoleAssignment(operation.DesiredState);
                var study = await _studyModelService.GetWithParticipantsAndUsersNoAccessCheck(operationStateDeserialized.StudyId);

                var currentRoleAssignmentTask = SetRoleAssignments(operation, study, cancellation.Token);

                while (!currentRoleAssignmentTask.IsCompleted)
                {
                    operation = await _cloudResourceOperationUpdateService.TouchAsync(operation.Id);

                    if (await _cloudResourceReadService.ResourceIsDeleted(operation.Resource.Id) ||
                        operation.Status == CloudResourceOperationState.ABORTED ||
                        operation.Status == CloudResourceOperationState.ABANDONED)
                    {
                        _provisioningLogService.OperationWarning(operation, $"Operation aborted, role assignment will be aborted", eventId: _roleAssignmentEventId);
                        cancellation.Cancel();
                        break;
                    }

                    Thread.Sleep((int)TimeSpan.FromSeconds(3).TotalMilliseconds);
                }

                if (!currentRoleAssignmentTask.IsCompletedSuccessfully)
                {
                    if (currentRoleAssignmentTask.Exception == null)
                    {
                        throw new Exception("Role assignment task failed");
                    }
                    else
                    {
                        throw currentRoleAssignmentTask.Exception;
                    }
                }
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null && ex.InnerException.Message.Contains("A task was canceled"))
                {
                    throw new ProvisioningException($"Resource provisioning (Ensure role assignments) aborted.", logAsWarning: true, innerException: ex.InnerException);
                }
                else
                {
                    throw new ProvisioningException($"Resource provisioning (Ensure role assignments) failed.", CloudResourceOperationState.FAILED, postponeQueueItemFor: 10, innerException: ex);
                }
            }
        }
예제 #6
0
        public static string GetOsName(CloudResource resource)
        {
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(resource.ConfigString);

            if (vmSettings != null)
            {
                return(vmSettings.OperatingSystem);
            }

            return(null);
        }
예제 #7
0
        public static string TranslateAllowedIpsToOperationDesiredState(List <DatasetFirewallRule> datasetFirewallRules)
        {
            if (datasetFirewallRules.Count == 0)
            {
                return(null);
            }

            var translated = TranslateAllowedIpsToGenericFirewallRule(datasetFirewallRules);

            return(CloudResourceConfigStringSerializer.Serialize(translated));
        }
예제 #8
0
        async Task ScheduleCreationOfSandboxResourceGroupRoleAssignments(SandboxResourceCreationAndSchedulingDto dto, ProvisioningQueueParentDto queueParentItem)
        {
            var desiredState = CloudResourceConfigStringSerializer.Serialize(new CloudResourceOperationStateForRoleUpdate(dto.StudyId));
            var resourceGroupCreateOperation = dto.ResourceGroup.Operations.FirstOrDefault().Id;
            var updateOpId = await _cloudResourceOperationCreateService.CreateUpdateOperationAsync(dto.ResourceGroup.Id, CloudResourceOperationType.ENSURE_ROLES, dependsOn : resourceGroupCreateOperation, desiredState : desiredState);

            queueParentItem.Children.Add(new ProvisioningQueueChildDto()
            {
                ResourceOperationId = updateOpId.Id
            });
        }
        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);
        }
        protected async Task CreateRoleUpdateOperationsAsync(int studyId)
        {
            var resourcesToUpdate = await _cloudResourceReadService.GetDatasetResourceGroupIdsForStudy(studyId);

            resourcesToUpdate.AddRange(await _cloudResourceReadService.GetSandboxResourceGroupIdsForStudy(studyId));

            foreach (var currentResourceId in resourcesToUpdate)
            {
                var desiredState    = CloudResourceConfigStringSerializer.Serialize(new CloudResourceOperationStateForRoleUpdate(studyId));
                var updateOperation = await _cloudResourceOperationCreateService.CreateUpdateOperationAsync(currentResourceId, CloudResourceOperationType.ENSURE_ROLES, desiredState : desiredState);

                await _provisioningQueueService.CreateItemAndEnqueue(updateOperation);
            }
        }
        public async Task <ResourceProvisioningResult> Update(ResourceProvisioningParameters parameters, CancellationToken cancellationToken = default)
        {
            _logger.LogInformation($"Updating VM {parameters.Name}");

            var vm = await GetInternalAsync(parameters.ResourceGroupName, parameters.Name);

            var primaryNic = await _azure.NetworkInterfaces.GetByIdAsync(vm.PrimaryNetworkInterfaceId, cancellationToken);

            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(parameters.ConfigurationString);

            await UpdateVmRules(parameters, vmSettings, primaryNic.PrimaryPrivateIP, cancellationToken);

            var result = CreateCRUDResult(vm);

            return(result);
        }
예제 #12
0
        static string CreateVmSettingsString(string size = VirtualMachineConstants.SIZE, string osCategory = "windows", string os = "win2019datacenter")
        {
            var vmSettings = new VmSettingsDto()
            {
                DiagnosticStorageAccountName = "diagstorageaccountname",
                NetworkName             = "networkName",
                SubnetName              = "subnetname",
                Size                    = size,
                Rules                   = VmRuleUtils.CreateInitialVmRules(1),
                OperatingSystemCategory = osCategory,
                OperatingSystem         = os,
                Username                = VirtualMachineConstants.USERNAME,
                Password                = "******",
            };

            return(CloudResourceConfigStringSerializer.Serialize(vmSettings));
        }
예제 #13
0
        async Task ScheduleCreationOfVirtualNetwork(SandboxResourceCreationAndSchedulingDto dto, ProvisioningQueueParentDto queueParentItem)
        {
            var networkName       = AzureResourceNameUtil.VNet(dto.StudyName, dto.SandboxName);
            var sandboxSubnetName = AzureResourceNameUtil.SubNet(dto.StudyName, dto.SandboxName);

            var networkSettings = new NetworkSettingsDto()
            {
                SandboxSubnetName = sandboxSubnetName
            };
            var networkSettingsString = CloudResourceConfigStringSerializer.Serialize(networkSettings);

            var nsgCreateOperation = dto.NetworkSecurityGroup.Operations.FirstOrDefault().Id;

            var resourceEntry = await CreateResourceEntryAndAddToQueue(dto, queueParentItem, AzureResourceType.VirtualNetwork, resourceName : networkName, configString : networkSettingsString, dependsOn : nsgCreateOperation);

            dto.Network = resourceEntry;
        }
        async Task DeleteInternalAsync(string resourceGroupName, string virtualMachineName, string networkSecurityGroupName, string configString)
        {
            var vm = await GetInternalAsync(resourceGroupName, virtualMachineName, false);

            if (vm == null)
            {
                _logger.LogWarning($"Virtual Machine {virtualMachineName} appears to be deleted allready");
                return;
            }

            //Ensure resource is is managed by this instance
            EnsureResourceIsManagedByThisIEnvironmentThrowIfNot(resourceGroupName, vm.Tags);

            await _azure.VirtualMachines.DeleteByResourceGroupAsync(resourceGroupName, virtualMachineName);

            //Delete all the disks
            await DeleteDiskById(vm.OSDiskId);

            foreach (var curNic in vm.NetworkInterfaceIds)
            {
                await DeleteNic(curNic);
            }

            foreach (var curDiskKvp in vm.DataDisks)
            {
                await DeleteDiskById(curDiskKvp.Value.Id);
            }

            //Delete VM rules
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(configString);

            foreach (var curRule in vmSettings.Rules)
            {
                try
                {
                    await _azureNetworkSecurityGroupRuleService.DeleteRule(resourceGroupName, networkSecurityGroupName, curRule.Name);
                }
                catch (Exception)
                {
                    _logger.LogWarning($"Delete VM: Failed to delete NSG rule {curRule.Name} for vm {virtualMachineName}. Assuming it has allready been deleted");
                }
            }
        }
예제 #15
0
        public async Task <VmRuleDto> GetRuleById(int vmId, string ruleId, CancellationToken cancellationToken = default)
        {
            var vm = await GetVirtualMachineResourceEntry(vmId, UserOperation.Study_Read);

            //Get config string
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(vm.ConfigString);

            if (vmSettings.Rules != null)
            {
                foreach (var curExistingRule in vmSettings.Rules)
                {
                    if (curExistingRule.Name == ruleId)
                    {
                        return(curExistingRule);
                    }
                }
            }

            throw new NotFoundException($"Rule with id {ruleId} does not exist");
        }
예제 #16
0
        public async Task <VmRuleDto> GetInternetRule(int vmId)
        {
            var vm = await GetVirtualMachineResourceEntry(vmId, UserOperation.Study_Crud_Sandbox);

            //Get config string
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(vm.ConfigString);

            if (vmSettings.Rules != null)
            {
                foreach (var curRule in vmSettings.Rules)
                {
                    if (curRule.Direction == RuleDirection.Outbound)
                    {
                        if (curRule.Name.Contains(AzureVmConstants.RulePresets.OPEN_CLOSE_INTERNET))
                        {
                            return(curRule);
                        }
                    }
                }
            }

            return(null);
        }
예제 #17
0
        public static VmRuleDto GetInternetRule(CloudResource vmResource)
        {
            if (!String.IsNullOrWhiteSpace(vmResource.ConfigString))
            {
                var vmSettings = CloudResourceConfigStringSerializer.VmSettings(vmResource.ConfigString);

                if (vmSettings != null && vmSettings.Rules != null)
                {
                    foreach (var curRule in vmSettings.Rules)
                    {
                        if (curRule.Direction == RuleDirection.Outbound)
                        {
                            if (curRule.Name.Contains(AzureVmConstants.RulePresets.OPEN_CLOSE_INTERNET))
                            {
                                return(curRule);
                            }
                        }
                    }
                }
            }

            return(null);
        }
        public async Task <ResourceProvisioningResult> EnsureCreated(ResourceProvisioningParameters parameters, CancellationToken cancellationToken = default)
        {
            _logger.LogInformation($"Ensuring VM exists: {parameters.Name} in resource Group: {parameters.ResourceGroupName}");

            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(parameters.ConfigurationString);

            var virtualMachine = await GetInternalAsync(parameters.ResourceGroupName, parameters.Name, false);

            if (virtualMachine == null)
            {
                _logger.LogInformation($"VM {parameters.Name} did not exist in resource Group: {parameters.ResourceGroupName}, creating!");

                var    passwordReference = vmSettings.Password;
                string password          = await GetPasswordFromKeyVault(passwordReference);

                string vmSize = vmSettings.Size;

                virtualMachine = await CreateInternalAsync(GetRegionFromString(parameters.Region),
                                                           parameters.ResourceGroupName,
                                                           parameters.Name,
                                                           vmSettings.NetworkName, vmSettings.SubnetName,
                                                           vmSettings.Username, password,
                                                           vmSize, vmSettings.OperatingSystem, vmSettings.OperatingSystemCategory, parameters.Tags,
                                                           vmSettings.DiagnosticStorageAccountName, cancellationToken);

                await DeletePasswordFromKeyVault(passwordReference);

                if (vmSettings.DataDisks != null && vmSettings.DataDisks.Count > 0)
                {
                    foreach (var curDisk in vmSettings.DataDisks)
                    {
                        var sizeAsInt = Convert.ToInt32(curDisk);

                        if (sizeAsInt == 0)
                        {
                            throw new Exception($"Illegal data disk size: {curDisk}");
                        }

                        await ApplyVmDataDisksInternalAsync(parameters.ResourceGroupName, parameters.Name, sizeAsInt, parameters.Tags);
                    }
                }

                _logger.LogInformation($"Done creating Virtual Machine for sandbox with Id: {parameters.SandboxId}! Id: {virtualMachine.Id}");
            }
            else
            {
                //Validate data disks
                if (vmSettings.DataDisks != null && vmSettings.DataDisks.Count > 0)
                {
                    if (virtualMachine.DataDisks.Count != vmSettings.DataDisks.Count)
                    {
                        throw new Exception($"Data disk(s) not created properly. Expected count of {vmSettings.DataDisks}, saw {vmSettings.DataDisks.Count} on VM");
                    }
                }
            }

            var primaryNic = await _azure.NetworkInterfaces.GetByIdAsync(virtualMachine.PrimaryNetworkInterfaceId, cancellationToken);

            //Add tags to NIC
            await primaryNic.UpdateTags().WithTags(parameters.Tags).ApplyTagsAsync();

            await UpdateVmRules(parameters, vmSettings, primaryNic.PrimaryPrivateIP, cancellationToken);

            var result = CreateCRUDResult(virtualMachine);

            return(result);
        }
예제 #19
0
        public async Task <List <VmRuleDto> > SetRules(int vmId, List <VmRuleDto> updatedRuleSet, CancellationToken cancellationToken = default)
        {
            var vm = await GetVirtualMachineResourceEntry(vmId, UserOperation.Study_Crud_Sandbox);


            //Get config string
            var vmSettings = CloudResourceConfigStringSerializer.VmSettings(vm.ConfigString);

            await ValidateRuleUpdateInputThrowIfNot(vm, vmSettings.Rules, updatedRuleSet);

            bool saveAfterwards = false;

            if (updatedRuleSet == null || updatedRuleSet != null && updatedRuleSet.Count == 0) //Easy, all rules should be deleted
            {
                vmSettings.Rules = null;
                saveAfterwards   = true;
            }
            else
            {
                var newRules = updatedRuleSet.Where(r => String.IsNullOrWhiteSpace(r.Name)).ToList();
                var rulesThatShouldExistAllready = updatedRuleSet.Where(r => !String.IsNullOrWhiteSpace(r.Name)).ToList();

                //Check that the new rules does not have a duplicate in existing rules
                foreach (var curNew in newRules)
                {
                    ThrowIfRuleExists(rulesThatShouldExistAllready, curNew);
                }

                foreach (var curRule in updatedRuleSet)
                {
                    if (curRule.Direction == RuleDirection.Inbound)
                    {
                        if (curRule.Action == RuleAction.Deny)
                        {
                            throw new ArgumentException("Inbound rules can only have Action: Allow");
                        }

                        if (String.IsNullOrWhiteSpace(curRule.Name))
                        {
                            curRule.Name = AzureResourceNameUtil.NsgRuleNameForVm(vmId);
                            //curRule.Priority = AzureVmUtil.GetNextVmRulePriority(updatedRuleSet, curRule.Direction);
                        }
                    }
                    else
                    {
                        if (String.IsNullOrWhiteSpace(curRule.Name) || !curRule.Name.Contains(AzureVmConstants.RulePresets.OPEN_CLOSE_INTERNET))
                        {
                            throw new ArgumentException("Custom outbound rules are not allowed");
                        }
                    }
                }

                vmSettings.Rules = updatedRuleSet;
                saveAfterwards   = true;
            }

            if (saveAfterwards)
            {
                vm.ConfigString = CloudResourceConfigStringSerializer.Serialize(vmSettings);

                await _db.SaveChangesAsync();

                await CreateUpdateOperationAndAddQueueItem(vm, "Updated rules");
            }

            return(updatedRuleSet != null ? updatedRuleSet : new List <VmRuleDto>());
        }