mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-30 00:48:01 +00:00
Fix remote execution on Terraform Cloud after v1.1.0 (#2793)
* Fix remote execution on Terraform Cloud after v1.1.0 * Do not check terraform version for -no-color * Move string comparison for newer version earlier * Update remote apply test
This commit is contained in:
@@ -41,7 +41,7 @@ func (a *ApplyStepRunner) Run(ctx command.ProjectContext, extraArgs []string, pa
|
||||
|
||||
// TODO: Leverage PlanTypeStepRunnerDelegate here
|
||||
if IsRemotePlan(contents) {
|
||||
args := append(append([]string{"apply", "-input=false"}, extraArgs...), ctx.EscapedCommentArgs...)
|
||||
args := append(append([]string{"apply", "-input=false", "-no-color"}, extraArgs...), ctx.EscapedCommentArgs...)
|
||||
out, err = a.runRemoteApply(ctx, args, path, planPath, ctx.TerraformVersion, envs)
|
||||
if err == nil {
|
||||
out = a.cleanRemoteApplyOutput(out)
|
||||
|
||||
@@ -267,7 +267,7 @@ null_resource.dir2[1]: Destruction complete after 0s
|
||||
Apply complete! Resources: 0 added, 0 changed, 1 destroyed.
|
||||
`, output)
|
||||
|
||||
Equals(t, []string{"apply", "-input=false", "extra", "args", "comment", "args"}, tfExec.CalledArgs)
|
||||
Equals(t, []string{"apply", "-input=false", "-no-color", "extra", "args", "comment", "args"}, tfExec.CalledArgs)
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
|
||||
|
||||
@@ -63,14 +63,14 @@ func (p *PlanStepRunner) isRemoteOpsErr(output string, err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(output, remoteOpsErr01114) || strings.Contains(output, remoteOpsErr012) || strings.Contains(output, remoteOpsErr100)
|
||||
return strings.Contains(output, remoteOpsErr110) || strings.Contains(output, remoteOpsErr01114) || strings.Contains(output, remoteOpsErr012) || strings.Contains(output, remoteOpsErr100)
|
||||
}
|
||||
|
||||
// remotePlan runs a terraform plan command compatible with TFE remote
|
||||
// operations.
|
||||
func (p *PlanStepRunner) remotePlan(ctx command.ProjectContext, extraArgs []string, path string, tfVersion *version.Version, planFile string, envs map[string]string) (string, error) {
|
||||
argList := [][]string{
|
||||
{"plan", "-input=false", "-refresh"},
|
||||
{"plan", "-input=false", "-refresh", "-no-color"},
|
||||
extraArgs,
|
||||
ctx.EscapedCommentArgs,
|
||||
}
|
||||
@@ -340,6 +340,16 @@ The "remote" backend does not support saving the generated execution plan
|
||||
locally at this time.
|
||||
`
|
||||
|
||||
// remoteOpsErr110 is the error terraform plan will return if this project is
|
||||
// using Terraform Cloud remote operations in TF 1.1.0 and above
|
||||
var remoteOpsErr110 = `╷
|
||||
│ Error: Saving a generated plan is currently not supported
|
||||
│
|
||||
│ Terraform Cloud does not support saving the generated execution plan
|
||||
│ locally at this time.
|
||||
╵
|
||||
`
|
||||
|
||||
// remoteOpsHeader is the header we add to the planfile if this plan was
|
||||
// generated using TFE remote operations.
|
||||
var remoteOpsHeader = "Atlantis: this plan was created by remote ops\n"
|
||||
|
||||
@@ -685,22 +685,45 @@ func TestRun_NoOptionalVarsIn012(t *testing.T) {
|
||||
|
||||
// Test plans if using remote ops.
|
||||
func TestRun_RemoteOps(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"0.11.15 error": `Error: Saving a generated plan is currently not supported!
|
||||
cases := []struct {
|
||||
name string
|
||||
tfVersion string
|
||||
remoteOpsErr string
|
||||
}{
|
||||
{
|
||||
name: "0.11.15 error",
|
||||
tfVersion: "0.11.15",
|
||||
remoteOpsErr: `Error: Saving a generated plan is currently not supported!
|
||||
|
||||
The "remote" backend does not support saving the generated execution
|
||||
plan locally at this time.
|
||||
|
||||
`,
|
||||
"0.12.* error": `Error: Saving a generated plan is currently not supported
|
||||
},
|
||||
{
|
||||
name: "0.12.* error",
|
||||
tfVersion: "0.12.0",
|
||||
remoteOpsErr: `Error: Saving a generated plan is currently not supported
|
||||
|
||||
The "remote" backend does not support saving the generated execution plan
|
||||
locally at this time.
|
||||
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "1.1.0 error",
|
||||
tfVersion: "1.1.0",
|
||||
remoteOpsErr: `╷
|
||||
│ Error: Saving a generated plan is currently not supported
|
||||
│
|
||||
│ Terraform Cloud does not support saving the generated execution plan
|
||||
│ locally at this time.
|
||||
╵
|
||||
`,
|
||||
},
|
||||
}
|
||||
for name, remoteOpsErr := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
// Now that mocking is set up, we're ready to run the plan.
|
||||
@@ -722,7 +745,7 @@ locally at this time.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
|
||||
tfVersion, _ := version.NewVersion("0.11.12")
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
updater := mocks2.NewMockCommitStatusUpdater()
|
||||
asyncTf := &remotePlanMock{}
|
||||
s := runtime.PlanStepRunner{
|
||||
@@ -763,16 +786,28 @@ locally at this time.
|
||||
"comment",
|
||||
"args",
|
||||
}
|
||||
if tfVersion.GreaterThanOrEqual(version.Must(version.NewVersion("0.12.0"))) {
|
||||
expPlanArgs = []string{"plan",
|
||||
"-input=false",
|
||||
"-refresh",
|
||||
"-out",
|
||||
fmt.Sprintf("%q", filepath.Join(absProjectPath, "default.tfplan")),
|
||||
"extra",
|
||||
"args",
|
||||
"comment",
|
||||
"args",
|
||||
}
|
||||
}
|
||||
|
||||
planErr := errors.New("exit status 1: err")
|
||||
planOutput := "\n" + remoteOpsErr
|
||||
planOutput := "\n" + c.remoteOpsErr
|
||||
asyncTf.LinesToSend = remotePlanOutput
|
||||
When(terraform.RunCommandWithVersion(ctx, absProjectPath, expPlanArgs, map[string]string(nil), tfVersion, "default")).
|
||||
ThenReturn(planOutput, planErr)
|
||||
|
||||
output, err := s.Run(ctx, []string{"extra", "args"}, absProjectPath, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, `
|
||||
Assert(t, strings.Contains(output, `
|
||||
An execution plan has been generated and is shown below.
|
||||
Resource actions are indicated with the following symbols:
|
||||
- destroy
|
||||
@@ -782,26 +817,15 @@ Terraform will perform the following actions:
|
||||
- null_resource.hi[1]
|
||||
|
||||
|
||||
Plan: 0 to add, 0 to change, 1 to destroy.`, output)
|
||||
Plan: 0 to add, 0 to change, 1 to destroy.`), "expect plan success")
|
||||
|
||||
expRemotePlanArgs := []string{"plan", "-input=false", "-refresh", "extra", "args", "comment", "args"}
|
||||
expRemotePlanArgs := []string{"plan", "-input=false", "-refresh", "-no-color", "extra", "args", "comment", "args"}
|
||||
Equals(t, expRemotePlanArgs, asyncTf.CalledArgs)
|
||||
|
||||
// Verify that the fake plan file we write has the correct contents.
|
||||
bytes, err := os.ReadFile(filepath.Join(absProjectPath, "default.tfplan"))
|
||||
Ok(t, err)
|
||||
Equals(t, `Atlantis: this plan was created by remote ops
|
||||
|
||||
An execution plan has been generated and is shown below.
|
||||
Resource actions are indicated with the following symbols:
|
||||
- destroy
|
||||
|
||||
Terraform will perform the following actions:
|
||||
|
||||
- null_resource.hi[1]
|
||||
|
||||
|
||||
Plan: 0 to add, 0 to change, 1 to destroy.`, string(bytes))
|
||||
Assert(t, strings.HasPrefix(string(bytes), "Atlantis: this plan was created by remote ops"), "expect remote plan")
|
||||
|
||||
// Ensure that the status was updated with the runURL.
|
||||
runURL := "https://app.terraform.io/app/lkysow-enterprises/atlantis-tfe-test/runs/run-is4oVvJfrkud1KvE"
|
||||
|
||||
Reference in New Issue
Block a user