public async Task <Run> Handle(Command request, CancellationToken cancellationToken) { if (!(await _authorizationService.AuthorizeAsync(_user, null, new ContentDeveloperRequirement())).Succeeded) { throw new ForbiddenException(); } await ValidateWorkspace(request.WorkspaceId); Domain.Models.Run run = null; using (var lockResult = await _lockService.GetWorkspaceLock(request.WorkspaceId).LockAsync(0)) { if (!lockResult.AcquiredLock) { throw new WorkspaceConflictException(); } if ((await _db.AnyIncompleteRuns(request.WorkspaceId))) { throw new ConflictException("This Workspace's current Run must be rejected or applied before a new one can be created."); } run = await this.DoWork(request); } await _mediator.Publish(new RunCreated { RunId = run.Id }); return(_mapper.Map <Run>(run)); }
private void ValidateRun(Domain.Models.Run run) { if (run == null) { throw new EntityNotFoundException <Run>(); } if (run.Status != RunStatus.Applying && run.Status != RunStatus.Planning) { throw new InvalidOperationException("Cannot cancel a Run without a Plan or Apply in progress"); } }
private void ValidateRun(Domain.Models.Run run) { if (run == null) { throw new EntityNotFoundException <Run>(); } if (run.Plan == null || run.Plan.Status == PlanStatus.Queued || run.Plan.Status == PlanStatus.Planning) { throw new InvalidOperationException("Cannot reject a Run with a Plan in progress. Please try again when it has completed."); } if (run.Apply != null) { throw new ConflictException("Cannot reject a Run that is already being applied"); } }
private async Task ValidateRun(Domain.Models.Run run, CancellationToken cancellationToken) { if (run.Status != RunStatus.Applied_StateError && run.Status != RunStatus.Failed_StateError) { throw new WorkspaceConflictException(); } var notLatest = await _db.Runs .AnyAsync(r => r.WorkspaceId == run.WorkspaceId && r.CreatedAt > run.CreatedAt, cancellationToken); if (notLatest) { throw new ConflictException("State can only be saved for the latest Run."); } }
private async Task <Domain.Models.Plan> CreatePlan(Domain.Models.Run run) { var plan = new Domain.Models.Plan { RunId = run.Id, Status = Domain.Models.PlanStatus.Planning }; run.Plan = plan; run.Status = Domain.Models.RunStatus.Planning; await _db.AddAsync(plan); await _db.SaveChangesAsync(); _output = _outputService.GetOrAddOutput(plan.Id); await _mediator.Publish(new RunUpdated(run.Id)); return(plan); }
private async Task <bool> DoWork(Domain.Models.Run run) { var projectId = run.Workspace.Directory.ProjectId; var dynamicHost = run.Workspace.DynamicHost; Host host = null; _plan = await CreatePlan(run); var workspace = run.Workspace; var files = await _db.GetWorkspaceFiles(workspace, workspace.Directory); var workingDir = workspace.GetPath(_options.RootWorkingDirectory); if (dynamicHost) { // check if host already selected for this workspace if (workspace.HostId.HasValue) { host = workspace.Host; } else { // select a host. multiply by 1.0 to cast as double host = await _db.Hosts .Where(h => h.ProjectId == projectId && h.Enabled && !h.Development) .OrderBy(h => (h.Machines.Count * 1.0 / h.MaximumMachines * 1.0) * 100.0).FirstOrDefaultAsync(); } if (host == null) { _output.AddLine("No Host could be found to use for this Plan"); return(true); } else { _output.AddLine($"Attempting to use Host {host.Name} for this Plan"); } files.Add(host.GetHostFile()); } await workspace.PrepareFileSystem(workingDir, files); _timer = new System.Timers.Timer(_options.OutputSaveInterval); _timer.Elapsed += OnTimedEvent; _timer.Start(); bool isError = false; // Init var initResult = _terraformService.InitializeWorkspace(workspace, OutputHandler); isError = initResult.IsError; if (!isError) { // Plan var planResult = _terraformService.Plan(workspace, run.IsDestroy, run.Targets, OutputHandler); isError = planResult.IsError; } lock (_plan) { _timerComplete = true; _timer.Stop(); } if (dynamicHost) { var result = _terraformService.Show(workspace); isError = result.IsError; if (!isError) { var planOutput = JsonSerializer.Deserialize <PlanOutput>(result.Output, DefaultJsonSettings.Settings); var addedMachines = planOutput.GetAddedMachines(); var hostLock = _lockService.GetHostLock(host.Id); lock (hostLock) { var existingMachines = _db.HostMachines.Where(x => x.HostId == host.Id).ToList(); var addedCount = addedMachines.Count(); if (addedCount + existingMachines.Count < host.MaximumMachines) { List <HostMachine> newMachines = new List <HostMachine>(); foreach (var addedMachine in addedMachines) { var name = addedMachine.Address; if (existingMachines.Any(m => m.WorkspaceId == workspace.Id && m.Name == name)) { continue; } newMachines.Add(new HostMachine { HostId = host.Id, WorkspaceId = workspace.Id, Name = name }); } _db.HostMachines.AddRange(newMachines); workspace.HostId = host.Id; _db.SaveChanges(); _output.AddLine($"Allocated {addedCount} new machines to Host {host.Name}"); } else { _output.AddLine($"{addedCount} new machines exceeds the maximum assigned to Host {host.Name}"); isError = true; } } } } return(isError); }