예제 #1
0
            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));
            }
예제 #2
0
            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");
                }
            }
예제 #3
0
            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");
                }
            }
예제 #4
0
            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.");
                }
            }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }