forked from hootsuite/atlantis
/
project_pre_execute.go
113 lines (103 loc) · 4.49 KB
/
project_pre_execute.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
package events
import (
"fmt"
"path/filepath"
"strings"
"github.com/hashicorp/go-version"
"github.com/hootsuite/atlantis/server/events/locking"
"github.com/hootsuite/atlantis/server/events/models"
"github.com/hootsuite/atlantis/server/events/run"
"github.com/hootsuite/atlantis/server/events/terraform"
"github.com/pkg/errors"
)
//go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_project_pre_executor.go ProjectPreExecutor
// ProjectPreExecutor executes before the plan and apply executors. It handles
// the setup tasks that are common to both plan and apply.
type ProjectPreExecutor interface {
// Execute executes the pre plan/apply tasks.
Execute(ctx *CommandContext, repoDir string, project models.Project) PreExecuteResult
}
// DefaultProjectPreExecutor implements ProjectPreExecutor.
type DefaultProjectPreExecutor struct {
Locker locking.Locker
ConfigReader ProjectConfigReader
Terraform terraform.Client
Run run.Runner
}
// PreExecuteResult is the result of running the pre execute.
type PreExecuteResult struct {
ProjectResult ProjectResult
ProjectConfig ProjectConfig
TerraformVersion *version.Version
LockResponse locking.TryLockResponse
}
// Execute executes the pre plan/apply tasks.
func (p *DefaultProjectPreExecutor) Execute(ctx *CommandContext, repoDir string, project models.Project) PreExecuteResult {
workspace := ctx.Command.Workspace
lockAttempt, err := p.Locker.TryLock(project, workspace, ctx.Pull, ctx.User)
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: errors.Wrap(err, "acquiring lock")}}
}
if !lockAttempt.LockAcquired && lockAttempt.CurrLock.Pull.Num != ctx.Pull.Num {
return PreExecuteResult{ProjectResult: ProjectResult{Failure: fmt.Sprintf(
"This project is currently locked by #%d. The locking plan must be applied or discarded before future plans can execute.",
lockAttempt.CurrLock.Pull.Num)}}
}
ctx.Log.Info("acquired lock with id %q", lockAttempt.LockKey)
// Check if config file is found, if not we continue the run.
var config ProjectConfig
absolutePath := filepath.Join(repoDir, project.Path)
if p.ConfigReader.Exists(absolutePath) {
config, err = p.ConfigReader.Read(absolutePath)
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: err}}
}
ctx.Log.Info("parsed atlantis config file in %q", absolutePath)
}
// Check if terraform version is >= 0.9.0.
terraformVersion := p.Terraform.Version()
if config.TerraformVersion != nil {
terraformVersion = config.TerraformVersion
}
constraints, _ := version.NewConstraint(">= 0.9.0")
if constraints.Check(terraformVersion) {
ctx.Log.Info("determined that we are running terraform with version >= 0.9.0. Running version %s", terraformVersion)
if len(config.PreInit) > 0 {
_, err := p.Run.Execute(ctx.Log, config.PreInit, absolutePath, workspace, terraformVersion, "pre_init")
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: errors.Wrapf(err, "running %s commands", "pre_init")}}
}
}
_, err := p.Terraform.Init(ctx.Log, absolutePath, workspace, config.GetExtraArguments("init"), terraformVersion)
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: err}}
}
} else {
ctx.Log.Info("determined that we are running terraform with version < 0.9.0. Running version %s", terraformVersion)
if len(config.PreGet) > 0 {
_, err := p.Run.Execute(ctx.Log, config.PreGet, absolutePath, workspace, terraformVersion, "pre_get")
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: errors.Wrapf(err, "running %s commands", "pre_get")}}
}
}
terraformGetCmd := append([]string{"get", "-no-color"}, config.GetExtraArguments("get")...)
_, err := p.Terraform.RunCommandWithVersion(ctx.Log, absolutePath, terraformGetCmd, terraformVersion, workspace)
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: err}}
}
}
stage := fmt.Sprintf("pre_%s", strings.ToLower(ctx.Command.Name.String()))
var commands []string
if ctx.Command.Name == Plan {
commands = config.PrePlan
} else {
commands = config.PreApply
}
if len(commands) > 0 {
_, err := p.Run.Execute(ctx.Log, commands, absolutePath, workspace, terraformVersion, stage)
if err != nil {
return PreExecuteResult{ProjectResult: ProjectResult{Error: errors.Wrapf(err, "running %s commands", stage)}}
}
}
return PreExecuteResult{ProjectConfig: config, TerraformVersion: terraformVersion, LockResponse: lockAttempt}
}